diff options
Diffstat (limited to 'layout/base/nsDisplayList.h')
-rw-r--r-- | layout/base/nsDisplayList.h | 4550 |
1 files changed, 4550 insertions, 0 deletions
diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h new file mode 100644 index 000000000..df584b489 --- /dev/null +++ b/layout/base/nsDisplayList.h @@ -0,0 +1,4550 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=2 sw=2 et tw=78: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* + * structures that represent things to be painted (ordered in z-order), + * used during painting and hit testing + */ + +#ifndef NSDISPLAYLIST_H_ +#define NSDISPLAYLIST_H_ + +#include "mozilla/Attributes.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/EnumSet.h" +#include "mozilla/Maybe.h" +#include "nsCOMPtr.h" +#include "nsContainerFrame.h" +#include "nsPoint.h" +#include "nsRect.h" +#include "plarena.h" +#include "nsRegion.h" +#include "nsDisplayListInvalidation.h" +#include "nsRenderingContext.h" +#include "DisplayListClipState.h" +#include "LayerState.h" +#include "FrameMetrics.h" +#include "mozilla/EnumeratedArray.h" +#include "mozilla/Maybe.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/TimeStamp.h" +#include "mozilla/gfx/UserData.h" + +#include <stdint.h> +#include "nsTHashtable.h" + +#include <stdlib.h> +#include <algorithm> + +class nsIContent; +class nsRenderingContext; +class nsDisplayList; +class nsDisplayTableItem; +class nsISelection; +class nsIScrollableFrame; +class nsDisplayLayerEventRegions; +class nsDisplayScrollInfoLayer; +class nsCaret; + +namespace mozilla { +class FrameLayerBuilder; +class DisplayItemScrollClip; +namespace layers { +class Layer; +class ImageLayer; +class ImageContainer; +} // namespace layers +} // namespace mozilla + +// A set of blend modes, that never includes OP_OVER (since it's +// considered the default, rather than a specific blend mode). +typedef mozilla::EnumSet<mozilla::gfx::CompositionOp> BlendModeSet; + +/* + * 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. + */ + +// All types are defined in nsDisplayItemTypes.h +#define NS_DISPLAY_DECL_NAME(n, e) \ + virtual const char* Name() override { return n; } \ + virtual Type GetType() override { return e; } + + +/** + * Represents a frame that is considered to have (or will have) "animated geometry" + * for itself and descendant frames. + * + * For example the scrolled frames of scrollframes which are actively being scrolled + * fall into this category. Frames with certain CSS properties that are being animated + * (e.g. 'left'/'top' etc) are also placed in this category. Frames with different + * active geometry roots are in different PaintedLayers, so that we can animate the + * geometry root by changing its transform (either on the main thread or in the + * compositor). + * + * nsDisplayListBuilder constructs a tree of these (for fast traversals) and assigns + * one for each display item. + * + * The animated geometry root for a display item is required to be a descendant (or + * equal to) the item's ReferenceFrame(), which means that we will fall back to + * returning aItem->ReferenceFrame() when we can't find another animated geometry root. + * + * The animated geometry root isn't strongly defined for a frame as transforms and + * background-attachment:fixed can cause it to vary between display items for a given + * frame. + */ +struct AnimatedGeometryRoot +{ + AnimatedGeometryRoot(nsIFrame* aFrame, AnimatedGeometryRoot* aParent) + : mFrame(aFrame) + , mParentAGR(aParent) + {} + + operator nsIFrame*() { return mFrame; } + + nsIFrame* operator ->() const { return mFrame; } + + void* operator new(size_t aSize, + nsDisplayListBuilder* aBuilder); + + nsIFrame* mFrame; + AnimatedGeometryRoot* mParentAGR; +}; + +enum class nsDisplayListBuilderMode : uint8_t { + PAINTING, + EVENT_DELIVERY, + PLUGIN_GEOMETRY, + FRAME_VISIBILITY, + TRANSFORM_COMPUTATION, + GENERATE_GLYPH, + PAINTING_SELECTION_BACKGROUND +}; + +/** + * 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 a PLArena. It also establishes the reference + * coordinate system for all display list items. Some of the parameters are + * available from the prescontext/presshell, but we copy them into the builder + * for faster/more convenient access. + */ +class nsDisplayListBuilder { + typedef mozilla::LayoutDeviceIntRect LayoutDeviceIntRect; + typedef mozilla::LayoutDeviceIntRegion LayoutDeviceIntRegion; + + /** + * 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. + * + * nsFrame::BuildDisplayListForStackingContext() uses + * AutoPreserves3DContext to install an instance on the builder. + * + * \see AutoAccumulateTransform, AutoAccumulateRect, + * AutoPreserves3DContext, Accumulate, GetCurrentTransform, + * StartRoot. + */ + class Preserves3DContext { + public: + typedef mozilla::gfx::Matrix4x4 Matrix4x4; + + Preserves3DContext() + : mAccumulatedRectLevels(0) + {} + Preserves3DContext(const Preserves3DContext &aOther) + : mAccumulatedTransform() + , mAccumulatedRect() + , mAccumulatedRectLevels(0) + , mDirtyRect(aOther.mDirtyRect) {} + + // Accmulate transforms of ancestors on the preserves-3d chain. + Matrix4x4 mAccumulatedTransform; + // Accmulate visible rect of descendants in the preserves-3d context. + nsRect mAccumulatedRect; + // How far this frame is from the root of the current 3d context. + int mAccumulatedRectLevels; + nsRect mDirtyRect; + }; + +public: + typedef mozilla::FrameLayerBuilder FrameLayerBuilder; + typedef mozilla::DisplayItemClip DisplayItemClip; + typedef mozilla::DisplayListClipState DisplayListClipState; + typedef mozilla::DisplayItemScrollClip DisplayItemScrollClip; + typedef nsIWidget::ThemeGeometry ThemeGeometry; + typedef mozilla::layers::Layer Layer; + typedef mozilla::layers::FrameMetrics FrameMetrics; + typedef mozilla::layers::FrameMetrics::ViewID ViewID; + typedef mozilla::gfx::Matrix4x4 Matrix4x4; + + /** + * @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); + ~nsDisplayListBuilder(); + + void SetWillComputePluginGeometry(bool aWillComputePluginGeometry) + { + mWillComputePluginGeometry = aWillComputePluginGeometry; + } + void SetForPluginGeometry() + { + NS_ASSERTION(mMode == nsDisplayListBuilderMode::PAINTING, "Can only switch from PAINTING to PLUGIN_GEOMETRY"); + NS_ASSERTION(mWillComputePluginGeometry, "Should have signalled this in advance"); + mMode = nsDisplayListBuilderMode::PLUGIN_GEOMETRY; + } + + mozilla::layers::LayerManager* GetWidgetLayerManager(nsView** aView = nullptr); + + /** + * @return true if the display is being built in order to determine which + * frame is under the mouse position. + */ + bool IsForEventDelivery() + { + return mMode == nsDisplayListBuilderMode::EVENT_DELIVERY; + } + + /** + * Be careful with this. The display list will be built in PAINTING mode + * first and then switched to PLUGIN_GEOMETRY before a second call to + * ComputeVisibility. + * @return true if the display list is being built to compute geometry + * for plugins. + */ + bool IsForPluginGeometry() + { + return mMode == nsDisplayListBuilderMode::PLUGIN_GEOMETRY; + } + + /** + * @return true if the display list is being built for painting. + */ + bool IsForPainting() + { + return mMode == nsDisplayListBuilderMode::PAINTING; + } + + /** + * @return true if the display list is being built for determining frame + * visibility. + */ + bool IsForFrameVisibility() + { + return mMode == nsDisplayListBuilderMode::FRAME_VISIBILITY; + } + + /** + * @return true if the display list is being built for creating the glyph + * mask from text items. + */ + bool IsForGenerateGlyphMask() + { + return mMode == nsDisplayListBuilderMode::GENERATE_GLYPH; + } + + /** + * @return true if the display list is being built for painting selection + * background. + */ + bool IsForPaintingSelectionBG() + { + return mMode == nsDisplayListBuilderMode::PAINTING_SELECTION_BACKGROUND; + } + + bool WillComputePluginGeometry() { return mWillComputePluginGeometry; } + /** + * @return true if "painting is suppressed" during page load and we + * should paint only the background of the document. + */ + bool IsBackgroundOnly() { + NS_ASSERTION(mPresShellStates.Length() > 0, + "don't call this if we're not in a presshell"); + return CurrentPresShellState()->mIsBackgroundOnly; + } + /** + * @return true if the currently active BuildDisplayList call is being + * applied to a frame at the root of a pseudo stacking context. A pseudo + * stacking context is either a real stacking context or basically what + * CSS2.1 appendix E refers to with "treat the element as if it created + * a new stacking context + */ + bool IsAtRootOfPseudoStackingContext() { return mIsAtRootOfPseudoStackingContext; } + + /** + * @return the selection that painting should be restricted to (or nullptr + * in the normal unrestricted case) + */ + nsISelection* GetBoundingSelection() { return mBoundingSelection; } + + /** + * @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); + + /** + * @return the root of the display list's frame (sub)tree, whose origin + * establishes the coordinate system for the display list + */ + nsIFrame* RootReferenceFrame() + { + 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) { + 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; } + /** + * Get the ViewID of the nearest scrolling ancestor frame. + */ + ViewID GetCurrentScrollParentId() const { return mCurrentScrollParentId; } + /** + * Get and set the flag that indicates if scroll parents should have layers + * forcibly created. This flag is set when a deeply nested scrollframe has + * a displayport, and for scroll handoff to work properly the ancestor + * scrollframes should also get their own scrollable layers. + */ + void ForceLayerForScrollParent() { mForceLayerForScrollParent = true; } + /** + * Get the ViewID and the scrollbar flags corresponding to the scrollbar for + * which we are building display items at the moment. + */ + void GetScrollbarInfo(ViewID* aOutScrollbarTarget, uint32_t* aOutScrollbarFlags) + { + *aOutScrollbarTarget = mCurrentScrollbarTarget; + *aOutScrollbarFlags = mCurrentScrollbarFlags; + } + /** + * Returns true if building a scrollbar, and the scrollbar will not be + * layerized. + */ + bool IsBuildingNonLayerizedScrollbar() const { + return mIsBuildingScrollbar && !mCurrentScrollbarWillHaveLayer; + } + /** + * Calling this setter makes us include all out-of-flow descendant + * frames in the display list, wherever they may be positioned (even + * outside the dirty rects). + */ + void SetIncludeAllOutOfFlows() { mIncludeAllOutOfFlows = true; } + bool GetIncludeAllOutOfFlows() const { return mIncludeAllOutOfFlows; } + /** + * Calling this setter makes us exclude all leaf frames that aren't + * selected. + */ + void SetSelectedFramesOnly() { mSelectedFramesOnly = true; } + bool GetSelectedFramesOnly() { return mSelectedFramesOnly; } + /** + * Calling this setter makes us compute accurate visible regions at the cost + * of performance if regions get very complex. + */ + void SetAccurateVisibleRegions() { mAccurateVisibleRegions = true; } + bool GetAccurateVisibleRegions() { return mAccurateVisibleRegions; } + /** + * @return Returns true if we should include the caret in any display lists + * that we make. + */ + bool IsBuildingCaret() { return mBuildCaret; } + /** + * 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 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& GetDirtyRect() { return mDirtyRect; } + const nsIFrame* GetCurrentFrame() { return mCurrentFrame; } + const nsIFrame* GetCurrentReferenceFrame() { return mCurrentReferenceFrame; } + const nsPoint& GetCurrentFrameOffsetToReferenceFrame() { return mCurrentOffsetToReferenceFrame; } + AnimatedGeometryRoot* GetCurrentAnimatedGeometryRoot() { + return mCurrentAGR; + } + AnimatedGeometryRoot* GetRootAnimatedGeometryRoot() { + return &mRootAGR; + } + + void RecomputeCurrentAnimatedGeometryRoot(); + + /** + * 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; } + + nsDisplayLayerEventRegions* GetLayerEventRegions() { return mLayerEventRegions; } + void SetLayerEventRegions(nsDisplayLayerEventRegions* aItem) + { + mLayerEventRegions = aItem; + } + bool IsBuildingLayerEventRegions(); + static bool LayerEventRegionsEnabled(); + bool IsInsidePointerEventsNoneDoc() + { + return CurrentPresShellState()->mInsidePointerEventsNoneDoc; + } + + bool GetAncestorHasApzAwareEventHandler() { return mAncestorHasApzAwareEventHandler; } + void SetAncestorHasApzAwareEventHandler(bool aValue) + { + mAncestorHasApzAwareEventHandler = aValue; + } + + bool HaveScrollableDisplayPort() const { return mHaveScrollableDisplayPort; } + void SetHaveScrollableDisplayPort() { mHaveScrollableDisplayPort = true; } + + bool SetIsCompositingCheap(bool aCompositingCheap) { + bool temp = mIsCompositingCheap; + mIsCompositingCheap = aCompositingCheap; + return temp; + } + bool IsCompositingCheap() const { return mIsCompositingCheap; } + /** + * Display the caret if needed. + */ + void DisplayCaret(nsIFrame* aFrame, const nsRect& aDirtyRect, + nsDisplayList* aList) { + nsIFrame* frame = GetCaretFrame(); + if (aFrame == frame) { + frame->DisplayCaret(this, aDirtyRect, aList); + } + } + /** + * 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 CurrentPresShellState()->mCaretRect; + } + /** + * Get the caret associated with the current presshell. + */ + nsCaret* GetCaret(); + /** + * 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(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(); + /** + * Notify the display list builder that we're leaving a presshell. + */ + void LeavePresShell(nsIFrame* aReferenceFrame, nsDisplayList* aPaintedContents); + + /** + * Returns true if we're currently building a display list that's + * directly or indirectly under an nsDisplayTransform. + */ + bool IsInTransform() const { return mInTransform; } + /** + * Indicate whether or not we're directly or indirectly under and + * nsDisplayTransform or SVG foreignObject. + */ + void SetInTransform(bool aInTransform) { mInTransform = aInTransform; } + + /** + * Return true if we're currently building a display list for a + * nested presshell. + */ + bool IsInSubdocument() { return mPresShellStates.Length() > 1; } + + /** + * 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() { + return mIsInChromePresContext || mIsBuildingForPopup; + } + + /** + * @return true if images have been set to decode synchronously. + */ + bool ShouldSyncDecodeImages() { 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; + } + + /** + * Helper method to generate background painting flags based on the + * information available in the display list builder. Currently only + * accounts for mSyncDecodeImages. + */ + uint32_t GetBackgroundPaintFlags(); + + /** + * Subtracts aRegion from *aVisibleRegion. We avoid letting + * aVisibleRegion become overcomplex by simplifying it if necessary --- + * unless mAccurateVisibleRegions is set, in which case we let it + * get arbitrarily complex. + */ + 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, + const nsRect& aDirtyRect); + /** + * 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); + + const nsTArray<ThemeGeometry>& GetThemeGeometries() { return mThemeGeometries; } + + /** + * 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) const { + return + (aFrame->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO) || + GetIncludeAllOutOfFlows(); + } + + /** + * 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 NS_THEME_TOOLBAR and + * NS_THEME_WINDOW_TITLEBAR) 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 aRect the device-pixel rect relative to the widget's displayRoot + * for the themed widget + */ + void RegisterThemeGeometry(uint8_t aWidgetType, + const mozilla::LayoutDeviceIntRect& aRect) { + if (mIsPaintingToWindow) { + mThemeGeometries.AppendElement(ThemeGeometry(aWidgetType, aRect)); + } + } + + /** + * 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; + + /** + * Allocate memory in our arena. It will only be freed when this display list + * builder is destroyed. This memory holds nsDisplayItems. nsDisplayItem + * destructors are called as soon as the item is no longer used. + */ + void* Allocate(size_t aSize); + + /** + * Allocate a new DisplayItemClip in the arena. Will be cleaned up + * automatically when the arena goes away. + */ + const DisplayItemClip* AllocateDisplayItemClip(const DisplayItemClip& aOriginal); + + /** + * Allocate a new DisplayItemScrollClip in the arena. Will be cleaned up + * automatically when the arena goes away. + */ + DisplayItemScrollClip* AllocateDisplayItemScrollClip(const DisplayItemScrollClip* aParent, + nsIScrollableFrame* aScrollableFrame, + const DisplayItemClip* aClip, + bool aIsAsyncScrollable); + + /** + * Transfer off main thread animations to the layer. May be called + * with aBuilder and aItem both null, but only if the caller has + * already checked that off main thread animations should be sent to + * the layer. When they are both null, the animations are added to + * the layer as pending animations. + */ + static void AddAnimationsAndTransitionsToLayer(Layer* aLayer, + nsDisplayListBuilder* aBuilder, + nsDisplayItem* aItem, + nsIFrame* aFrame, + nsCSSPropertyID aProperty); + + /** + * A helper class to temporarily set the value of + * mIsAtRootOfPseudoStackingContext, and temporarily + * set mCurrentFrame and related state. Also temporarily sets mDirtyRect. + * aDirtyRect is relative to aForChild. + */ + class AutoBuildingDisplayList; + friend class AutoBuildingDisplayList; + class AutoBuildingDisplayList { + public: + AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder, + nsIFrame* aForChild, + const nsRect& aDirtyRect, bool aIsRoot) + : mBuilder(aBuilder), + mPrevFrame(aBuilder->mCurrentFrame), + mPrevReferenceFrame(aBuilder->mCurrentReferenceFrame), + mPrevLayerEventRegions(aBuilder->mLayerEventRegions), + mPrevOffset(aBuilder->mCurrentOffsetToReferenceFrame), + mPrevDirtyRect(aBuilder->mDirtyRect), + mPrevAGR(aBuilder->mCurrentAGR), + mPrevIsAtRootOfPseudoStackingContext(aBuilder->mIsAtRootOfPseudoStackingContext), + mPrevAncestorHasApzAwareEventHandler(aBuilder->mAncestorHasApzAwareEventHandler), + mPrevBuildingInvisibleItems(aBuilder->mBuildingInvisibleItems) + { + if (aForChild->IsTransformed()) { + aBuilder->mCurrentOffsetToReferenceFrame = nsPoint(); + aBuilder->mCurrentReferenceFrame = aForChild; + } else if (aBuilder->mCurrentFrame == aForChild->GetParent()) { + aBuilder->mCurrentOffsetToReferenceFrame += aForChild->GetPosition(); + } else { + aBuilder->mCurrentReferenceFrame = + aBuilder->FindReferenceFrameFor(aForChild, + &aBuilder->mCurrentOffsetToReferenceFrame); + } + if (aBuilder->mCurrentFrame == aForChild->GetParent()) { + if (aBuilder->IsAnimatedGeometryRoot(aForChild)) { + aBuilder->mCurrentAGR = aBuilder->WrapAGRForFrame(aForChild, aBuilder->mCurrentAGR); + } + } else if (aForChild != aBuilder->mCurrentFrame) { + aBuilder->mCurrentAGR = aBuilder->FindAnimatedGeometryRootFor(aForChild); + } + MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(aBuilder->RootReferenceFrame(), *aBuilder->mCurrentAGR)); + aBuilder->mCurrentFrame = aForChild; + aBuilder->mDirtyRect = aDirtyRect; + aBuilder->mIsAtRootOfPseudoStackingContext = aIsRoot; + } + void SetDirtyRect(const nsRect& aRect) { + mBuilder->mDirtyRect = aRect; + } + void SetReferenceFrameAndCurrentOffset(const nsIFrame* aFrame, const nsPoint& aOffset) { + mBuilder->mCurrentReferenceFrame = aFrame; + mBuilder->mCurrentOffsetToReferenceFrame = aOffset; + } + // Return the previous frame's animated geometry root, whether or not the + // current frame is an immediate descendant. + const nsIFrame* GetPrevAnimatedGeometryRoot() const { + return mPrevAnimatedGeometryRoot; + } + bool IsAnimatedGeometryRoot() const { + return *mBuilder->mCurrentAGR == mBuilder->mCurrentFrame; + + } + void RestoreBuildingInvisibleItemsValue() { + mBuilder->mBuildingInvisibleItems = mPrevBuildingInvisibleItems; + } + ~AutoBuildingDisplayList() { + mBuilder->mCurrentFrame = mPrevFrame; + mBuilder->mCurrentReferenceFrame = mPrevReferenceFrame; + mBuilder->mLayerEventRegions = mPrevLayerEventRegions; + mBuilder->mCurrentOffsetToReferenceFrame = mPrevOffset; + mBuilder->mDirtyRect = mPrevDirtyRect; + mBuilder->mCurrentAGR = mPrevAGR; + mBuilder->mIsAtRootOfPseudoStackingContext = mPrevIsAtRootOfPseudoStackingContext; + mBuilder->mAncestorHasApzAwareEventHandler = mPrevAncestorHasApzAwareEventHandler; + mBuilder->mBuildingInvisibleItems = mPrevBuildingInvisibleItems; + } + private: + nsDisplayListBuilder* mBuilder; + const nsIFrame* mPrevFrame; + const nsIFrame* mPrevReferenceFrame; + nsIFrame* mPrevAnimatedGeometryRoot; + nsDisplayLayerEventRegions* mPrevLayerEventRegions; + nsPoint mPrevOffset; + nsRect mPrevDirtyRect; + AnimatedGeometryRoot* mPrevAGR; + bool mPrevIsAtRootOfPseudoStackingContext; + bool mPrevAncestorHasApzAwareEventHandler; + bool mPrevBuildingInvisibleItems; + }; + + /** + * A helper class to temporarily set the value of mInTransform. + */ + class AutoInTransformSetter; + friend class AutoInTransformSetter; + 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 AutoSaveRestorePerspectiveIndex; + friend class AutoSaveRestorePerspectiveIndex; + class AutoSaveRestorePerspectiveIndex { + public: + AutoSaveRestorePerspectiveIndex(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) + : mBuilder(nullptr) + { + if (aFrame->ChildrenHavePerspective()) { + mBuilder = aBuilder; + mCachedItemIndex = aBuilder->mPerspectiveItemIndex; + aBuilder->mPerspectiveItemIndex = 0; + } + } + + ~AutoSaveRestorePerspectiveIndex() + { + if (mBuilder) { + mBuilder->mPerspectiveItemIndex = mCachedItemIndex; + } + } + + private: + nsDisplayListBuilder* mBuilder; + uint32_t mCachedItemIndex; + }; + + /** + * A helper class to temporarily set the value of mCurrentScrollParentId. + */ + class AutoCurrentScrollParentIdSetter; + friend class AutoCurrentScrollParentIdSetter; + class AutoCurrentScrollParentIdSetter { + public: + AutoCurrentScrollParentIdSetter(nsDisplayListBuilder* aBuilder, ViewID aScrollId) + : mBuilder(aBuilder) + , mOldValue(aBuilder->mCurrentScrollParentId) + , mOldForceLayer(aBuilder->mForceLayerForScrollParent) { + // If this AutoCurrentScrollParentIdSetter has the same scrollId as the + // previous one on the stack, then that means the scrollframe that + // created this isn't actually scrollable and cannot participate in + // scroll handoff. We set mCanBeScrollParent to false to indicate this. + mCanBeScrollParent = (mOldValue != aScrollId); + aBuilder->mCurrentScrollParentId = aScrollId; + aBuilder->mForceLayerForScrollParent = false; + } + bool ShouldForceLayerForScrollParent() const { + // Only scrollframes participating in scroll handoff can be forced to + // layerize + return mCanBeScrollParent && mBuilder->mForceLayerForScrollParent; + }; + ~AutoCurrentScrollParentIdSetter() { + mBuilder->mCurrentScrollParentId = mOldValue; + if (mCanBeScrollParent) { + // If this flag is set, caller code is responsible for having dealt + // with the current value of mBuilder->mForceLayerForScrollParent, so + // we can just restore the old value. + mBuilder->mForceLayerForScrollParent = mOldForceLayer; + } else { + // Otherwise we need to keep propagating the force-layerization flag + // upwards to the next ancestor scrollframe that does participate in + // scroll handoff. + mBuilder->mForceLayerForScrollParent |= mOldForceLayer; + } + } + private: + nsDisplayListBuilder* mBuilder; + ViewID mOldValue; + bool mOldForceLayer; + bool mCanBeScrollParent; + }; + + /** + * A helper class to temporarily set the value of mCurrentScrollbarTarget + * and mCurrentScrollbarFlags. + */ + class AutoCurrentScrollbarInfoSetter; + friend class AutoCurrentScrollbarInfoSetter; + class AutoCurrentScrollbarInfoSetter { + public: + AutoCurrentScrollbarInfoSetter(nsDisplayListBuilder* aBuilder, ViewID aScrollTargetID, + uint32_t aScrollbarFlags, bool aWillHaveLayer) + : mBuilder(aBuilder) { + aBuilder->mIsBuildingScrollbar = true; + aBuilder->mCurrentScrollbarTarget = aScrollTargetID; + aBuilder->mCurrentScrollbarFlags = aScrollbarFlags; + aBuilder->mCurrentScrollbarWillHaveLayer = aWillHaveLayer; + } + ~AutoCurrentScrollbarInfoSetter() { + // No need to restore old values because scrollbars cannot be nested. + mBuilder->mIsBuildingScrollbar = false; + mBuilder->mCurrentScrollbarTarget = FrameMetrics::NULL_SCROLL_ID; + mBuilder->mCurrentScrollbarFlags = 0; + mBuilder->mCurrentScrollbarWillHaveLayer = false; + } + private: + nsDisplayListBuilder* mBuilder; + }; + + /** + * 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; + friend class AutoAccumulateTransform; + class AutoAccumulateTransform { + public: + typedef mozilla::gfx::Matrix4x4 Matrix4x4; + + explicit AutoAccumulateTransform(nsDisplayListBuilder* aBuilder) + : mBuilder(aBuilder) + , mSavedTransform(aBuilder->mPreserves3DCtx.mAccumulatedTransform) {} + + ~AutoAccumulateTransform() { + mBuilder->mPreserves3DCtx.mAccumulatedTransform = mSavedTransform; + } + + void Accumulate(const Matrix4x4& aTransform) { + mBuilder->mPreserves3DCtx.mAccumulatedTransform = + aTransform * mBuilder->mPreserves3DCtx.mAccumulatedTransform; + } + + const Matrix4x4& GetCurrentTransform() { + return mBuilder->mPreserves3DCtx.mAccumulatedTransform; + } + + void StartRoot() { + mBuilder->mPreserves3DCtx.mAccumulatedTransform = Matrix4x4(); + } + + private: + nsDisplayListBuilder* mBuilder; + Matrix4x4 mSavedTransform; + }; + + /** + * A helper class to collect bounds rects of descendants. + * + * For a 3D context root, it's bounds is computed from the bounds of + * descendants. If we transform bounds frame by frame applying + * transforms, the bounds may turn to empty for any singular + * transform on the path, but it is not empty for the accumulated + * transform. + */ + class AutoAccumulateRect; + friend class AutoAccumulateRect; + 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; + } + + // Helpers for tables + nsDisplayTableItem* GetCurrentTableItem() { return mCurrentTableItem; } + void SetCurrentTableItem(nsDisplayTableItem* aTableItem) { mCurrentTableItem = aTableItem; } + + struct OutOfFlowDisplayData { + OutOfFlowDisplayData(const DisplayItemClip* aContainingBlockClip, + const DisplayItemScrollClip* aContainingBlockScrollClip, + const nsRect &aDirtyRect) + : mContainingBlockClip(aContainingBlockClip ? *aContainingBlockClip : DisplayItemClip()) + , mContainingBlockScrollClip(aContainingBlockScrollClip) + , mDirtyRect(aDirtyRect) + {} + DisplayItemClip mContainingBlockClip; + const DisplayItemScrollClip* mContainingBlockScrollClip; + nsRect mDirtyRect; + }; + + NS_DECLARE_FRAME_PROPERTY_DELETABLE(OutOfFlowDisplayDataProperty, + OutOfFlowDisplayData) + + static OutOfFlowDisplayData* GetOutOfFlowData(nsIFrame* aFrame) + { + return aFrame->Properties().Get(OutOfFlowDisplayDataProperty()); + } + + nsPresContext* CurrentPresContext() { + return CurrentPresShellState()->mPresShell->GetPresContext(); + } + + /** + * Accumulates the bounds of box frames that have moz-appearance + * -moz-win-exclude-glass style. Used in setting glass margins on + * Windows. + * + * We set the window opaque region (from which glass margins are computed) + * to the intersection of the glass region specified here and the opaque + * region computed during painting. So the excluded glass region actually + * *limits* the extent of the opaque area reported to Windows. We limit it + * so that changes to the computed opaque region (which can vary based on + * region optimizations and the placement of UI elements) outside the + * -moz-win-exclude-glass area don't affect the glass margins reported to + * Windows; changing those margins willy-nilly can cause the Windows 7 glass + * haze effect to jump around disconcertingly. + */ + void AddWindowExcludeGlassRegion(const nsRegion& bounds) { + mWindowExcludeGlassRegion.Or(mWindowExcludeGlassRegion, bounds); + } + const nsRegion& GetWindowExcludeGlassRegion() { + return mWindowExcludeGlassRegion; + } + /** + * Accumulates opaque stuff into the window opaque region. + */ + void AddWindowOpaqueRegion(const nsRegion& bounds) { + mWindowOpaqueRegion.Or(mWindowOpaqueRegion, bounds); + } + /** + * 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 mWindowOpaqueRegion; + } + void SetGlassDisplayItem(nsDisplayItem* aItem) { + if (mGlassDisplayItem) { + // Web pages or extensions could trigger this by using + // -moz-appearance:win-borderless-glass etc on their own elements. + // Keep the first one, since that will be the background of the root + // window + NS_WARNING("Multiple glass backgrounds found?"); + } else { + mGlassDisplayItem = aItem; + } + } + bool NeedToForceTransparentSurfaceForItem(nsDisplayItem* aItem); + + void SetContainsPluginItem() { mContainsPluginItem = true; } + bool ContainsPluginItem() { return mContainsPluginItem; } + + /** + * mContainsBlendMode is true if we processed a display item that + * has a blend mode attached. We do this so we can insert a + * nsDisplayBlendContainer in the parent stacking context. + */ + void SetContainsBlendMode(bool aContainsBlendMode) { mContainsBlendMode = aContainsBlendMode; } + bool ContainsBlendMode() const { return mContainsBlendMode; } + + uint32_t AllocatePerspectiveItemIndex() { return mPerspectiveItemIndex++; } + + DisplayListClipState& ClipState() { return mClipState; } + + /** + * 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); + + void EnterSVGEffectsContents(nsDisplayList* aHoistedItemsStorage); + void ExitSVGEffectsContents(); + + bool ShouldBuildScrollInfoItemsForHoisting() const + { return mSVGEffectsBuildingDepth > 0; } + + 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; + friend class AutoPreserves3DContext; + class AutoPreserves3DContext { + public: + explicit AutoPreserves3DContext(nsDisplayListBuilder* aBuilder) + : mBuilder(aBuilder) + , mSavedCtx(aBuilder->mPreserves3DCtx) {} + ~AutoPreserves3DContext() { + mBuilder->mPreserves3DCtx = mSavedCtx; + } + + private: + nsDisplayListBuilder* mBuilder; + Preserves3DContext mSavedCtx; + }; + + const nsRect GetPreserves3DDirtyRect(const nsIFrame *aFrame) const { + return mPreserves3DCtx.mDirtyRect; + } + void SetPreserves3DDirtyRect(const nsRect &aDirtyRect) { + mPreserves3DCtx.mDirtyRect = aDirtyRect; + } + + bool IsBuildingInvisibleItems() const { return mBuildingInvisibleItems; } + void SetBuildingInvisibleItems(bool aBuildingInvisibleItems) { + mBuildingInvisibleItems = aBuildingInvisibleItems; + } + +private: + void MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame, nsIFrame* aFrame, + const nsRect& aDirtyRect); + + /** + * Returns whether a frame acts as an animated geometry root, optionally + * returning the next ancestor to check. + */ + bool IsAnimatedGeometryRoot(nsIFrame* aFrame, nsIFrame** aParent = nullptr); + + /** + * Returns the nearest ancestor frame to aFrame that is considered to have + * (or will have) animated geometry. This can return aFrame. + */ + nsIFrame* FindAnimatedGeometryRootFrameFor(nsIFrame* aFrame); + + friend class nsDisplayCanvasBackgroundImage; + friend class nsDisplayBackgroundImage; + friend class nsDisplayFixedPosition; + AnimatedGeometryRoot* FindAnimatedGeometryRootFor(nsDisplayItem* aItem); + + AnimatedGeometryRoot* WrapAGRForFrame(nsIFrame* aAnimatedGeometryRoot, + AnimatedGeometryRoot* aParent = nullptr); + + friend class nsDisplayItem; + AnimatedGeometryRoot* FindAnimatedGeometryRootFor(nsIFrame* aFrame); + + nsDataHashtable<nsPtrHashKey<nsIFrame>, AnimatedGeometryRoot*> mFrameToAnimatedGeometryRootMap; + + /** + * Add the current frame to the AGR budget if possible and remember + * the outcome. Subsequent calls will return the same value as + * returned here. + */ + bool AddToAGRBudget(nsIFrame* aFrame); + + struct PresShellState { + nsIPresShell* mPresShell; + nsIFrame* mCaretFrame; + nsRect mCaretRect; + uint32_t mFirstFrameMarkedForDisplay; + 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; + }; + + PresShellState* CurrentPresShellState() { + NS_ASSERTION(mPresShellStates.Length() > 0, + "Someone forgot to enter a presshell"); + return &mPresShellStates[mPresShellStates.Length() - 1]; + } + + struct DocumentWillChangeBudget { + DocumentWillChangeBudget() + : mBudget(0) + {} + + uint32_t mBudget; + }; + + nsIFrame* const mReferenceFrame; + nsIFrame* mIgnoreScrollFrame; + nsDisplayLayerEventRegions* mLayerEventRegions; + PLArenaPool mPool; + nsCOMPtr<nsISelection> mBoundingSelection; + AutoTArray<PresShellState,8> mPresShellStates; + AutoTArray<nsIFrame*,100> mFramesMarkedForDisplay; + AutoTArray<ThemeGeometry,2> mThemeGeometries; + nsDisplayTableItem* mCurrentTableItem; + DisplayListClipState mClipState; + // mCurrentFrame is the frame that we're currently calling (or about to call) + // BuildDisplayList on. + const nsIFrame* mCurrentFrame; + // The reference frame for mCurrentFrame. + const nsIFrame* mCurrentReferenceFrame; + // The offset from mCurrentFrame to mCurrentReferenceFrame. + nsPoint mCurrentOffsetToReferenceFrame; + + AnimatedGeometryRoot* mCurrentAGR; + AnimatedGeometryRoot mRootAGR; + + // will-change budget tracker + nsDataHashtable<nsPtrHashKey<nsPresContext>, DocumentWillChangeBudget> + mWillChangeBudget; + + // Any frame listed in this set is already counted in the budget + // and thus is in-budget. + nsTHashtable<nsPtrHashKey<nsIFrame> > mWillChangeBudgetSet; + + // Area of animated geometry root budget already allocated + uint32_t mUsedAGRBudget; + // Set of frames already counted in budget + nsTHashtable<nsPtrHashKey<nsIFrame> > mAGRBudgetSet; + + // Relative to mCurrentFrame. + nsRect mDirtyRect; + nsRegion mWindowExcludeGlassRegion; + nsRegion mWindowOpaqueRegion; + LayoutDeviceIntRegion mWindowDraggingRegion; + LayoutDeviceIntRegion mWindowNoDraggingRegion; + // The display item for the Windows window glass background, if any + nsDisplayItem* mGlassDisplayItem; + // 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<DisplayItemScrollClip*> mScrollClipsToDestroy; + nsTArray<DisplayItemClip*> mDisplayItemClipsToDestroy; + nsDisplayListBuilderMode mMode; + ViewID mCurrentScrollParentId; + ViewID mCurrentScrollbarTarget; + uint32_t mCurrentScrollbarFlags; + Preserves3DContext mPreserves3DCtx; + uint32_t mPerspectiveItemIndex; + int32_t mSVGEffectsBuildingDepth; + bool mContainsBlendMode; + bool mIsBuildingScrollbar; + bool mCurrentScrollbarWillHaveLayer; + bool mBuildCaret; + bool mIgnoreSuppression; + bool mIsAtRootOfPseudoStackingContext; + bool mIncludeAllOutOfFlows; + bool mDescendIntoSubdocuments; + bool mSelectedFramesOnly; + bool mAccurateVisibleRegions; + bool mAllowMergingAndFlattening; + bool mWillComputePluginGeometry; + // True when we're building a display list that's directly or indirectly + // under an nsDisplayTransform + bool mInTransform; + bool mIsInChromePresContext; + bool mSyncDecodeImages; + bool mIsPaintingToWindow; + bool mIsCompositingCheap; + bool mContainsPluginItem; + bool mAncestorHasApzAwareEventHandler; + // True when the first async-scrollable scroll frame for which we build a + // display list has a display port. An async-scrollable scroll frame is one + // which WantsAsyncScroll(). + bool mHaveScrollableDisplayPort; + bool mWindowDraggingAllowed; + bool mIsBuildingForPopup; + bool mForceLayerForScrollParent; + bool mAsyncPanZoomEnabled; + bool mBuildingInvisibleItems; +}; + +class nsDisplayItem; +class nsDisplayList; +/** + * nsDisplayItems are put in singly-linked lists rooted in an nsDisplayList. + * nsDisplayItemLink holds the link. The lists are linked from lowest to + * highest in z-order. + */ +class nsDisplayItemLink { + // This is never instantiated directly, so no need to count constructors and + // destructors. +protected: + nsDisplayItemLink() : mAbove(nullptr) {} + nsDisplayItem* mAbove; + + friend class nsDisplayList; +}; + +/** + * This is the unit of rendering and event testing. Each instance of this + * class represents an entity that can be drawn on the screen, e.g., a + * frame's CSS background, or a frame's text string. + * + * nsDisplayItems can be containers --- i.e., they can perform hit testing + * and painting by recursively traversing a list of child items. + * + * These are arena-allocated during display list construction. A typical + * subclass would just have a frame pointer, so its object would be just three + * pointers (vtable, next-item, frame). + * + * Display items belong to a list at all times (except temporarily as they + * move from one list to another). + */ +class nsDisplayItem : public nsDisplayItemLink { +public: + typedef mozilla::ContainerLayerParameters ContainerLayerParameters; + typedef mozilla::DisplayItemClip DisplayItemClip; + typedef mozilla::DisplayItemScrollClip DisplayItemScrollClip; + typedef mozilla::layers::FrameMetrics FrameMetrics; + typedef mozilla::layers::ScrollMetadata ScrollMetadata; + typedef mozilla::layers::FrameMetrics::ViewID ViewID; + typedef mozilla::layers::Layer Layer; + typedef mozilla::layers::LayerManager LayerManager; + typedef mozilla::LayerState LayerState; + + // This is never instantiated directly (it has pure virtual methods), so no + // need to count constructors and destructors. + nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame); + nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + const DisplayItemScrollClip* aScrollClip); + /** + * This constructor is only used in rare cases when we need to construct + * temporary items. + */ + explicit nsDisplayItem(nsIFrame* aFrame) + : mFrame(aFrame) + , mClip(nullptr) + , mScrollClip(nullptr) + , mReferenceFrame(nullptr) + , mAnimatedGeometryRoot(nullptr) + , mForceNotVisible(false) +#ifdef MOZ_DUMP_PAINTING + , mPainted(false) +#endif + { + } + virtual ~nsDisplayItem() {} + + void* operator new(size_t aSize, + nsDisplayListBuilder* aBuilder) { + return aBuilder->Allocate(aSize); + } + +// Contains all the type integers for each display list item type +#include "nsDisplayItemTypes.h" + + struct HitTestState { + explicit HitTestState() : mInPreserves3D(false) {} + + ~HitTestState() { + NS_ASSERTION(mItemBuffer.Length() == 0, + "mItemBuffer should have been cleared"); + } + + // Handling transform items for preserve 3D frames. + bool mInPreserves3D; + AutoTArray<nsDisplayItem*, 100> mItemBuffer; + }; + + /** + * Some consecutive items should be rendered together as a unit, e.g., + * outlines for the same element. For this, we need a way for items to + * identify their type. We use the type for other purposes too. + */ + virtual Type GetType() = 0; + /** + * Pairing this with the GetUnderlyingFrame() pointer gives a key that + * uniquely identifies this display item in the display item tree. + * XXX check nsOptionEventGrabberWrapper/nsXULEventRedirectorWrapper + */ + virtual uint32_t GetPerFrameKey() { return uint32_t(GetType()); } + /** + * This is called after we've constructed a display list for event handling. + * When this is called, we've already ensured that aRect intersects the + * item's bounds and that clipping has been taking into account. + * + * @param aRect the point or rect being tested, relative to the reference + * frame. If the width and height are both 1 app unit, it indicates we're + * hit testing a point, not a rect. + * @param aState must point to a HitTestState. If you don't have one, + * just create one with the default constructor and pass it in. + * @param aOutFrames each item appends the frame(s) in this display item that + * the rect is considered over (if any) to aOutFrames. + */ + virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, + HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {} + /** + * @return the frame that this display item is based on. This is used to sort + * items by z-index and content order and for some other uses. Never + * returns null. + */ + inline nsIFrame* Frame() const { return mFrame; } + /** + * Compute the used z-index of our frame; returns zero for elements to which + * z-index does not apply, and for z-index:auto. + * @note This can be overridden, @see nsDisplayWrapList::SetOverrideZIndex. + */ + virtual int32_t ZIndex() const; + /** + * The default bounds is the frame border rect. + * @param aSnap *aSnap is set to true if the returned rect will be + * snapped to nearest device pixel edges during actual drawing. + * It might be set to false and snap anyway, so code computing the set of + * pixels affected by this display item needs to round outwards to pixel + * boundaries when *aSnap is set to false. + * This does not take the item's clipping into account. + * @return a rectangle relative to aBuilder->ReferenceFrame() that + * contains the area drawn by this display item + */ + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) + { + *aSnap = false; + return nsRect(ToReferenceFrame(), Frame()->GetSize()); + } + /** + * Returns true if nothing will be rendered inside aRect, false if uncertain. + * aRect is assumed to be contained in this item's bounds. + */ + virtual bool IsInvisibleInRect(const nsRect& aRect) + { + return false; + } + /** + * Returns the result of GetBounds intersected with the item's clip. + * The intersection is approximate since rounded corners are not taking into + * account. + */ + nsRect GetClippedBounds(nsDisplayListBuilder* aBuilder); + nsRect GetBorderRect() { + return nsRect(ToReferenceFrame(), Frame()->GetSize()); + } + nsRect GetPaddingRect() { + return Frame()->GetPaddingRectRelativeToSelf() + ToReferenceFrame(); + } + nsRect GetContentRect() { + return Frame()->GetContentRectRelativeToSelf() + ToReferenceFrame(); + } + + /** + * Checks if the frame(s) owning this display item have been marked as invalid, + * and needing repainting. + */ + virtual bool IsInvalid(nsRect& aRect) { + bool result = mFrame ? mFrame->IsInvalid(aRect) : false; + aRect += ToReferenceFrame(); + return result; + } + + /** + * Creates and initializes an nsDisplayItemGeometry object that retains the current + * areas covered by this display item. These need to retain enough information + * such that they can be compared against a future nsDisplayItem of the same type, + * and determine if repainting needs to happen. + * + * Subclasses wishing to store more information need to override both this + * and ComputeInvalidationRegion, as well as implementing an nsDisplayItemGeometry + * subclass. + * + * The default implementation tracks both the display item bounds, and the frame's + * border rect. + */ + virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) + { + return new nsDisplayItemGenericGeometry(this, aBuilder); + } + + /** + * Compares an nsDisplayItemGeometry object from a previous paint against the + * current item. Computes if the geometry of the item has changed, and the + * invalidation area required for correct repainting. + * + * The existing geometry will have been created from a display item with a + * matching GetPerFrameKey()/mFrame pair to the current item. + * + * The default implementation compares the display item bounds, and the frame's + * border rect, and invalidates the entire bounds if either rect changes. + * + * @param aGeometry The geometry of the matching display item from the + * previous paint. + * @param aInvalidRegion Output param, the region to invalidate, or + * unchanged if none. + */ + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, + const nsDisplayItemGeometry* aGeometry, + nsRegion* aInvalidRegion) + { + const nsDisplayItemGenericGeometry* geometry = static_cast<const nsDisplayItemGenericGeometry*>(aGeometry); + bool snap; + if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) || + !geometry->mBorderRect.IsEqualInterior(GetBorderRect())) { + aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds); + } + } + + /** + * An alternative default implementation of ComputeInvalidationRegion, + * that instead invalidates only the changed area between the two items. + */ + void ComputeInvalidationRegionDifference(nsDisplayListBuilder* aBuilder, + const nsDisplayItemBoundsGeometry* aGeometry, + nsRegion* aInvalidRegion) + { + bool snap; + nsRect bounds = GetBounds(aBuilder, &snap); + + if (!aGeometry->mBounds.IsEqualInterior(bounds)) { + nscoord radii[8]; + if (aGeometry->mHasRoundedCorners || + Frame()->GetBorderRadii(radii)) { + aInvalidRegion->Or(aGeometry->mBounds, bounds); + } else { + aInvalidRegion->Xor(aGeometry->mBounds, bounds); + } + } + } + + /** + * Called when the area rendered by this display item has changed (been + * invalidated or changed geometry) since the last paint. This includes + * when the display item was not rendered at all in the last paint. + * It does NOT get called when a display item was being rendered and no + * longer is, because generally that means there is no display item to + * call this method on. + */ + virtual void NotifyRenderingChanged() {} + + /** + * @param aSnap set to true if the edges of the rectangles of the opaque + * region would be snapped to device pixels when drawing + * @return a region of the item that is opaque --- that is, every pixel + * that is visible is painted with an opaque + * color. This is useful for determining when one piece + * of content completely obscures another so that we can do occlusion + * culling. + * This does not take clipping into account. + */ + virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, + bool* aSnap) + { + *aSnap = false; + return nsRegion(); + } + /** + * @return Some(nscolor) if the item is guaranteed to paint every pixel in its + * bounds with the same (possibly translucent) color + */ + virtual mozilla::Maybe<nscolor> IsUniform(nsDisplayListBuilder* aBuilder) + { return mozilla::Nothing(); } + /** + * @return true if the contents of this item are rendered fixed relative + * to the nearest viewport. + */ + virtual bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder) + { return false; } + + virtual bool ClearsBackground() + { return false; } + + virtual bool ProvidesFontSmoothingBackgroundColor(nscolor* aColor) + { return false; } + + /** + * Returns true if all layers that can be active should be forced to be + * active. Requires setting the pref layers.force-active=true. + */ + static bool ForceActiveLayers(); + + /** + * @return LAYER_NONE if BuildLayer will return null. In this case + * there is no layer for the item, and Paint should be called instead + * to paint the content using Thebes. + * Return LAYER_INACTIVE if there is a layer --- BuildLayer will + * not return null (unless there's an error) --- but the layer contents + * are not changing frequently. In this case it makes sense to composite + * the layer into a PaintedLayer with other content, so we don't have to + * recomposite it every time we paint. + * Note: GetLayerState is only allowed to return LAYER_INACTIVE if all + * descendant display items returned LAYER_INACTIVE or LAYER_NONE. Also, + * all descendant display item frames must have an active scrolled root + * that's either the same as this item's frame's active scrolled root, or + * a descendant of this item's frame. This ensures that the entire + * set of display items can be collapsed onto a single PaintedLayer. + * Return LAYER_ACTIVE if the layer is active, that is, its contents are + * changing frequently. In this case it makes sense to keep the layer + * as a separate buffer in VRAM and composite it into the destination + * every time we paint. + * + * Users of GetLayerState should check ForceActiveLayers() and if it returns + * true, change a returned value of LAYER_INACTIVE to LAYER_ACTIVE. + */ + virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aParameters) + { return mozilla::LAYER_NONE; } + /** + * Return true to indicate the layer should be constructed even if it's + * completely invisible. + */ + virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) + { return false; } + /** + * Actually paint this item to some rendering context. + * Content outside mVisibleRect need not be painted. + * aCtx must be set up as for nsDisplayList::Paint. + */ + virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) {} + +#ifdef MOZ_DUMP_PAINTING + /** + * Mark this display item as being painted via FrameLayerBuilder::DrawPaintedLayer. + */ + bool Painted() { return mPainted; } + + /** + * Check if this display item has been painted. + */ + void SetPainted() { mPainted = true; } +#endif + + /** + * Get the layer drawn by this display item. Call this only if + * GetLayerState() returns something other than LAYER_NONE. + * If GetLayerState returned LAYER_NONE then Paint will be called + * instead. + * This is called while aManager is in the construction phase. + * + * The caller (nsDisplayList) is responsible for setting the visible + * region of the layer. + * + * @param aContainerParameters should be passed to + * FrameLayerBuilder::BuildContainerLayerFor if a ContainerLayer is + * constructed. + */ + virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aContainerParameters) + { return nullptr; } + + /** + * On entry, aVisibleRegion contains the region (relative to ReferenceFrame()) + * which may be visible. If the display item opaquely covers an area, it + * can remove that area from aVisibleRegion before returning. + * nsDisplayList::ComputeVisibility automatically subtracts the region + * returned by GetOpaqueRegion, and automatically removes items whose bounds + * do not intersect the visible area, so implementations of + * nsDisplayItem::ComputeVisibility do not need to do these things. + * nsDisplayList::ComputeVisibility will already have set mVisibleRect on + * this item to the intersection of *aVisibleRegion and this item's bounds. + * We rely on that, so this should only be called by + * nsDisplayList::ComputeVisibility or nsDisplayItem::RecomputeVisibility. + * aAllowVisibleRegionExpansion is a rect where we are allowed to + * expand the visible region and is only used for making sure the + * background behind a plugin is visible. + * This method needs to be idempotent. + * + * @return true if the item is visible, false if no part of the item + * is visible. + */ + virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion); + + /** + * Try to merge with the other item (which is below us in the display + * list). This gets used by nsDisplayClip to coalesce clipping operations + * (optimization), by nsDisplayOpacity to merge rendering for the same + * content element into a single opacity group (correctness), and will be + * used by nsDisplayOutline to merge multiple outlines for the same element + * (also for correctness). + * @return true if the merge was successful and the other item should be deleted + */ + virtual bool TryMerge(nsDisplayItem* aItem) { + return false; + } + + /** + * Appends the underlying frames of all display items that have been + * merged into this one (excluding this item's own underlying frame) + * to aFrames. + */ + virtual void GetMergedFrames(nsTArray<nsIFrame*>* aFrames) {} + + /** + * During the visibility computation and after TryMerge, display lists may + * return true here to flatten themselves away, removing them. This + * flattening is distinctly different from FlattenTo, which occurs before + * items are merged together. + */ + virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) { + return false; + } + + /** + * If this has a child list where the children are in the same coordinate + * system as this item (i.e., they have the same reference frame), + * return the list. + */ + virtual nsDisplayList* GetSameCoordinateSystemChildren() { return nullptr; } + virtual void UpdateBounds(nsDisplayListBuilder* aBuilder) {} + /** + * Do UpdateBounds() for items with frames establishing or extending + * 3D rendering context. + * + * This function is called by UpdateBoundsFor3D() of + * nsDisplayTransform(), and it is called by + * BuildDisplayListForStackingContext() on transform items + * establishing 3D rendering context. + * + * The bounds of a transform item with the frame establishing 3D + * rendering context should be computed by calling + * DoUpdateBoundsPreserves3D() on all descendants that participate + * the same 3d rendering context. + */ + virtual void DoUpdateBoundsPreserves3D(nsDisplayListBuilder* aBuilder) {} + + /** + * If this has a child list, return it, even if the children are in + * a different coordinate system to this item. + */ + virtual nsDisplayList* GetChildren() { return nullptr; } + + /** + * Returns the visible rect. + */ + const nsRect& GetVisibleRect() const { return mVisibleRect; } + + /** + * Returns the visible rect for the children, relative to their + * reference frame. Can be different from mVisibleRect for nsDisplayTransform, + * since the reference frame for the children is different from the reference + * frame for the item itself. + */ + virtual const nsRect& GetVisibleRectForChildren() const { return mVisibleRect; } + + /** + * Stores the given opacity value to be applied when drawing. It is an error to + * call this if CanApplyOpacity returned false. + */ + virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder, + float aOpacity, + const DisplayItemClip* aClip) { + NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity not supported on this type"); + } + /** + * Returns true if this display item would return true from ApplyOpacity without + * actually applying the opacity. Otherwise returns false. + */ + virtual bool CanApplyOpacity() const { + return false; + } + + /** + * For debugging and stuff + */ + virtual const char* Name() = 0; + + virtual void WriteDebugInfo(std::stringstream& aStream) {} + + nsDisplayItem* GetAbove() { return mAbove; } + + /** + * Like ComputeVisibility, but does the work that nsDisplayList + * does per-item: + * -- Intersects GetBounds with aVisibleRegion and puts the result + * in mVisibleRect + * -- Subtracts bounds from aVisibleRegion if the item is opaque + */ + bool RecomputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion); + + /** + * Returns the result of aBuilder->ToReferenceFrame(GetUnderlyingFrame()) + */ + const nsPoint& ToReferenceFrame() const { + NS_ASSERTION(mFrame, "No frame?"); + return mToReferenceFrame; + } + /** + * @return the root of the display list's frame (sub)tree, whose origin + * establishes the coordinate system for the display list + */ + const nsIFrame* ReferenceFrame() const { return mReferenceFrame; } + + /** + * Returns the reference frame for display item children of this item. + */ + virtual const nsIFrame* ReferenceFrameForChildren() const { return mReferenceFrame; } + + AnimatedGeometryRoot* GetAnimatedGeometryRoot() const { + MOZ_ASSERT(mAnimatedGeometryRoot, "Must have cached AGR before accessing it!"); + return mAnimatedGeometryRoot; + } + + virtual struct AnimatedGeometryRoot* AnimatedGeometryRootForScrollMetadata() const { + return GetAnimatedGeometryRoot(); + } + + /** + * Checks if this display item (or any children) contains content that might + * be rendered with component alpha (e.g. subpixel antialiasing). Returns the + * bounds of the area that needs component alpha, or an empty rect if nothing + * in the item does. + */ + virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) { return nsRect(); } + + /** + * Disable usage of component alpha. Currently only relevant for items that have text. + */ + virtual void DisableComponentAlpha() {} + + /** + * Check if we can add async animations to the layer for this display item. + */ + virtual bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) { + return false; + } + + virtual bool SupportsOptimizingToImage() { return false; } + + const DisplayItemClip& GetClip() + { + return mClip ? *mClip : DisplayItemClip::NoClip(); + } + void SetClip(nsDisplayListBuilder* aBuilder, const DisplayItemClip& aClip) + { + if (!aClip.HasClip()) { + mClip = nullptr; + return; + } + mClip = aBuilder->AllocateDisplayItemClip(aClip); + } + + void IntersectClip(nsDisplayListBuilder* aBuilder, const DisplayItemClip& aClip) + { + if (mClip) { + DisplayItemClip temp = *mClip; + temp.IntersectWith(aClip); + SetClip(aBuilder, temp); + } else { + SetClip(aBuilder, aClip); + } + } + + void SetScrollClip(const DisplayItemScrollClip* aScrollClip) { mScrollClip = aScrollClip; } + const DisplayItemScrollClip* ScrollClip() const { return mScrollClip; } + + bool BackfaceIsHidden() { + return mFrame->BackfaceIsHidden(); + } + +protected: + friend class nsDisplayList; + + nsDisplayItem() { mAbove = nullptr; } + + nsIFrame* mFrame; + const DisplayItemClip* mClip; + const DisplayItemScrollClip* mScrollClip; + // Result of FindReferenceFrameFor(mFrame), if mFrame is non-null + const nsIFrame* mReferenceFrame; + struct AnimatedGeometryRoot* mAnimatedGeometryRoot; + // Result of ToReferenceFrame(mFrame), if mFrame is non-null + nsPoint mToReferenceFrame; + // This is the rectangle that needs to be painted. + // Display item construction sets this to the dirty rect. + // nsDisplayList::ComputeVisibility sets this to the visible region + // of the item by intersecting the current visible region with the bounds + // of the item. Paint implementations can use this to limit their drawing. + // Guaranteed to be contained in GetBounds(). + nsRect mVisibleRect; + bool mForceNotVisible; +#ifdef MOZ_DUMP_PAINTING + // True if this frame has been painted. + bool mPainted; +#endif +}; + +/** + * Manages a singly-linked list of display list items. + * + * mSentinel is the sentinel list value, the first value in the null-terminated + * linked list of items. mTop is the last item in the list (whose 'above' + * pointer is null). This class has no virtual methods. So list objects are just + * two pointers. + * + * Stepping upward through this list is very fast. Stepping downward is very + * slow so we don't support it. The methods that need to step downward + * (HitTest(), ComputeVisibility()) internally build a temporary array of all + * the items while they do the downward traversal, so overall they're still + * linear time. We have optimized for efficient AppendToTop() of both + * items and lists, with minimal codesize. AppendToBottom() is efficient too. + */ +class nsDisplayList { +public: + typedef mozilla::DisplayItemScrollClip DisplayItemScrollClip; + typedef mozilla::layers::Layer Layer; + typedef mozilla::layers::LayerManager LayerManager; + typedef mozilla::layers::PaintedLayer PaintedLayer; + + /** + * Create an empty list. + */ + nsDisplayList() + : mIsOpaque(false) + , mForceTransparentSurface(false) + { + mTop = &mSentinel; + mSentinel.mAbove = nullptr; + } + ~nsDisplayList() { + if (mSentinel.mAbove) { + NS_WARNING("Nonempty list left over?"); + } + DeleteAll(); + } + + /** + * Append an item to the top of the list. The item must not currently + * be in a list and cannot be null. + */ + void AppendToTop(nsDisplayItem* aItem) { + NS_ASSERTION(aItem, "No item to append!"); + NS_ASSERTION(!aItem->mAbove, "Already in a list!"); + mTop->mAbove = aItem; + mTop = aItem; + } + + /** + * Append a new item to the top of the list. The intended usage is + * AppendNewToTop(new ...); + */ + void AppendNewToTop(nsDisplayItem* aItem) { + if (aItem) { + AppendToTop(aItem); + } + } + + /** + * Append a new item to the bottom of the list. The intended usage is + * AppendNewToBottom(new ...); + */ + void AppendNewToBottom(nsDisplayItem* aItem) { + if (aItem) { + AppendToBottom(aItem); + } + } + + /** + * Append a new item to the bottom of the list. The item must be non-null + * and not already in a list. + */ + void AppendToBottom(nsDisplayItem* aItem) { + NS_ASSERTION(aItem, "No item to append!"); + NS_ASSERTION(!aItem->mAbove, "Already in a list!"); + aItem->mAbove = mSentinel.mAbove; + mSentinel.mAbove = aItem; + if (mTop == &mSentinel) { + mTop = aItem; + } + } + + /** + * Removes all items from aList and appends them to the top of this list + */ + void AppendToTop(nsDisplayList* aList) { + if (aList->mSentinel.mAbove) { + mTop->mAbove = aList->mSentinel.mAbove; + mTop = aList->mTop; + aList->mTop = &aList->mSentinel; + aList->mSentinel.mAbove = nullptr; + } + } + + /** + * Removes all items from aList and prepends them to the bottom of this list + */ + void AppendToBottom(nsDisplayList* aList) { + if (aList->mSentinel.mAbove) { + aList->mTop->mAbove = mSentinel.mAbove; + mSentinel.mAbove = aList->mSentinel.mAbove; + if (mTop == &mSentinel) { + mTop = aList->mTop; + } + + aList->mTop = &aList->mSentinel; + aList->mSentinel.mAbove = nullptr; + } + } + + /** + * Remove an item from the bottom of the list and return it. + */ + nsDisplayItem* RemoveBottom(); + + /** + * Remove all items from the list and call their destructors. + */ + void DeleteAll(); + + /** + * @return the item at the top of the list, or null if the list is empty + */ + nsDisplayItem* GetTop() const { + return mTop != &mSentinel ? static_cast<nsDisplayItem*>(mTop) : nullptr; + } + /** + * @return the item at the bottom of the list, or null if the list is empty + */ + nsDisplayItem* GetBottom() const { return mSentinel.mAbove; } + bool IsEmpty() const { return mTop == &mSentinel; } + + /** + * This is *linear time*! + * @return the number of items in the list + */ + uint32_t Count() const; + /** + * Stable sort the list by the z-order of GetUnderlyingFrame() on + * each item. 'auto' is counted as zero. + * It is assumed that the list is already in content document order. + */ + void SortByZOrder(); + /** + * Stable sort the list by the tree order of the content of + * GetUnderlyingFrame() on each item. z-index is ignored. + * @param aCommonAncestor a common ancestor of all the content elements + * associated with the display items, for speeding up tree order + * checks, or nullptr if not known; it's only a hint, if it is not an + * ancestor of some elements, then we lose performance but not correctness + */ + void SortByContentOrder(nsIContent* aCommonAncestor); + + /** + * Generic stable sort. Take care, because some of the items might be nsDisplayLists + * themselves. + * aCmp(item1, item2) should return true if item1 <= item2. We sort the items + * into increasing order. + */ + typedef bool (* SortLEQ)(nsDisplayItem* aItem1, nsDisplayItem* aItem2, + void* aClosure); + void Sort(SortLEQ aCmp, void* aClosure); + + /** + * Compute visiblity for the items in the list. + * We put this logic here so it can be shared by top-level + * painting and also display items that maintain child lists. + * This is also a good place to put ComputeVisibility-related logic + * that must be applied to every display item. In particular, this + * sets mVisibleRect on each display item. + * This sets mIsOpaque if the entire visible area of this list has + * been removed from aVisibleRegion when we return. + * This does not remove any items from the list, so we can recompute + * visiblity with different regions later (see + * FrameLayerBuilder::DrawPaintedLayer). + * This method needs to be idempotent. + * + * @param aVisibleRegion the area that is visible, relative to the + * reference frame; on return, this contains the area visible under the list. + * I.e., opaque contents of this list are subtracted from aVisibleRegion. + * @param aListVisibleBounds must be equal to the bounds of the intersection + * of aVisibleRegion and GetBounds() for this list. + * @return true if any item in the list is visible. + */ + bool ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion, + const nsRect& aListVisibleBounds); + + /** + * As ComputeVisibilityForSublist, but computes visibility for a root + * list (a list that does not belong to an nsDisplayItem). + * This method needs to be idempotent. + * + * @param aVisibleRegion the area that is visible + */ + bool ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion); + + /** + * Returns true if the visible region output from ComputeVisiblity was + * empty, i.e. everything visible in this list is opaque. + */ + bool IsOpaque() const { + return mIsOpaque; + } + + /** + * Returns true if any display item requires the surface to be transparent. + */ + bool NeedsTransparentSurface() const { + return mForceTransparentSurface; + } + /** + * Paint the list to the rendering context. We assume that (0,0) in aCtx + * corresponds to the origin of the reference frame. For best results, + * aCtx's current transform should make (0,0) pixel-aligned. The + * rectangle in aDirtyRect is painted, which *must* be contained in the + * dirty rect used to construct the display list. + * + * If aFlags contains PAINT_USE_WIDGET_LAYERS and + * ShouldUseWidgetLayerManager() is set, then we will paint using + * the reference frame's widget's layer manager (and ctx may be null), + * otherwise we will use a temporary BasicLayerManager and ctx must + * not be null. + * + * If PAINT_EXISTING_TRANSACTION is set, the reference frame's widget's + * layer manager has already had BeginTransaction() called on it and + * we should not call it again. + * + * If PAINT_COMPRESSED is set, the FrameLayerBuilder should be set to compressed mode + * to avoid short cut optimizations. + * + * This must only be called on the root display list of the display list + * tree. + * + * We return the layer manager used for painting --- mainly so that + * callers can dump its layer tree if necessary. + */ + enum { + PAINT_DEFAULT = 0, + PAINT_USE_WIDGET_LAYERS = 0x01, + PAINT_EXISTING_TRANSACTION = 0x04, + PAINT_NO_COMPOSITE = 0x08, + PAINT_COMPRESSED = 0x10 + }; + already_AddRefed<LayerManager> PaintRoot(nsDisplayListBuilder* aBuilder, + nsRenderingContext* aCtx, + uint32_t aFlags); + /** + * Get the bounds. Takes the union of the bounds of all children. + * The result is not cached. + */ + nsRect GetBounds(nsDisplayListBuilder* aBuilder) const; + /** + * Return the union of the scroll clipped bounds of all children. To get the + * scroll clipped bounds of a child item, we start with the item's clipped + * bounds and walk its scroll clip chain up to (but not including) + * aIncludeScrollClipsUpTo, and take each scroll clip into account. For + * scroll clips from async scrollable frames we assume that the item can move + * anywhere inside that scroll frame. + * In other words, the return value from this method includes all pixels that + * could potentially be covered by items in this list under async scrolling. + */ + nsRect GetScrollClippedBoundsUpTo(nsDisplayListBuilder* aBuilder, + const DisplayItemScrollClip* aIncludeScrollClipsUpTo) const; + /** + * Find the topmost display item that returns a non-null frame, and return + * the frame. + */ + void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, + nsDisplayItem::HitTestState* aState, + nsTArray<nsIFrame*> *aOutFrames) const; + /** + * Compute the union of the visible rects of the items in the list. The + * result is not cached. + */ + nsRect GetVisibleRect() const; + + void SetIsOpaque() + { + mIsOpaque = true; + } + void SetNeedsTransparentSurface() + { + mForceTransparentSurface = true; + } + +private: + // This class is only used on stack, so we don't have to worry about leaking + // it. Don't let us be heap-allocated! + void* operator new(size_t sz) CPP_THROW_NEW; + + nsDisplayItemLink mSentinel; + nsDisplayItemLink* mTop; + + // This is set to true by FrameLayerBuilder if the final visible region + // is empty (i.e. everything that was visible is covered by some + // opaque content in this list). + bool mIsOpaque; + // This is set to true by FrameLayerBuilder if any display item in this + // list needs to force the surface containing this list to be transparent. + bool mForceTransparentSurface; +}; + +/** + * This is passed as a parameter to nsIFrame::BuildDisplayList. That method + * will put any generated items onto the appropriate list given here. It's + * basically just a collection with one list for each separate stacking layer. + * The lists themselves are external to this object and thus can be shared + * with others. Some of the list pointers may even refer to the same list. + */ +class nsDisplayListSet { +public: + /** + * @return a list where one should place the border and/or background for + * this frame (everything from steps 1 and 2 of CSS 2.1 appendix E) + */ + nsDisplayList* BorderBackground() const { return mBorderBackground; } + /** + * @return a list where one should place the borders and/or backgrounds for + * block-level in-flow descendants (step 4 of CSS 2.1 appendix E) + */ + nsDisplayList* BlockBorderBackgrounds() const { return mBlockBorderBackgrounds; } + /** + * @return a list where one should place descendant floats (step 5 of + * CSS 2.1 appendix E) + */ + nsDisplayList* Floats() const { return mFloats; } + /** + * @return a list where one should place the (pseudo) stacking contexts + * for descendants of this frame (everything from steps 3, 7 and 8 + * of CSS 2.1 appendix E) + */ + nsDisplayList* PositionedDescendants() const { return mPositioned; } + /** + * @return a list where one should place the outlines + * for this frame and its descendants (step 9 of CSS 2.1 appendix E) + */ + nsDisplayList* Outlines() const { return mOutlines; } + /** + * @return a list where one should place all other content + */ + nsDisplayList* Content() const { return mContent; } + + nsDisplayListSet(nsDisplayList* aBorderBackground, + nsDisplayList* aBlockBorderBackgrounds, + nsDisplayList* aFloats, + nsDisplayList* aContent, + nsDisplayList* aPositionedDescendants, + nsDisplayList* aOutlines) : + mBorderBackground(aBorderBackground), + mBlockBorderBackgrounds(aBlockBorderBackgrounds), + mFloats(aFloats), + mContent(aContent), + mPositioned(aPositionedDescendants), + mOutlines(aOutlines) { + } + + /** + * A copy constructor that lets the caller override the BorderBackground + * list. + */ + nsDisplayListSet(const nsDisplayListSet& aLists, + nsDisplayList* aBorderBackground) : + mBorderBackground(aBorderBackground), + mBlockBorderBackgrounds(aLists.BlockBorderBackgrounds()), + mFloats(aLists.Floats()), + mContent(aLists.Content()), + mPositioned(aLists.PositionedDescendants()), + mOutlines(aLists.Outlines()) { + } + + /** + * Move all display items in our lists to top of the corresponding lists in the + * destination. + */ + void MoveTo(const nsDisplayListSet& aDestination) const; + +private: + // This class is only used on stack, so we don't have to worry about leaking + // it. Don't let us be heap-allocated! + void* operator new(size_t sz) CPP_THROW_NEW; + +protected: + nsDisplayList* mBorderBackground; + nsDisplayList* mBlockBorderBackgrounds; + nsDisplayList* mFloats; + nsDisplayList* mContent; + nsDisplayList* mPositioned; + nsDisplayList* mOutlines; +}; + +/** + * A specialization of nsDisplayListSet where the lists are actually internal + * to the object, and all distinct. + */ +struct nsDisplayListCollection : public nsDisplayListSet { + nsDisplayListCollection() : + nsDisplayListSet(&mLists[0], &mLists[1], &mLists[2], &mLists[3], &mLists[4], + &mLists[5]) {} + explicit nsDisplayListCollection(nsDisplayList* aBorderBackground) : + nsDisplayListSet(aBorderBackground, &mLists[1], &mLists[2], &mLists[3], &mLists[4], + &mLists[5]) {} + + /** + * Sort all lists by content order. + */ + void SortAllByContentOrder(nsIContent* aCommonAncestor) { + for (int32_t i = 0; i < 6; ++i) { + mLists[i].SortByContentOrder(aCommonAncestor); + } + } + +private: + // This class is only used on stack, so we don't have to worry about leaking + // it. Don't let us be heap-allocated! + void* operator new(size_t sz) CPP_THROW_NEW; + + nsDisplayList mLists[6]; +}; + + +class nsDisplayImageContainer : public nsDisplayItem { +public: + typedef mozilla::LayerIntPoint LayerIntPoint; + typedef mozilla::LayoutDeviceRect LayoutDeviceRect; + typedef mozilla::layers::ImageContainer ImageContainer; + typedef mozilla::layers::ImageLayer ImageLayer; + + nsDisplayImageContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) + : nsDisplayItem(aBuilder, aFrame) + {} + + /** + * @return true if this display item can be optimized into an image layer. + * It is an error to call GetContainer() unless you've called + * CanOptimizeToImageLayer() first and it returned true. + */ + virtual bool CanOptimizeToImageLayer(LayerManager* aManager, + nsDisplayListBuilder* aBuilder); + + already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager, + nsDisplayListBuilder* aBuilder); + void ConfigureLayer(ImageLayer* aLayer, + const ContainerLayerParameters& aParameters); + + virtual already_AddRefed<imgIContainer> GetImage() = 0; + + virtual nsRect GetDestRect() = 0; + + virtual bool SupportsOptimizingToImage() override { return true; } +}; + +/** + * Use this class to implement not-very-frequently-used display items + * that are not opaque, do not receive events, and are bounded by a frame's + * border-rect. + * + * This should not be used for display items which are created frequently, + * because each item is one or two pointers bigger than an item from a + * custom display item class could be, and fractionally slower. However it does + * save code size. We use this for infrequently-used item types. + */ +class nsDisplayGeneric : public nsDisplayItem { +public: + typedef class mozilla::gfx::DrawTarget DrawTarget; + + typedef void (* PaintCallback)(nsIFrame* aFrame, DrawTarget* aDrawTarget, + const nsRect& aDirtyRect, nsPoint aFramePt); + + // XXX: should be removed eventually + typedef void (* OldPaintCallback)(nsIFrame* aFrame, nsRenderingContext* aCtx, + const nsRect& aDirtyRect, nsPoint aFramePt); + + nsDisplayGeneric(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + PaintCallback aPaint, const char* aName, Type aType) + : nsDisplayItem(aBuilder, aFrame) + , mPaint(aPaint) + , mOldPaint(nullptr) + , mName(aName) + , mType(aType) + { + MOZ_COUNT_CTOR(nsDisplayGeneric); + } + + // XXX: should be removed eventually + nsDisplayGeneric(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + OldPaintCallback aOldPaint, const char* aName, Type aType) + : nsDisplayItem(aBuilder, aFrame) + , mPaint(nullptr) + , mOldPaint(aOldPaint) + , mName(aName) + , mType(aType) + { + MOZ_COUNT_CTOR(nsDisplayGeneric); + } +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayGeneric() { + MOZ_COUNT_DTOR(nsDisplayGeneric); + } +#endif + + virtual void Paint(nsDisplayListBuilder* aBuilder, + nsRenderingContext* aCtx) override { + MOZ_ASSERT(!!mPaint != !!mOldPaint); + if (mPaint) { + mPaint(mFrame, aCtx->GetDrawTarget(), mVisibleRect, ToReferenceFrame()); + } else { + mOldPaint(mFrame, aCtx, mVisibleRect, ToReferenceFrame()); + } + } + NS_DISPLAY_DECL_NAME(mName, mType) + +protected: + PaintCallback mPaint; + OldPaintCallback mOldPaint; // XXX: should be removed eventually + const char* mName; + Type mType; +}; + +/** + * Generic display item that can contain overflow. Use this in lieu of + * nsDisplayGeneric if you have a frame that should use the visual overflow + * rect of its frame when drawing items, instead of the frame's bounds. + */ +class nsDisplayGenericOverflow : public nsDisplayGeneric { + public: + nsDisplayGenericOverflow(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + PaintCallback aPaint, const char* aName, Type aType) + : nsDisplayGeneric(aBuilder, aFrame, aPaint, aName, aType) + { + MOZ_COUNT_CTOR(nsDisplayGenericOverflow); + } + // XXX: should be removed eventually + nsDisplayGenericOverflow(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + OldPaintCallback aOldPaint, const char* aName, Type aType) + : nsDisplayGeneric(aBuilder, aFrame, aOldPaint, aName, aType) + { + MOZ_COUNT_CTOR(nsDisplayGenericOverflow); + } + #ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayGenericOverflow() { + MOZ_COUNT_DTOR(nsDisplayGenericOverflow); + } + #endif + + /** + * Returns the frame's visual overflow rect instead of the frame's bounds. + */ + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, + bool* aSnap) override + { + *aSnap = false; + return Frame()->GetVisualOverflowRect() + ToReferenceFrame(); + } +}; + +#if defined(MOZ_REFLOW_PERF_DSP) && defined(MOZ_REFLOW_PERF) +/** + * This class implements painting of reflow counts. Ideally, we would simply + * make all the frame names be those returned by nsFrame::GetFrameName + * (except that tosses in the content tag name!) and support only one color + * and eliminate this class altogether in favor of nsDisplayGeneric, but for + * the time being we can't pass args to a PaintCallback, so just have a + * separate class to do the right thing. Sadly, this alsmo means we need to + * hack all leaf frame classes to handle this. + * + * XXXbz the color thing is a bit of a mess, but 0 basically means "not set" + * here... I could switch it all to nscolor, but why bother? + */ +class nsDisplayReflowCount : public nsDisplayItem { +public: + nsDisplayReflowCount(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + const char* aFrameName, + uint32_t aColor = 0) + : nsDisplayItem(aBuilder, aFrame), + mFrameName(aFrameName), + mColor(aColor) + { + MOZ_COUNT_CTOR(nsDisplayReflowCount); + } +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayReflowCount() { + MOZ_COUNT_DTOR(nsDisplayReflowCount); + } +#endif + + virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override { + mFrame->PresContext()->PresShell()->PaintCount(mFrameName, aCtx, + mFrame->PresContext(), + mFrame, ToReferenceFrame(), + mColor); + } + NS_DISPLAY_DECL_NAME("nsDisplayReflowCount", TYPE_REFLOW_COUNT) +protected: + const char* mFrameName; + nscolor mColor; +}; + +#define DO_GLOBAL_REFLOW_COUNT_DSP(_name) \ + PR_BEGIN_MACRO \ + if (!aBuilder->IsBackgroundOnly() && !aBuilder->IsForEventDelivery() && \ + PresContext()->PresShell()->IsPaintingFrameCounts()) { \ + aLists.Outlines()->AppendNewToTop( \ + new (aBuilder) nsDisplayReflowCount(aBuilder, this, _name)); \ + } \ + PR_END_MACRO + +#define DO_GLOBAL_REFLOW_COUNT_DSP_COLOR(_name, _color) \ + PR_BEGIN_MACRO \ + if (!aBuilder->IsBackgroundOnly() && !aBuilder->IsForEventDelivery() && \ + PresContext()->PresShell()->IsPaintingFrameCounts()) { \ + aLists.Outlines()->AppendNewToTop( \ + new (aBuilder) nsDisplayReflowCount(aBuilder, this, _name, _color)); \ + } \ + PR_END_MACRO + +/* + Macro to be used for classes that don't actually implement BuildDisplayList + */ +#define DECL_DO_GLOBAL_REFLOW_COUNT_DSP(_class, _super) \ + void BuildDisplayList(nsDisplayListBuilder* aBuilder, \ + const nsRect& aDirtyRect, \ + const nsDisplayListSet& aLists) { \ + DO_GLOBAL_REFLOW_COUNT_DSP(#_class); \ + _super::BuildDisplayList(aBuilder, aDirtyRect, aLists); \ + } + +#else // MOZ_REFLOW_PERF_DSP && MOZ_REFLOW_PERF + +#define DO_GLOBAL_REFLOW_COUNT_DSP(_name) +#define DO_GLOBAL_REFLOW_COUNT_DSP_COLOR(_name, _color) +#define DECL_DO_GLOBAL_REFLOW_COUNT_DSP(_class, _super) + +#endif // MOZ_REFLOW_PERF_DSP && MOZ_REFLOW_PERF + +class nsDisplayCaret : public nsDisplayItem { +public: + nsDisplayCaret(nsDisplayListBuilder* aBuilder, nsIFrame* aCaretFrame); +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayCaret(); +#endif + + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override; + virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override; + NS_DISPLAY_DECL_NAME("Caret", TYPE_CARET) + +protected: + RefPtr<nsCaret> mCaret; + nsRect mBounds; +}; + +/** + * The standard display item to paint the CSS borders of a frame. + */ +class nsDisplayBorder : public nsDisplayItem { +public: + nsDisplayBorder(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame); + +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayBorder() { + MOZ_COUNT_DTOR(nsDisplayBorder); + } +#endif + + virtual bool IsInvisibleInRect(const nsRect& aRect) override; + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override; + virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override; + NS_DISPLAY_DECL_NAME("Border", TYPE_BORDER) + + virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override; + + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, + const nsDisplayItemGeometry* aGeometry, + nsRegion* aInvalidRegion) override; + +protected: + nsRect CalculateBounds(const nsStyleBorder& aStyleBorder); + + nsRect mBounds; +}; + +/** + * A simple display item that just renders a solid color across the + * specified bounds. For canvas frames (in the CSS sense) we split off the + * drawing of the background color into this class (from nsDisplayBackground + * via nsDisplayCanvasBackground). This is done so that we can always draw a + * background color to avoid ugly flashes of white when we can't draw a full + * frame tree (ie when a page is loading). The bounds can differ from the + * frame's bounds -- this is needed when a frame/iframe is loading and there + * is not yet a frame tree to go in the frame/iframe so we use the subdoc + * frame of the parent document as a standin. + */ +class nsDisplaySolidColorBase : public nsDisplayItem { +public: + nsDisplaySolidColorBase(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nscolor aColor) + : nsDisplayItem(aBuilder, aFrame), mColor(aColor) + {} + + virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override + { + return new nsDisplaySolidColorGeometry(this, aBuilder, mColor); + } + + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, + const nsDisplayItemGeometry* aGeometry, + nsRegion* aInvalidRegion) override + { + const nsDisplaySolidColorGeometry* geometry = + static_cast<const nsDisplaySolidColorGeometry*>(aGeometry); + if (mColor != geometry->mColor) { + bool dummy; + aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &dummy)); + return; + } + ComputeInvalidationRegionDifference(aBuilder, geometry, aInvalidRegion); + } + + virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, + bool* aSnap) override { + *aSnap = false; + nsRegion result; + if (NS_GET_A(mColor) == 255) { + result = GetBounds(aBuilder, aSnap); + } + return result; + } + + virtual mozilla::Maybe<nscolor> IsUniform(nsDisplayListBuilder* aBuilder) override + { + return mozilla::Some(mColor); + } + +protected: + nscolor mColor; +}; + +class nsDisplaySolidColor : public nsDisplaySolidColorBase { +public: + nsDisplaySolidColor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + const nsRect& aBounds, nscolor aColor) + : nsDisplaySolidColorBase(aBuilder, aFrame, aColor), mBounds(aBounds) + { + NS_ASSERTION(NS_GET_A(aColor) > 0, "Don't create invisible nsDisplaySolidColors!"); + MOZ_COUNT_CTOR(nsDisplaySolidColor); + } +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplaySolidColor() { + MOZ_COUNT_DTOR(nsDisplaySolidColor); + } +#endif + + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override; + + virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override; + + virtual void WriteDebugInfo(std::stringstream& aStream) override; + + NS_DISPLAY_DECL_NAME("SolidColor", TYPE_SOLID_COLOR) + +private: + nsRect mBounds; +}; + +/** + * A display item that renders a solid color over a region. This is not + * exposed through CSS, its only purpose is efficient invalidation of + * the find bar highlighter dimmer. + */ +class nsDisplaySolidColorRegion : public nsDisplayItem { + typedef mozilla::gfx::Color Color; + +public: + nsDisplaySolidColorRegion(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + const nsRegion& aRegion, nscolor aColor) + : nsDisplayItem(aBuilder, aFrame), mRegion(aRegion), mColor(Color::FromABGR(aColor)) + { + NS_ASSERTION(NS_GET_A(aColor) > 0, "Don't create invisible nsDisplaySolidColorRegions!"); + MOZ_COUNT_CTOR(nsDisplaySolidColorRegion); + } +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplaySolidColorRegion() { + MOZ_COUNT_DTOR(nsDisplaySolidColorRegion); + } +#endif + + virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override + { + return new nsDisplaySolidColorRegionGeometry(this, aBuilder, mRegion, mColor); + } + + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, + const nsDisplayItemGeometry* aGeometry, + nsRegion* aInvalidRegion) override + { + const nsDisplaySolidColorRegionGeometry* geometry = + static_cast<const nsDisplaySolidColorRegionGeometry*>(aGeometry); + if (mColor == geometry->mColor) { + aInvalidRegion->Xor(geometry->mRegion, mRegion); + } else { + aInvalidRegion->Or(geometry->mRegion.GetBounds(), mRegion.GetBounds()); + } + } + +protected: + + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override; + virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override; + virtual void WriteDebugInfo(std::stringstream& aStream) override; + + NS_DISPLAY_DECL_NAME("SolidColorRegion", TYPE_SOLID_COLOR_REGION) + +private: + nsRegion mRegion; + Color mColor; +}; + +/** + * A display item to paint one background-image for a frame. Each background + * image layer gets its own nsDisplayBackgroundImage. + */ +class nsDisplayBackgroundImage : public nsDisplayImageContainer { +public: + /** + * aLayer signifies which background layer this item represents. + * aIsThemed should be the value of aFrame->IsThemed. + * aBackgroundStyle should be the result of + * nsCSSRendering::FindBackground, or null if FindBackground returned false. + * aBackgroundRect is relative to aFrame. + */ + nsDisplayBackgroundImage(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + uint32_t aLayer, const nsRect& aBackgroundRect, + const nsStyleBackground* aBackgroundStyle); + virtual ~nsDisplayBackgroundImage(); + + // This will create and append new items for all the layers of the + // background. Returns whether we appended a themed background. + // aAllowWillPaintBorderOptimization should usually be left at true, unless + // aFrame has special border drawing that causes opaque borders to not + // actually be opaque. + static bool AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuilder, + nsIFrame* aFrame, + const nsRect& aBackgroundRect, + nsDisplayList* aList, + bool aAllowWillPaintBorderOptimization = true, + nsStyleContext* aStyleContext = nullptr); + + virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aParameters) override; + + virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aContainerParameters) override; + + virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, + HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) override; + virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion) override; + virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, + bool* aSnap) override; + virtual mozilla::Maybe<nscolor> IsUniform(nsDisplayListBuilder* aBuilder) override; + /** + * GetBounds() returns the background painting area. + */ + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override; + virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override; + virtual uint32_t GetPerFrameKey() override; + NS_DISPLAY_DECL_NAME("Background", TYPE_BACKGROUND) + + /** + * Return the background positioning area. + * (GetBounds() returns the background painting area.) + * Can be called only when mBackgroundStyle is non-null. + */ + nsRect GetPositioningArea(); + + /** + * Returns true if existing rendered pixels of this display item may need + * to be redrawn if the positioning area size changes but its position does + * not. + * If false, only the changed painting area needs to be redrawn when the + * positioning area size changes but its position does not. + */ + bool RenderingMightDependOnPositioningAreaSizeChange(); + + virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override + { + return new nsDisplayBackgroundGeometry(this, aBuilder); + } + + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, + const nsDisplayItemGeometry* aGeometry, + nsRegion* aInvalidRegion) override; + + virtual bool CanOptimizeToImageLayer(LayerManager* aManager, + nsDisplayListBuilder* aBuilder) override; + virtual already_AddRefed<imgIContainer> GetImage() override; + virtual nsRect GetDestRect() override; + + static nsRegion GetInsideClipRegion(nsDisplayItem* aItem, uint8_t aClip, + const nsRect& aRect, const nsRect& aBackgroundRect); + + virtual bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder) override; + +protected: + typedef class mozilla::layers::ImageContainer ImageContainer; + typedef class mozilla::layers::ImageLayer ImageLayer; + + bool TryOptimizeToImageLayer(LayerManager* aManager, nsDisplayListBuilder* aBuilder); + bool IsNonEmptyFixedImage() const; + nsRect GetBoundsInternal(nsDisplayListBuilder* aBuilder); + bool ShouldTreatAsFixed() const; + bool ComputeShouldTreatAsFixed(bool isTransformedFixed) const; + + void PaintInternal(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx, + const nsRect& aBounds, nsRect* aClipRect); + + // Determine whether we want to be separated into our own layer, independent + // of whether this item can actually be layerized. + enum ImageLayerization { + WHENEVER_POSSIBLE, + ONLY_FOR_SCALING, + NO_LAYER_NEEDED + }; + ImageLayerization ShouldCreateOwnLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager); + + // Cache the result of nsCSSRendering::FindBackground. Always null if + // mIsThemed is true or if FindBackground returned false. + const nsStyleBackground* mBackgroundStyle; + nsCOMPtr<imgIContainer> mImage; + nsRect mBackgroundRect; // relative to the reference frame + nsRect mFillRect; + nsRect mDestRect; + /* Bounds of this display item */ + nsRect mBounds; + uint32_t mLayer; + bool mIsRasterImage; + /* Whether the image should be treated as fixed to the viewport. */ + bool mShouldTreatAsFixed; +}; + + +/** + * A display item to paint the native theme background for a frame. + */ +class nsDisplayThemedBackground : public nsDisplayItem { +public: + nsDisplayThemedBackground(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + const nsRect& aBackgroundRect); + virtual ~nsDisplayThemedBackground(); + + virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, + HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) override; + virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, + bool* aSnap) override; + virtual mozilla::Maybe<nscolor> IsUniform(nsDisplayListBuilder* aBuilder) override; + virtual bool ProvidesFontSmoothingBackgroundColor(nscolor* aColor) override; + + /** + * GetBounds() returns the background painting area. + */ + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override; + virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override; + NS_DISPLAY_DECL_NAME("ThemedBackground", TYPE_THEMED_BACKGROUND) + + /** + * Return the background positioning area. + * (GetBounds() returns the background painting area.) + * Can be called only when mBackgroundStyle is non-null. + */ + nsRect GetPositioningArea(); + + /** + * Return whether our frame's document does not have the state + * NS_DOCUMENT_STATE_WINDOW_INACTIVE. + */ + bool IsWindowActive(); + + virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override + { + return new nsDisplayThemedBackgroundGeometry(this, aBuilder); + } + + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, + const nsDisplayItemGeometry* aGeometry, + nsRegion* aInvalidRegion) override; + + virtual void WriteDebugInfo(std::stringstream& aStream) override; +protected: + nsRect GetBoundsInternal(); + + void PaintInternal(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx, + const nsRect& aBounds, nsRect* aClipRect); + + nsRect mBackgroundRect; + nsRect mBounds; + nsITheme::Transparency mThemeTransparency; + uint8_t mAppearance; +}; + +class nsDisplayBackgroundColor : public nsDisplayItem +{ + typedef mozilla::gfx::Color Color; + +public: + nsDisplayBackgroundColor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + const nsRect& aBackgroundRect, + const nsStyleBackground* aBackgroundStyle, + nscolor aColor) + : nsDisplayItem(aBuilder, aFrame) + , mBackgroundRect(aBackgroundRect) + , mBackgroundStyle(aBackgroundStyle) + , mColor(Color::FromABGR(aColor)) + { } + + virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override; + + virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, + bool* aSnap) override; + virtual mozilla::Maybe<nscolor> IsUniform(nsDisplayListBuilder* aBuilder) override; + virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, + HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) override; + + virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder, + float aOpacity, + const DisplayItemClip* aClip) override; + virtual bool CanApplyOpacity() const override; + + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override + { + *aSnap = true; + return mBackgroundRect; + } + + virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override + { + return new nsDisplaySolidColorGeometry(this, aBuilder, mColor.ToABGR()); + } + + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, + const nsDisplayItemGeometry* aGeometry, + nsRegion* aInvalidRegion) override + { + const nsDisplaySolidColorGeometry* geometry = static_cast<const nsDisplaySolidColorGeometry*>(aGeometry); + if (mColor.ToABGR() != geometry->mColor) { + bool dummy; + aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &dummy)); + return; + } + ComputeInvalidationRegionDifference(aBuilder, geometry, aInvalidRegion); + } + + NS_DISPLAY_DECL_NAME("BackgroundColor", TYPE_BACKGROUND_COLOR) + virtual void WriteDebugInfo(std::stringstream& aStream) override; + +protected: + const nsRect mBackgroundRect; + const nsStyleBackground* mBackgroundStyle; + mozilla::gfx::Color mColor; +}; + +class nsDisplayClearBackground : public nsDisplayItem +{ +public: + nsDisplayClearBackground(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) + : nsDisplayItem(aBuilder, aFrame) + { } + + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override + { + *aSnap = true; + return nsRect(ToReferenceFrame(), Frame()->GetSize()); + } + + virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, + bool* aSnap) override { + *aSnap = false; + return GetBounds(aBuilder, aSnap); + } + + virtual mozilla::Maybe<nscolor> IsUniform(nsDisplayListBuilder* aBuilder) override + { + return mozilla::Some(NS_RGBA(0, 0, 0, 0)); + } + + virtual bool ClearsBackground() override + { + return true; + } + + virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aParameters) override + { + return mozilla::LAYER_ACTIVE_FORCE; + } + + virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aContainerParameters) override; + + NS_DISPLAY_DECL_NAME("ClearBackground", TYPE_CLEAR_BACKGROUND) +}; + +/** + * The standard display item to paint the outer CSS box-shadows of a frame. + */ +class nsDisplayBoxShadowOuter final : public nsDisplayItem { +public: + nsDisplayBoxShadowOuter(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) + : nsDisplayItem(aBuilder, aFrame) + , mOpacity(1.0) { + MOZ_COUNT_CTOR(nsDisplayBoxShadowOuter); + mBounds = GetBoundsInternal(); + } +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayBoxShadowOuter() { + MOZ_COUNT_DTOR(nsDisplayBoxShadowOuter); + } +#endif + + virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override; + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override; + virtual bool IsInvisibleInRect(const nsRect& aRect) override; + virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion) override; + NS_DISPLAY_DECL_NAME("BoxShadowOuter", TYPE_BOX_SHADOW_OUTER) + + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, + const nsDisplayItemGeometry* aGeometry, + nsRegion* aInvalidRegion) override; + + virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder, + float aOpacity, + const DisplayItemClip* aClip) override + { + NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed"); + mOpacity = aOpacity; + if (aClip) { + IntersectClip(aBuilder, *aClip); + } + } + virtual bool CanApplyOpacity() const override + { + return true; + } + + virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override + { + return new nsDisplayBoxShadowOuterGeometry(this, aBuilder, mOpacity); + } + + nsRect GetBoundsInternal(); + +private: + nsRegion mVisibleRegion; + nsRect mBounds; + float mOpacity; +}; + +/** + * The standard display item to paint the inner CSS box-shadows of a frame. + */ +class nsDisplayBoxShadowInner : public nsDisplayItem { +public: + nsDisplayBoxShadowInner(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) + : nsDisplayItem(aBuilder, aFrame) { + MOZ_COUNT_CTOR(nsDisplayBoxShadowInner); + } +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayBoxShadowInner() { + MOZ_COUNT_DTOR(nsDisplayBoxShadowInner); + } +#endif + + virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override; + virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion) override; + NS_DISPLAY_DECL_NAME("BoxShadowInner", TYPE_BOX_SHADOW_INNER) + + virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override + { + return new nsDisplayBoxShadowInnerGeometry(this, aBuilder); + } + + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, + const nsDisplayItemGeometry* aGeometry, + nsRegion* aInvalidRegion) override + { + const nsDisplayBoxShadowInnerGeometry* geometry = static_cast<const nsDisplayBoxShadowInnerGeometry*>(aGeometry); + if (!geometry->mPaddingRect.IsEqualInterior(GetPaddingRect())) { + // nsDisplayBoxShadowInner is based around the padding rect, but it can + // touch pixels outside of this. We should invalidate the entire bounds. + bool snap; + aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &snap)); + } + } + +private: + nsRegion mVisibleRegion; +}; + +/** + * The standard display item to paint the CSS outline of a frame. + */ +class nsDisplayOutline : public nsDisplayItem { +public: + nsDisplayOutline(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) : + nsDisplayItem(aBuilder, aFrame) { + MOZ_COUNT_CTOR(nsDisplayOutline); + } +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayOutline() { + MOZ_COUNT_DTOR(nsDisplayOutline); + } +#endif + + virtual bool IsInvisibleInRect(const nsRect& aRect) override; + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override; + virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override; + NS_DISPLAY_DECL_NAME("Outline", TYPE_OUTLINE) +}; + +/** + * A class that lets you receive events within the frame bounds but never paints. + */ +class nsDisplayEventReceiver : public nsDisplayItem { +public: + nsDisplayEventReceiver(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) + : nsDisplayItem(aBuilder, aFrame) { + MOZ_COUNT_CTOR(nsDisplayEventReceiver); + } +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayEventReceiver() { + MOZ_COUNT_DTOR(nsDisplayEventReceiver); + } +#endif + + virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, + HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) override; + NS_DISPLAY_DECL_NAME("EventReceiver", TYPE_EVENT_RECEIVER) +}; + +/** + * A display item that tracks event-sensitive regions which will be set + * on the ContainerLayer that eventually contains this item. + * + * One of these is created for each stacking context and pseudo-stacking-context. + * It accumulates regions for event targets contributed by the border-boxes of + * frames in its (pseudo) stacking context. A nsDisplayLayerEventRegions + * eventually contributes its regions to the PaintedLayer it is placed in by + * FrameLayerBuilder. (We don't create a display item for every frame that + * could be an event target (i.e. almost all frames), because that would be + * high overhead.) + * + * We always make leaf layers other than PaintedLayers transparent to events. + * For example, an event targeting a canvas or video will actually target the + * background of that element, which is logically in the PaintedLayer behind the + * CanvasFrame or ImageFrame. We only need to create a + * nsDisplayLayerEventRegions when an element's background could be in front + * of a lower z-order element with its own layer. + */ +class nsDisplayLayerEventRegions final : public nsDisplayItem { +public: + nsDisplayLayerEventRegions(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) + : nsDisplayItem(aBuilder, aFrame) + { + MOZ_COUNT_CTOR(nsDisplayLayerEventRegions); + } +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayLayerEventRegions() { + MOZ_COUNT_DTOR(nsDisplayLayerEventRegions); + } +#endif + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override + { + *aSnap = false; + return nsRect(); + } + nsRect GetHitRegionBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) + { + *aSnap = false; + return mHitRegion.GetBounds().Union(mMaybeHitRegion.GetBounds()); + } + + virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder, + float aOpacity, + const DisplayItemClip* aClip) override + { + NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed"); + } + virtual bool CanApplyOpacity() const override + { + return true; + } + + NS_DISPLAY_DECL_NAME("LayerEventRegions", TYPE_LAYER_EVENT_REGIONS) + + // Indicate that aFrame's border-box contributes to the event regions for + // this layer. aFrame must have the same reference frame as mFrame. + void AddFrame(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame); + + // Indicate that an inactive scrollframe's scrollport should be added to the + // dispatch-to-content region, to ensure that APZ lets content create a + // displayport. + void AddInactiveScrollPort(const nsRect& aRect); + + bool IsEmpty() const; + + int32_t ZIndex() const override; + void SetOverrideZIndex(int32_t aZIndex); + + const nsRegion& HitRegion() { return mHitRegion; } + const nsRegion& MaybeHitRegion() { return mMaybeHitRegion; } + const nsRegion& DispatchToContentHitRegion() { return mDispatchToContentHitRegion; } + const nsRegion& NoActionRegion() { return mNoActionRegion; } + const nsRegion& HorizontalPanRegion() { return mHorizontalPanRegion; } + const nsRegion& VerticalPanRegion() { return mVerticalPanRegion; } + nsRegion CombinedTouchActionRegion(); + + virtual void WriteDebugInfo(std::stringstream& aStream) override; + +private: + // Relative to aFrame's reference frame. + // These are the points that are definitely in the hit region. + nsRegion mHitRegion; + // These are points that may or may not be in the hit region. Only main-thread + // event handling can tell for sure (e.g. because complex shapes are present). + nsRegion mMaybeHitRegion; + // These are points that need to be dispatched to the content thread for + // resolution. Always contained in the union of mHitRegion and mMaybeHitRegion. + nsRegion mDispatchToContentHitRegion; + // These are points where panning is disabled, as determined by the touch-action + // property. Always contained in the union of mHitRegion and mMaybeHitRegion. + nsRegion mNoActionRegion; + // These are points where panning is horizontal, as determined by the touch-action + // property. Always contained in the union of mHitRegion and mMaybeHitRegion. + nsRegion mHorizontalPanRegion; + // These are points where panning is vertical, as determined by the touch-action + // property. Always contained in the union of mHitRegion and mMaybeHitRegion. + nsRegion mVerticalPanRegion; + // If these event regions are for an inactive scroll frame, the z-index of + // this display item is overridden to be the largest z-index of the content + // in the scroll frame. This ensures that the event regions item remains on + // top of the content after sorting items by z-index. + mozilla::Maybe<int32_t> mOverrideZIndex; +}; + +/** + * A class that lets you wrap a display list as a display item. + * + * GetUnderlyingFrame() is troublesome for wrapped lists because if the wrapped + * list has many items, it's not clear which one has the 'underlying frame'. + * Thus we force the creator to specify what the underlying frame is. The + * underlying frame should be the root of a stacking context, because sorting + * a list containing this item will not get at the children. + * + * In some cases (e.g., clipping) we want to wrap a list but we don't have a + * particular underlying frame that is a stacking context root. In that case + * we allow the frame to be nullptr. Callers to GetUnderlyingFrame must + * detect and handle this case. + */ +class nsDisplayWrapList : public nsDisplayItem { +public: + /** + * Takes all the items from aList and puts them in our list. + */ + nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayList* aList); + nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayList* aList, + const DisplayItemScrollClip* aScrollClip); + nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayItem* aItem); + nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) + : nsDisplayItem(aBuilder, aFrame), mOverrideZIndex(0), mHasZIndexOverride(false) + { + MOZ_COUNT_CTOR(nsDisplayWrapList); + mBaseVisibleRect = mVisibleRect; + } + virtual ~nsDisplayWrapList(); + /** + * Call this if the wrapped list is changed. + */ + virtual void UpdateBounds(nsDisplayListBuilder* aBuilder) override + { + mBounds = mList.GetScrollClippedBoundsUpTo(aBuilder, mScrollClip); + // The display list may contain content that's visible outside the visible + // rect (i.e. the current dirty rect) passed in when the item was created. + // This happens when the dirty rect has been restricted to the visual + // overflow rect of a frame for some reason (e.g. when setting up dirty + // rects in nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay), but that + // frame contains placeholders for out-of-flows that aren't descendants of + // the frame. + mVisibleRect.UnionRect(mBaseVisibleRect, mList.GetVisibleRect()); + } + virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, + HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) override; + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override; + virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, + bool* aSnap) override; + virtual mozilla::Maybe<nscolor> IsUniform(nsDisplayListBuilder* aBuilder) override; + virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override; + virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion) override; + virtual bool TryMerge(nsDisplayItem* aItem) override { + return false; + } + virtual void GetMergedFrames(nsTArray<nsIFrame*>* aFrames) override + { + aFrames->AppendElements(mMergedFrames); + } + virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override { + return true; + } + virtual bool IsInvalid(nsRect& aRect) override + { + if (mFrame->IsInvalid(aRect) && aRect.IsEmpty()) { + return true; + } + nsRect temp; + for (uint32_t i = 0; i < mMergedFrames.Length(); i++) { + if (mMergedFrames[i]->IsInvalid(temp) && temp.IsEmpty()) { + aRect.SetEmpty(); + return true; + } + aRect = aRect.Union(temp); + } + aRect += ToReferenceFrame(); + return !aRect.IsEmpty(); + } + NS_DISPLAY_DECL_NAME("WrapList", TYPE_WRAP_LIST) + + virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) override; + + virtual nsDisplayList* GetSameCoordinateSystemChildren() override + { + NS_ASSERTION(mList.IsEmpty() || !ReferenceFrame() || + !mList.GetBottom()->ReferenceFrame() || + mList.GetBottom()->ReferenceFrame() == ReferenceFrame(), + "Children must have same reference frame"); + return &mList; + } + virtual nsDisplayList* GetChildren() override { return &mList; } + + virtual int32_t ZIndex() const override + { + return (mHasZIndexOverride) ? mOverrideZIndex : nsDisplayItem::ZIndex(); + } + + void SetOverrideZIndex(int32_t aZIndex) + { + mHasZIndexOverride = true; + mOverrideZIndex = aZIndex; + } + + void SetVisibleRect(const nsRect& aRect); + + void SetReferenceFrame(const nsIFrame* aFrame); + + /** + * This creates a copy of this item, but wrapping aItem instead of + * our existing list. Only gets called if this item returned nullptr + * for GetUnderlyingFrame(). aItem is guaranteed to return non-null from + * GetUnderlyingFrame(). + */ + virtual nsDisplayWrapList* WrapWithClone(nsDisplayListBuilder* aBuilder, + nsDisplayItem* aItem) { + NS_NOTREACHED("We never returned nullptr for GetUnderlyingFrame!"); + return nullptr; + } + +protected: + nsDisplayWrapList() {} + + void MergeFromTrackingMergedFrames(nsDisplayWrapList* aOther) + { + mList.AppendToBottom(&aOther->mList); + mBounds.UnionRect(mBounds, aOther->mBounds); + mVisibleRect.UnionRect(mVisibleRect, aOther->mVisibleRect); + mMergedFrames.AppendElement(aOther->mFrame); + mMergedFrames.AppendElements(mozilla::Move(aOther->mMergedFrames)); + } + + nsDisplayList mList; + // The frames from items that have been merged into this item, excluding + // this item's own frame. + nsTArray<nsIFrame*> mMergedFrames; + nsRect mBounds; + // Visible rect contributed by this display item itself. + // Our mVisibleRect may include the visible areas of children. + nsRect mBaseVisibleRect; + int32_t mOverrideZIndex; + bool mHasZIndexOverride; +}; + +/** + * We call WrapDisplayList on the in-flow lists: BorderBackground(), + * BlockBorderBackgrounds() and Content(). + * We call WrapDisplayItem on each item of Outlines(), PositionedDescendants(), + * and Floats(). This is done to support special wrapping processing for frames + * that may not be in-flow descendants of the current frame. + */ +class nsDisplayWrapper { +public: + // This is never instantiated directly (it has pure virtual methods), so no + // need to count constructors and destructors. + + virtual bool WrapBorderBackground() { return true; } + virtual nsDisplayItem* WrapList(nsDisplayListBuilder* aBuilder, + nsIFrame* aFrame, nsDisplayList* aList) = 0; + virtual nsDisplayItem* WrapItem(nsDisplayListBuilder* aBuilder, + nsDisplayItem* aItem) = 0; + + nsresult WrapLists(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + const nsDisplayListSet& aIn, const nsDisplayListSet& aOut); + nsresult WrapListsInPlace(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + const nsDisplayListSet& aLists); +protected: + nsDisplayWrapper() {} +}; + +/** + * The standard display item to paint a stacking context with translucency + * set by the stacking context root frame's 'opacity' style. + */ +class nsDisplayOpacity : public nsDisplayWrapList { +public: + nsDisplayOpacity(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayList* aList, + const DisplayItemScrollClip* aScrollClip, + bool aForEventsAndPluginsOnly); +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayOpacity(); +#endif + + virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, + bool* aSnap) override; + virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aContainerParameters) override; + virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aParameters) override; + virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion) override; + virtual bool TryMerge(nsDisplayItem* aItem) override; + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, + const nsDisplayItemGeometry* aGeometry, + nsRegion* aInvalidRegion) override + { + // We don't need to compute an invalidation region since we have LayerTreeInvalidation + } + virtual bool IsInvalid(nsRect& aRect) override + { + if (mForEventsAndPluginsOnly) { + return false; + } + return nsDisplayWrapList::IsInvalid(aRect); + } + virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder, + float aOpacity, + const DisplayItemClip* aClip) override; + virtual bool CanApplyOpacity() const override; + virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override; + static bool NeedsActiveLayer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame); + NS_DISPLAY_DECL_NAME("Opacity", TYPE_OPACITY) + virtual void WriteDebugInfo(std::stringstream& aStream) override; + + bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) override; + +private: + float mOpacity; + bool mForEventsAndPluginsOnly; +}; + +class nsDisplayBlendMode : public nsDisplayWrapList { +public: + nsDisplayBlendMode(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayList* aList, uint8_t aBlendMode, + const DisplayItemScrollClip* aScrollClip, + uint32_t aIndex = 0); +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayBlendMode(); +#endif + + nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, + bool* aSnap) override; + + virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aContainerParameters) override; + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, + const nsDisplayItemGeometry* aGeometry, + nsRegion* aInvalidRegion) override + { + // We don't need to compute an invalidation region since we have LayerTreeInvalidation + } + virtual uint32_t GetPerFrameKey() override { + return (mIndex << nsDisplayItem::TYPE_BITS) | + nsDisplayItem::GetPerFrameKey(); + } + virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aParameters) override; + virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion) override; + virtual bool TryMerge(nsDisplayItem* aItem) override; + virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override { + return false; + } + NS_DISPLAY_DECL_NAME("BlendMode", TYPE_BLEND_MODE) + +private: + uint8_t mBlendMode; + uint32_t mIndex; +}; + +class nsDisplayBlendContainer : public nsDisplayWrapList { +public: + static nsDisplayBlendContainer* + CreateForMixBlendMode(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayList* aList, const DisplayItemScrollClip* aScrollClip); + + static nsDisplayBlendContainer* + CreateForBackgroundBlendMode(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayList* aList, const DisplayItemScrollClip* aScrollClip); + +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayBlendContainer(); +#endif + + virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aContainerParameters) override; + virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aParameters) override; + virtual bool TryMerge(nsDisplayItem* aItem) override; + virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override { + return false; + } + virtual uint32_t GetPerFrameKey() override { + return (mIsForBackground ? 1 << nsDisplayItem::TYPE_BITS : 0) | + nsDisplayItem::GetPerFrameKey(); + } + NS_DISPLAY_DECL_NAME("BlendContainer", TYPE_BLEND_CONTAINER) + +private: + nsDisplayBlendContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayList* aList, + const DisplayItemScrollClip* aScrollClip, + bool aIsForBackground); + + // Used to distinguish containers created at building stacking + // context or appending background. + bool mIsForBackground; +}; + +/** + * A display item that has no purpose but to ensure its contents get + * their own layer. + */ +class nsDisplayOwnLayer : public nsDisplayWrapList { +public: + + /** + * nsDisplayOwnLayer constructor flags + */ + enum { + GENERATE_SUBDOC_INVALIDATIONS = 0x01, + VERTICAL_SCROLLBAR = 0x02, + HORIZONTAL_SCROLLBAR = 0x04, + GENERATE_SCROLLABLE_LAYER = 0x08, + SCROLLBAR_CONTAINER = 0x10 + }; + + /** + * @param aFlags GENERATE_SUBDOC_INVALIDATIONS : + * Add UserData to the created ContainerLayer, so that invalidations + * for this layer are send to our nsPresContext. + * GENERATE_SCROLLABLE_LAYER : only valid on nsDisplaySubDocument (and + * subclasses), indicates this layer is to be a scrollable layer, so call + * ComputeFrameMetrics, etc. + * @param aScrollTarget when VERTICAL_SCROLLBAR or HORIZONTAL_SCROLLBAR + * is set in the flags, this parameter should be the ViewID of the + * scrollable content this scrollbar is for. + */ + nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayList* aList, uint32_t aFlags = 0, + ViewID aScrollTarget = mozilla::layers::FrameMetrics::NULL_SCROLL_ID, + float aScrollbarThumbRatio = 0.0f, + bool aForceActive = true); +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayOwnLayer(); +#endif + + virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aContainerParameters) override; + virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aParameters) override; + virtual bool TryMerge(nsDisplayItem* aItem) override + { + // Don't allow merging, each sublist must have its own layer + return false; + } + virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override { + return false; + } + uint32_t GetFlags() { return mFlags; } + NS_DISPLAY_DECL_NAME("OwnLayer", TYPE_OWN_LAYER) +protected: + uint32_t mFlags; + ViewID mScrollTarget; + float mScrollbarThumbRatio; + bool mForceActive; +}; + +/** + * A display item for subdocuments. This is more or less the same as nsDisplayOwnLayer, + * except that it always populates the FrameMetrics instance on the ContainerLayer it + * builds. + */ +class nsDisplaySubDocument : public nsDisplayOwnLayer { +public: + nsDisplaySubDocument(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayList* aList, uint32_t aFlags); +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplaySubDocument(); +#endif + + virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aContainerParameters) override; + + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override; + + virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion) override; + + virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) override; + + virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, bool* aSnap) override; + + NS_DISPLAY_DECL_NAME("SubDocument", TYPE_SUBDOCUMENT) + + mozilla::UniquePtr<ScrollMetadata> ComputeScrollMetadata(Layer* aLayer, + const ContainerLayerParameters& aContainerParameters); + +protected: + ViewID mScrollParentId; + bool mForceDispatchToContentRegion; +}; + +/** + * A display item for subdocuments to capture the resolution from the presShell + * and ensure that it gets applied to all the right elements. This item creates + * a container layer. + */ +class nsDisplayResolution : public nsDisplaySubDocument { +public: + nsDisplayResolution(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayList* aList, uint32_t aFlags); +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayResolution(); +#endif + virtual void HitTest(nsDisplayListBuilder* aBuilder, + const nsRect& aRect, + HitTestState* aState, + nsTArray<nsIFrame*> *aOutFrames) override; + virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aContainerParameters) override; + NS_DISPLAY_DECL_NAME("Resolution", TYPE_RESOLUTION) +}; + +/** + * A display item used to represent sticky position elements. The contents + * gets its own layer and creates a stacking context, and the layer will have + * position-related metadata set on it. + */ +class nsDisplayStickyPosition : public nsDisplayOwnLayer { +public: + nsDisplayStickyPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayList* aList); +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayStickyPosition(); +#endif + + virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aContainerParameters) override; + NS_DISPLAY_DECL_NAME("StickyPosition", TYPE_STICKY_POSITION) + virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aParameters) override + { + return mozilla::LAYER_ACTIVE; + } + virtual bool TryMerge(nsDisplayItem* aItem) override; +}; + +class nsDisplayFixedPosition : public nsDisplayOwnLayer { +public: + nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayList* aList); + + static nsDisplayFixedPosition* CreateForFixedBackground(nsDisplayListBuilder* aBuilder, + nsIFrame* aFrame, + nsDisplayBackgroundImage* aImage, + uint32_t aIndex); + + +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayFixedPosition(); +#endif + + virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aContainerParameters) override; + NS_DISPLAY_DECL_NAME("FixedPosition", TYPE_FIXED_POSITION) + virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aParameters) override + { + return mozilla::LAYER_ACTIVE; + } + virtual bool TryMerge(nsDisplayItem* aItem) override; + + virtual bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder) override { return mIsFixedBackground; } + + virtual uint32_t GetPerFrameKey() override { return (mIndex << nsDisplayItem::TYPE_BITS) | nsDisplayItem::GetPerFrameKey(); } + + AnimatedGeometryRoot* AnimatedGeometryRootForScrollMetadata() const override { + return mAnimatedGeometryRootForScrollMetadata; + } + +private: + // For background-attachment:fixed + nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayList* aList, uint32_t aIndex); + void Init(nsDisplayListBuilder* aBuilder); + + AnimatedGeometryRoot* mAnimatedGeometryRootForScrollMetadata; + uint32_t mIndex; + bool mIsFixedBackground; +}; + +/** + * This creates an empty scrollable layer. It has no child layers. + * It is used to record the existence of a scrollable frame in the layer + * tree. + */ +class nsDisplayScrollInfoLayer : public nsDisplayWrapList +{ +public: + nsDisplayScrollInfoLayer(nsDisplayListBuilder* aBuilder, + nsIFrame* aScrolledFrame, nsIFrame* aScrollFrame); + NS_DISPLAY_DECL_NAME("ScrollInfoLayer", TYPE_SCROLL_INFO_LAYER) + + +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayScrollInfoLayer(); +#endif + + virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aContainerParameters) override; + + virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) override + { return true; } + + virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, + bool* aSnap) override { + *aSnap = false; + return nsRegion(); + } + + virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aParameters) override; + + virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override + { return false; } + + virtual void WriteDebugInfo(std::stringstream& aStream) override; + + mozilla::UniquePtr<ScrollMetadata> ComputeScrollMetadata(Layer* aLayer, + const ContainerLayerParameters& aContainerParameters); + +protected: + nsIFrame* mScrollFrame; + nsIFrame* mScrolledFrame; + ViewID mScrollParentId; +}; + +/** + * nsDisplayZoom is used for subdocuments that have a different full zoom than + * their parent documents. This item creates a container layer. + */ +class nsDisplayZoom : public nsDisplaySubDocument { +public: + /** + * @param aFrame is the root frame of the subdocument. + * @param aList contains the display items for the subdocument. + * @param aAPD is the app units per dev pixel ratio of the subdocument. + * @param aParentAPD is the app units per dev pixel ratio of the parent + * document. + * @param aFlags GENERATE_SUBDOC_INVALIDATIONS : + * Add UserData to the created ContainerLayer, so that invalidations + * for this layer are send to our nsPresContext. + */ + nsDisplayZoom(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayList* aList, + int32_t aAPD, int32_t aParentAPD, + uint32_t aFlags = 0); +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayZoom(); +#endif + + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override; + virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, + HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) override; + virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion) override; + virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aParameters) override + { + return mozilla::LAYER_ACTIVE; + } + NS_DISPLAY_DECL_NAME("Zoom", TYPE_ZOOM) + + // Get the app units per dev pixel ratio of the child document. + int32_t GetChildAppUnitsPerDevPixel() { return mAPD; } + // Get the app units per dev pixel ratio of the parent document. + int32_t GetParentAppUnitsPerDevPixel() { return mParentAPD; } + +private: + int32_t mAPD, mParentAPD; +}; + +class nsDisplaySVGEffects: public nsDisplayWrapList { +public: + nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayList* aList, bool aHandleOpacity, + const DisplayItemScrollClip* aScrollClip); + nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayList* aList, bool aHandleOpacity); +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplaySVGEffects(); +#endif + + virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, + bool* aSnap) override; + virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, + HitTestState* aState, + nsTArray<nsIFrame*> *aOutFrames) override; + + virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override { + return false; + } + + gfxRect BBoxInUserSpace() const; + gfxPoint UserSpaceOffset() const; + + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, + const nsDisplayItemGeometry* aGeometry, + nsRegion* aInvalidRegion) override; +protected: + bool ValidateSVGFrame(); + + // relative to mFrame + nsRect mEffectsBounds; + // True if we need to handle css opacity in this display item. + bool mHandleOpacity; +}; + +/** + * A display item to paint a stacking context with mask and clip effects + * set by the stacking context root frame's style. + */ +class nsDisplayMask : public nsDisplaySVGEffects { +public: + typedef mozilla::layers::ImageLayer ImageLayer; + typedef class mozilla::gfx::DrawTarget DrawTarget; + + nsDisplayMask(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayList* aList, bool aHandleOpacity, + const DisplayItemScrollClip* aScrollClip); +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayMask(); +#endif + + NS_DISPLAY_DECL_NAME("Mask", TYPE_MASK) + + virtual bool TryMerge(nsDisplayItem* aItem) override; + virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aContainerParameters) override; + virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aParameters) override; + + virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion) override; + + virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override + { + return new nsDisplayMaskGeometry(this, aBuilder); + } + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, + const nsDisplayItemGeometry* aGeometry, + nsRegion* aInvalidRegion) override; +#ifdef MOZ_DUMP_PAINTING + void PrintEffects(nsACString& aTo); +#endif + + void PaintAsLayer(nsDisplayListBuilder* aBuilder, + nsRenderingContext* aCtx, + LayerManager* aManager); + + /* + * Paint mask onto aMaskContext in mFrame's coordinate space. + */ + bool PaintMask(nsDisplayListBuilder* aBuilder, gfxContext* aMaskContext); + + const nsTArray<nsRect>& GetDestRects() + { + return mDestRects; + } +private: + // According to mask property and the capability of aManager, determine + // whether paint mask onto a dedicate mask layer. + bool ShouldPaintOnMaskLayer(LayerManager* aManager); + + nsTArray<nsRect> mDestRects; +}; + +/** + * A display item to paint a stacking context with filter effects set by the + * stacking context root frame's style. + */ +class nsDisplayFilter : public nsDisplaySVGEffects { +public: + nsDisplayFilter(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayList* aList, bool aHandleOpacity); +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayFilter(); +#endif + + NS_DISPLAY_DECL_NAME("Filter", TYPE_FILTER) + + virtual bool TryMerge(nsDisplayItem* aItem) override; + virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aContainerParameters) override; + virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aParameters) override; + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, + bool* aSnap) override { + *aSnap = false; + return mEffectsBounds + ToReferenceFrame(); + } + virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion) override; + virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override + { + return new nsDisplayFilterGeometry(this, aBuilder); + } + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, + const nsDisplayItemGeometry* aGeometry, + nsRegion* aInvalidRegion) override; +#ifdef MOZ_DUMP_PAINTING + void PrintEffects(nsACString& aTo); +#endif + + void PaintAsLayer(nsDisplayListBuilder* aBuilder, + nsRenderingContext* aCtx, + LayerManager* aManager); +}; + +/* A display item that applies a transformation to all of its descendant + * elements. This wrapper should only be used if there is a transform applied + * to the root element. + * + * The reason that a "bounds" rect is involved in transform calculations is + * because CSS-transforms allow percentage values for the x and y components + * of <translation-value>s, where percentages are percentages of the element's + * border box. + * + * INVARIANT: The wrapped frame is transformed or we supplied a transform getter + * function. + * INVARIANT: The wrapped frame is non-null. + */ +class nsDisplayTransform: public nsDisplayItem +{ + typedef mozilla::gfx::Matrix4x4 Matrix4x4; + typedef mozilla::gfx::Point3D Point3D; + + /* + * Avoid doing UpdateBounds() during construction. + */ + class StoreList : public nsDisplayWrapList { + public: + StoreList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayList* aList) : + nsDisplayWrapList(aBuilder, aFrame, aList) {} + StoreList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayItem* aItem) : + nsDisplayWrapList(aBuilder, aFrame, aItem) {} + virtual ~StoreList() {} + + virtual void UpdateBounds(nsDisplayListBuilder* aBuilder) override { + // For extending 3d rendering context, the bounds would be + // updated by DoUpdateBoundsPreserves3D(), not here. + if (!mFrame->Extend3DContext()) { + nsDisplayWrapList::UpdateBounds(aBuilder); + } + } + virtual void DoUpdateBoundsPreserves3D(nsDisplayListBuilder* aBuilder) override { + for (nsDisplayItem *i = mList.GetBottom(); i; i = i->GetAbove()) { + i->DoUpdateBoundsPreserves3D(aBuilder); + } + nsDisplayWrapList::UpdateBounds(aBuilder); + } + }; + +public: + /** + * Returns a matrix (in pixels) for the current frame. The matrix should be relative to + * the current frame's coordinate space. + * + * @param aFrame The frame to compute the transform for. + * @param aAppUnitsPerPixel The number of app units per graphics unit. + */ + typedef Matrix4x4 (* ComputeTransformFunction)(nsIFrame* aFrame, float aAppUnitsPerPixel); + + /* Constructor accepts a display list, empties it, and wraps it up. It also + * ferries the underlying frame to the nsDisplayItem constructor. + */ + nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame, + nsDisplayList *aList, const nsRect& aChildrenVisibleRect, + uint32_t aIndex = 0, bool aIsFullyVisible = false); + nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame, + nsDisplayItem *aItem, const nsRect& aChildrenVisibleRect, + uint32_t aIndex = 0); + nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame, + nsDisplayList *aList, const nsRect& aChildrenVisibleRect, + ComputeTransformFunction aTransformGetter, uint32_t aIndex = 0); + nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame, + nsDisplayList *aList, const nsRect& aChildrenVisibleRect, + const Matrix4x4& aTransform, uint32_t aIndex = 0); + +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayTransform() + { + MOZ_COUNT_DTOR(nsDisplayTransform); + } +#endif + + NS_DISPLAY_DECL_NAME("nsDisplayTransform", TYPE_TRANSFORM) + + virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) override + { + if (mStoredList.GetComponentAlphaBounds(aBuilder).IsEmpty()) + return nsRect(); + bool snap; + return GetBounds(aBuilder, &snap); + } + + virtual nsDisplayList* GetChildren() override { return mStoredList.GetChildren(); } + + virtual void HitTest(nsDisplayListBuilder *aBuilder, const nsRect& aRect, + HitTestState *aState, nsTArray<nsIFrame*> *aOutFrames) override; + virtual nsRect GetBounds(nsDisplayListBuilder *aBuilder, bool* aSnap) override; + virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder *aBuilder, + bool* aSnap) override; + virtual mozilla::Maybe<nscolor> IsUniform(nsDisplayListBuilder *aBuilder) override; + virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aParameters) override; + virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aContainerParameters) override; + virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) override; + virtual bool ComputeVisibility(nsDisplayListBuilder *aBuilder, + nsRegion *aVisibleRegion) override; + virtual bool TryMerge(nsDisplayItem *aItem) override; + + virtual uint32_t GetPerFrameKey() override { return (mIndex << nsDisplayItem::TYPE_BITS) | nsDisplayItem::GetPerFrameKey(); } + + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, + const nsDisplayItemGeometry* aGeometry, + nsRegion* aInvalidRegion) override + { + // We don't need to compute an invalidation region since we have LayerTreeInvalidation + } + + virtual const nsIFrame* ReferenceFrameForChildren() const override { + // If we were created using a transform-getter, then we don't + // belong to a transformed frame, and aren't a reference frame + // for our children. + if (!mTransformGetter) { + return mFrame; + } + return nsDisplayItem::ReferenceFrameForChildren(); + } + + AnimatedGeometryRoot* AnimatedGeometryRootForScrollMetadata() const override { + return mAnimatedGeometryRootForScrollMetadata; + } + + virtual const nsRect& GetVisibleRectForChildren() const override + { + return mChildrenVisibleRect; + } + + enum { + INDEX_MAX = UINT32_MAX >> nsDisplayItem::TYPE_BITS + }; + + /** + * We include the perspective matrix from our containing block for the + * purposes of visibility calculations, but we exclude it from the transform + * we set on the layer (for rendering), since there will be an + * nsDisplayPerspective created for that. + */ + const Matrix4x4& GetTransform(); + Matrix4x4 GetTransformForRendering(); + + /** + * Return the transform that is aggregation of all transform on the + * preserves3d chain. + */ + const Matrix4x4& GetAccumulatedPreserved3DTransform(nsDisplayListBuilder* aBuilder); + + float GetHitDepthAtPoint(nsDisplayListBuilder* aBuilder, const nsPoint& aPoint); + + /** + * TransformRect takes in as parameters a rectangle (in aFrame's coordinate + * space) and returns the smallest rectangle (in aFrame's coordinate space) + * containing the transformed image of that rectangle. That is, it takes + * the four corners of the rectangle, transforms them according to the + * matrix associated with the specified frame, then returns the smallest + * rectangle containing the four transformed points. + * + * @param untransformedBounds The rectangle (in app units) to transform. + * @param aFrame The frame whose transformation should be applied. This + * function raises an assertion if aFrame is null or doesn't have a + * transform applied to it. + * @param aOrigin The origin of the transform relative to aFrame's local + * coordinate space. + * @param aBoundsOverride (optional) Rather than using the frame's computed + * bounding rect as frame bounds, use this rectangle instead. Pass + * nullptr (or nothing at all) to use the default. + */ + static nsRect TransformRect(const nsRect &aUntransformedBounds, + const nsIFrame* aFrame, + const nsRect* aBoundsOverride = nullptr); + + /* UntransformRect is like TransformRect, except that it inverts the + * transform. + */ + static bool UntransformRect(const nsRect &aTransformedBounds, + const nsRect &aChildBounds, + const nsIFrame* aFrame, + nsRect *aOutRect); + + bool UntransformVisibleRect(nsDisplayListBuilder* aBuilder, + nsRect* aOutRect); + + static Point3D GetDeltaToTransformOrigin(const nsIFrame* aFrame, + float aAppUnitsPerPixel, + const nsRect* aBoundsOverride); + + /* + * Returns true if aFrame has perspective applied from its containing + * block. + * Returns the matrix to append to apply the persective (taking + * perspective-origin into account), relative to aFrames coordinate + * space). + * aOutMatrix is assumed to be the identity matrix, and isn't explicitly + * cleared. + */ + static bool ComputePerspectiveMatrix(const nsIFrame* aFrame, + float aAppUnitsPerPixel, + Matrix4x4& aOutMatrix); + + struct FrameTransformProperties + { + FrameTransformProperties(const nsIFrame* aFrame, + float aAppUnitsPerPixel, + const nsRect* aBoundsOverride); + FrameTransformProperties(nsCSSValueSharedList* aTransformList, + const Point3D& aToTransformOrigin) + : mFrame(nullptr) + , mTransformList(aTransformList) + , mToTransformOrigin(aToTransformOrigin) + {} + + const nsIFrame* mFrame; + RefPtr<nsCSSValueSharedList> mTransformList; + const Point3D mToTransformOrigin; + }; + + /** + * Given a frame with the -moz-transform property or an SVG transform, + * returns the transformation matrix for that frame. + * + * @param aFrame The frame to get the matrix from. + * @param aOrigin Relative to which point this transform should be applied. + * @param aAppUnitsPerPixel The number of app units per graphics unit. + * @param aBoundsOverride [optional] If this is nullptr (the default), the + * computation will use the value of TransformReferenceBox(aFrame). + * Otherwise, it will use the value of aBoundsOverride. This is + * mostly for internal use and in most cases you will not need to + * specify a value. + * @param aFlags OFFSET_BY_ORIGIN The resulting matrix will be translated + * by aOrigin. This translation is applied *before* the CSS transform. + * @param aFlags INCLUDE_PRESERVE3D_ANCESTORS The computed transform will + * include the transform of any ancestors participating in the same + * 3d rendering context. + * @param aFlags INCLUDE_PERSPECTIVE The resulting matrix will include the + * perspective transform from the containing block if applicable. + */ + enum { + OFFSET_BY_ORIGIN = 1 << 0, + INCLUDE_PRESERVE3D_ANCESTORS = 1 << 1, + INCLUDE_PERSPECTIVE = 1 << 2, + }; + static Matrix4x4 GetResultingTransformMatrix(const nsIFrame* aFrame, + const nsPoint& aOrigin, + float aAppUnitsPerPixel, + uint32_t aFlags, + const nsRect* aBoundsOverride = nullptr); + static Matrix4x4 GetResultingTransformMatrix(const FrameTransformProperties& aProperties, + const nsPoint& aOrigin, + float aAppUnitsPerPixel, + uint32_t aFlags, + const nsRect* aBoundsOverride = nullptr); + /** + * Return true when we should try to prerender the entire contents of the + * transformed frame even when it's not completely visible (yet). + */ + static bool ShouldPrerenderTransformedContent(nsDisplayListBuilder* aBuilder, + nsIFrame* aFrame); + bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) override; + + bool MayBeAnimated(nsDisplayListBuilder* aBuilder); + + virtual void WriteDebugInfo(std::stringstream& aStream) override; + + // Force the layer created for this item not to extend 3D context. + // See nsIFrame::BuildDisplayListForStackingContext() + void SetNoExtendContext() { mNoExtendContext = true; } + + virtual void DoUpdateBoundsPreserves3D(nsDisplayListBuilder* aBuilder) override { + MOZ_ASSERT(mFrame->Combines3DTransformWithAncestors() || + IsTransformSeparator()); + // Updating is not going through to child 3D context. + ComputeBounds(aBuilder); + } + + /** + * This function updates bounds for items with a frame establishing + * 3D rendering context. + * + * \see nsDisplayItem::DoUpdateBoundsPreserves3D() + */ + void UpdateBoundsFor3D(nsDisplayListBuilder* aBuilder) { + if (!mFrame->Extend3DContext() || + mFrame->Combines3DTransformWithAncestors() || + IsTransformSeparator()) { + // Not an establisher of a 3D rendering context. + return; + } + // Always start updating from an establisher of a 3D rendering context. + + nsDisplayListBuilder::AutoAccumulateRect accRect(aBuilder); + nsDisplayListBuilder::AutoAccumulateTransform accTransform(aBuilder); + accTransform.StartRoot(); + ComputeBounds(aBuilder); + mBounds = aBuilder->GetAccumulatedRect(); + mHasBounds = true; + } + + /** + * This item is an additional item as the boundary between parent + * and child 3D rendering context. + * \see nsIFrame::BuildDisplayListForStackingContext(). + */ + bool IsTransformSeparator() { return mIsTransformSeparator; } + /** + * This item is the boundary between parent and child 3D rendering + * context. + */ + bool IsLeafOf3DContext() { + return (IsTransformSeparator() || + (!mFrame->Extend3DContext() && + mFrame->Combines3DTransformWithAncestors())); + } + /** + * The backing frame of this item participates a 3D rendering + * context. + */ + bool IsParticipating3DContext() { + return mFrame->Extend3DContext() || + mFrame->Combines3DTransformWithAncestors(); + } + +private: + void ComputeBounds(nsDisplayListBuilder* aBuilder); + void SetReferenceFrameToAncestor(nsDisplayListBuilder* aBuilder); + void Init(nsDisplayListBuilder* aBuilder); + + static Matrix4x4 GetResultingTransformMatrixInternal(const FrameTransformProperties& aProperties, + const nsPoint& aOrigin, + float aAppUnitsPerPixel, + uint32_t aFlags, + const nsRect* aBoundsOverride); + + StoreList mStoredList; + Matrix4x4 mTransform; + // Accumulated transform of ancestors on the preserves-3d chain. + Matrix4x4 mTransformPreserves3D; + ComputeTransformFunction mTransformGetter; + AnimatedGeometryRoot* mAnimatedGeometryRootForChildren; + AnimatedGeometryRoot* mAnimatedGeometryRootForScrollMetadata; + nsRect mChildrenVisibleRect; + uint32_t mIndex; + nsRect mBounds; + // True for mBounds is valid. + bool mHasBounds; + // Be forced not to extend 3D context. Since we don't create a + // transform item, a container layer, for every frames in a + // preserves3d context, the transform items of a child preserves3d + // context may extend the parent context not intented if the root of + // the child preserves3d context doesn't create a transform item. + // With this flags, we force the item not extending 3D context. + bool mNoExtendContext; + // This item is a separator between 3D rendering contexts, and + // mTransform have been presetted by the constructor. + bool mIsTransformSeparator; + // True if mTransformPreserves3D have been initialized. + bool mTransformPreserves3DInited; + // True if the entire untransformed area has been treated as + // visible during display list construction. + bool mIsFullyVisible; +}; + +/* A display item that applies a perspective transformation to a single + * nsDisplayTransform child item. We keep this as a separate item since the + * perspective-origin is relative to an ancestor of the transformed frame, and + * APZ can scroll the child separately. + */ +class nsDisplayPerspective : public nsDisplayItem +{ + typedef mozilla::gfx::Point3D Point3D; + +public: + NS_DISPLAY_DECL_NAME("nsDisplayPerspective", TYPE_PERSPECTIVE) + + nsDisplayPerspective(nsDisplayListBuilder* aBuilder, nsIFrame* aTransformFrame, + nsIFrame* aPerspectiveFrame, + nsDisplayList* aList); + + virtual uint32_t GetPerFrameKey() override { return (mIndex << nsDisplayItem::TYPE_BITS) | nsDisplayItem::GetPerFrameKey(); } + + virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, + HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) override + { + return mList.HitTest(aBuilder, aRect, aState, aOutFrames); + } + + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override + { + return mList.GetBounds(aBuilder, aSnap); + } + + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, + const nsDisplayItemGeometry* aGeometry, + nsRegion* aInvalidRegion) override + {} + + virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, + bool* aSnap) override + { + return mList.GetOpaqueRegion(aBuilder, aSnap); + } + + virtual mozilla::Maybe<nscolor> IsUniform(nsDisplayListBuilder* aBuilder) override + { + return mList.IsUniform(aBuilder); + } + + virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aParameters) override; + + virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) override + { + if (!mList.GetChildren()->GetTop()) { + return false; + } + return mList.GetChildren()->GetTop()->ShouldBuildLayerEvenIfInvisible(aBuilder); + } + + virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aContainerParameters) override; + + virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion) override + { + mList.RecomputeVisibility(aBuilder, aVisibleRegion); + return true; + } + virtual nsDisplayList* GetSameCoordinateSystemChildren() override { return mList.GetChildren(); } + virtual nsDisplayList* GetChildren() override { return mList.GetChildren(); } + virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) override + { + return mList.GetComponentAlphaBounds(aBuilder); + } + + nsIFrame* TransformFrame() { return mTransformFrame; } + + virtual int32_t ZIndex() const override; + + virtual void + DoUpdateBoundsPreserves3D(nsDisplayListBuilder* aBuilder) override { + if (mList.GetChildren()->GetTop()) { + static_cast<nsDisplayTransform*>(mList.GetChildren()->GetTop())->DoUpdateBoundsPreserves3D(aBuilder); + } + } + +private: + nsDisplayWrapList mList; + nsIFrame* mTransformFrame; + uint32_t mIndex; +}; + +/** + * This class adds basic support for limiting the rendering (in the inline axis + * of the writing mode) to the part inside the specified edges. It's a base + * class for the display item classes that do the actual work. + * The two members, mVisIStartEdge and mVisIEndEdge, are relative to the edges + * of the frame's scrollable overflow rectangle and are the amount to suppress + * on each side. + * + * Setting none, both or only one edge is allowed. + * The values must be non-negative. + * The default value for both edges is zero, which means everything is painted. + */ +class nsCharClipDisplayItem : public nsDisplayItem { +public: + nsCharClipDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) + : nsDisplayItem(aBuilder, aFrame), mVisIStartEdge(0), mVisIEndEdge(0) {} + + explicit nsCharClipDisplayItem(nsIFrame* aFrame) + : nsDisplayItem(aFrame) {} + + virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override; + + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, + const nsDisplayItemGeometry* aGeometry, + nsRegion* aInvalidRegion) override; + + struct ClipEdges { + ClipEdges(const nsDisplayItem& aItem, + nscoord aVisIStartEdge, nscoord aVisIEndEdge) { + nsRect r = aItem.Frame()->GetScrollableOverflowRect() + + aItem.ToReferenceFrame(); + if (aItem.Frame()->GetWritingMode().IsVertical()) { + mVisIStart = aVisIStartEdge > 0 ? r.y + aVisIStartEdge : nscoord_MIN; + mVisIEnd = + aVisIEndEdge > 0 ? std::max(r.YMost() - aVisIEndEdge, mVisIStart) + : nscoord_MAX; + } else { + mVisIStart = aVisIStartEdge > 0 ? r.x + aVisIStartEdge : nscoord_MIN; + mVisIEnd = + aVisIEndEdge > 0 ? std::max(r.XMost() - aVisIEndEdge, mVisIStart) + : nscoord_MAX; + } + } + void Intersect(nscoord* aVisIStart, nscoord* aVisISize) const { + nscoord end = *aVisIStart + *aVisISize; + *aVisIStart = std::max(*aVisIStart, mVisIStart); + *aVisISize = std::max(std::min(end, mVisIEnd) - *aVisIStart, 0); + } + nscoord mVisIStart; + nscoord mVisIEnd; + }; + + ClipEdges Edges() const { + return ClipEdges(*this, mVisIStartEdge, mVisIEndEdge); + } + + static nsCharClipDisplayItem* CheckCast(nsDisplayItem* aItem) { + nsDisplayItem::Type t = aItem->GetType(); + return (t == nsDisplayItem::TYPE_TEXT) + ? static_cast<nsCharClipDisplayItem*>(aItem) : nullptr; + } + + // Lengths measured from the visual inline start and end sides + // (i.e. left and right respectively in horizontal writing modes, + // regardless of bidi directionality; top and bottom in vertical modes). + nscoord mVisIStartEdge; + nscoord mVisIEndEdge; + // Cached result of mFrame->IsSelected(). Only initialized when needed. + mutable mozilla::Maybe<bool> mIsFrameSelected; +}; + +namespace mozilla { + +class PaintTelemetry +{ + public: + enum class Metric { + DisplayList, + Layerization, + Rasterization, + COUNT, + }; + + class AutoRecord + { + public: + explicit AutoRecord(Metric aMetric); + ~AutoRecord(); + private: + Metric mMetric; + mozilla::TimeStamp mStart; + }; + + class AutoRecordPaint + { + public: + AutoRecordPaint(); + ~AutoRecordPaint(); + private: + mozilla::TimeStamp mStart; + }; + + private: + static uint32_t sPaintLevel; + static uint32_t sMetricLevel; + static mozilla::EnumeratedArray<Metric, Metric::COUNT, double> sMetrics; +}; + +} // namespace mozilla + +#endif /*NSDISPLAYLIST_H_*/ |