michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * vim: set ts=2 sw=2 et tw=78: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: */ michael@0: michael@0: /* michael@0: * structures that represent things to be painted (ordered in z-order), michael@0: * used during painting and hit testing michael@0: */ michael@0: michael@0: #ifndef NSDISPLAYLIST_H_ michael@0: #define NSDISPLAYLIST_H_ michael@0: michael@0: #include "mozilla/Attributes.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsIFrame.h" michael@0: #include "nsPoint.h" michael@0: #include "nsRect.h" michael@0: #include "nsCaret.h" michael@0: #include "plarena.h" michael@0: #include "nsRegion.h" michael@0: #include "FrameLayerBuilder.h" michael@0: #include "nsLayoutUtils.h" michael@0: #include "nsDisplayListInvalidation.h" michael@0: #include "DisplayListClipState.h" michael@0: michael@0: #include michael@0: michael@0: #include michael@0: #include michael@0: michael@0: class nsIContent; michael@0: class nsRenderingContext; michael@0: class nsDisplayTableItem; michael@0: class nsISelection; michael@0: class nsDisplayLayerEventRegions; michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: class Layer; michael@0: class ImageLayer; michael@0: class ImageContainer; michael@0: } //namepsace michael@0: } //namepsace michael@0: michael@0: /* michael@0: * An nsIFrame can have many different visual parts. For example an image frame michael@0: * can have a background, border, and outline, the image itself, and a michael@0: * translucent selection overlay. In general these parts can be drawn at michael@0: * discontiguous z-levels; see CSS2.1 appendix E: michael@0: * http://www.w3.org/TR/CSS21/zindex.html michael@0: * michael@0: * We construct a display list for a frame tree that contains one item michael@0: * for each visual part. The display list is itself a tree since some items michael@0: * are containers for other items; however, its structure does not match michael@0: * the structure of its source frame tree. The display list items are sorted michael@0: * by z-order. A display list can be used to paint the frames, to determine michael@0: * which frame is the target of a mouse event, and to determine what areas michael@0: * need to be repainted when scrolling. The display lists built for each task michael@0: * may be different for efficiency; in particular some frames need special michael@0: * display list items only for event handling, and do not create these items michael@0: * when the display list will be used for painting (the common case). For michael@0: * example, when painting we avoid creating nsDisplayBackground items for michael@0: * frames that don't display a visible background, but for event handling michael@0: * we need those backgrounds because they are not transparent to events. michael@0: * michael@0: * We could avoid constructing an explicit display list by traversing the michael@0: * frame tree multiple times in clever ways. However, reifying the display list michael@0: * reduces code complexity and reduces the number of times each frame must be michael@0: * traversed to one, which seems to be good for performance. It also means michael@0: * we can share code for painting, event handling and scroll analysis. michael@0: * michael@0: * Display lists are short-lived; content and frame trees cannot change michael@0: * between a display list being created and destroyed. Display lists should michael@0: * not be created during reflow because the frame tree may be in an michael@0: * inconsistent state (e.g., a frame's stored overflow-area may not include michael@0: * the bounds of all its children). However, it should be fine to create michael@0: * a display list while a reflow is pending, before it starts. michael@0: * michael@0: * A display list covers the "extended" frame tree; the display list for a frame michael@0: * tree containing FRAME/IFRAME elements can include frames from the subdocuments. michael@0: * michael@0: * Display item's coordinates are relative to their nearest reference frame ancestor. michael@0: * Both the display root and any frame with a transform act as a reference frame michael@0: * for their frame subtrees. michael@0: */ michael@0: michael@0: // All types are defined in nsDisplayItemTypes.h michael@0: #ifdef MOZ_DUMP_PAINTING michael@0: #define NS_DISPLAY_DECL_NAME(n, e) \ michael@0: virtual const char* Name() { return n; } \ michael@0: virtual Type GetType() { return e; } michael@0: #else michael@0: #define NS_DISPLAY_DECL_NAME(n, e) \ michael@0: virtual Type GetType() { return e; } michael@0: #endif michael@0: michael@0: /** michael@0: * This manages a display list and is passed as a parameter to michael@0: * nsIFrame::BuildDisplayList. michael@0: * It contains the parameters that don't change from frame to frame and manages michael@0: * the display list memory using a PLArena. It also establishes the reference michael@0: * coordinate system for all display list items. Some of the parameters are michael@0: * available from the prescontext/presshell, but we copy them into the builder michael@0: * for faster/more convenient access. michael@0: */ michael@0: class nsDisplayListBuilder { michael@0: public: michael@0: typedef mozilla::FramePropertyDescriptor FramePropertyDescriptor; michael@0: typedef mozilla::FrameLayerBuilder FrameLayerBuilder; michael@0: typedef mozilla::DisplayItemClip DisplayItemClip; michael@0: typedef mozilla::DisplayListClipState DisplayListClipState; michael@0: typedef nsIWidget::ThemeGeometry ThemeGeometry; michael@0: typedef mozilla::layers::Layer Layer; michael@0: typedef mozilla::layers::FrameMetrics::ViewID ViewID; michael@0: michael@0: /** michael@0: * @param aReferenceFrame the frame at the root of the subtree; its origin michael@0: * is the origin of the reference coordinate system for this display list michael@0: * @param aIsForEvents true if we're creating this list in order to michael@0: * determine which frame is under the mouse position michael@0: * @param aBuildCaret whether or not we should include the caret in any michael@0: * display lists that we make. michael@0: */ michael@0: enum Mode { michael@0: PAINTING, michael@0: EVENT_DELIVERY, michael@0: PLUGIN_GEOMETRY, michael@0: IMAGE_VISIBILITY, michael@0: OTHER michael@0: }; michael@0: nsDisplayListBuilder(nsIFrame* aReferenceFrame, Mode aMode, bool aBuildCaret); michael@0: ~nsDisplayListBuilder(); michael@0: michael@0: void SetWillComputePluginGeometry(bool aWillComputePluginGeometry) michael@0: { michael@0: mWillComputePluginGeometry = aWillComputePluginGeometry; michael@0: } michael@0: void SetForPluginGeometry() michael@0: { michael@0: NS_ASSERTION(mMode == PAINTING, "Can only switch from PAINTING to PLUGIN_GEOMETRY"); michael@0: NS_ASSERTION(mWillComputePluginGeometry, "Should have signalled this in advance"); michael@0: mMode = PLUGIN_GEOMETRY; michael@0: } michael@0: michael@0: /** michael@0: * @return true if the display is being built in order to determine which michael@0: * frame is under the mouse position. michael@0: */ michael@0: bool IsForEventDelivery() { return mMode == EVENT_DELIVERY; } michael@0: /** michael@0: * Be careful with this. The display list will be built in PAINTING mode michael@0: * first and then switched to PLUGIN_GEOMETRY before a second call to michael@0: * ComputeVisibility. michael@0: * @return true if the display list is being built to compute geometry michael@0: * for plugins. michael@0: */ michael@0: bool IsForPluginGeometry() { return mMode == PLUGIN_GEOMETRY; } michael@0: /** michael@0: * @return true if the display list is being built for painting. michael@0: */ michael@0: bool IsForPainting() { return mMode == PAINTING; } michael@0: /** michael@0: * @return true if the display list is being built for determining image michael@0: * visibility. michael@0: */ michael@0: bool IsForImageVisibility() { return mMode == IMAGE_VISIBILITY; } michael@0: bool WillComputePluginGeometry() { return mWillComputePluginGeometry; } michael@0: /** michael@0: * @return true if "painting is suppressed" during page load and we michael@0: * should paint only the background of the document. michael@0: */ michael@0: bool IsBackgroundOnly() { michael@0: NS_ASSERTION(mPresShellStates.Length() > 0, michael@0: "don't call this if we're not in a presshell"); michael@0: return CurrentPresShellState()->mIsBackgroundOnly; michael@0: } michael@0: /** michael@0: * @return true if the currently active BuildDisplayList call is being michael@0: * applied to a frame at the root of a pseudo stacking context. A pseudo michael@0: * stacking context is either a real stacking context or basically what michael@0: * CSS2.1 appendix E refers to with "treat the element as if it created michael@0: * a new stacking context michael@0: */ michael@0: bool IsAtRootOfPseudoStackingContext() { return mIsAtRootOfPseudoStackingContext; } michael@0: michael@0: /** michael@0: * @return the selection that painting should be restricted to (or nullptr michael@0: * in the normal unrestricted case) michael@0: */ michael@0: nsISelection* GetBoundingSelection() { return mBoundingSelection; } michael@0: michael@0: /** michael@0: * @return the root of given frame's (sub)tree, whose origin michael@0: * establishes the coordinate system for the child display items. michael@0: */ michael@0: const nsIFrame* FindReferenceFrameFor(const nsIFrame *aFrame) michael@0: { michael@0: if (aFrame == mCachedOffsetFrame) { michael@0: return mCachedReferenceFrame; michael@0: } michael@0: for (const nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) michael@0: { michael@0: if (f == mReferenceFrame || f->IsTransformed()) { michael@0: mCachedOffsetFrame = aFrame; michael@0: mCachedReferenceFrame = f; michael@0: mCachedOffset = aFrame->GetOffsetToCrossDoc(f); michael@0: return f; michael@0: } michael@0: } michael@0: mCachedOffsetFrame = aFrame; michael@0: mCachedReferenceFrame = mReferenceFrame; michael@0: mCachedOffset = aFrame->GetOffsetToCrossDoc(mReferenceFrame); michael@0: return mReferenceFrame; michael@0: } michael@0: michael@0: /** michael@0: * @return the root of the display list's frame (sub)tree, whose origin michael@0: * establishes the coordinate system for the display list michael@0: */ michael@0: nsIFrame* RootReferenceFrame() michael@0: { michael@0: return mReferenceFrame; michael@0: } michael@0: michael@0: /** michael@0: * @return a point pt such that adding pt to a coordinate relative to aFrame michael@0: * makes it relative to ReferenceFrame(), i.e., returns michael@0: * aFrame->GetOffsetToCrossDoc(ReferenceFrame()). The returned point is in michael@0: * the appunits of aFrame. It may be optimized to be faster than michael@0: * aFrame->GetOffsetToCrossDoc(ReferenceFrame()) (but currently isn't). michael@0: */ michael@0: const nsPoint& ToReferenceFrame(const nsIFrame* aFrame) { michael@0: if (aFrame != mCachedOffsetFrame) { michael@0: FindReferenceFrameFor(aFrame); michael@0: } michael@0: return mCachedOffset; michael@0: } michael@0: /** michael@0: * When building the display list, the scrollframe aFrame will be "ignored" michael@0: * for the purposes of clipping, and its scrollbars will be hidden. We use michael@0: * this to allow RenderOffscreen to render a whole document without beign michael@0: * clipped by the viewport or drawing the viewport scrollbars. michael@0: */ michael@0: void SetIgnoreScrollFrame(nsIFrame* aFrame) { mIgnoreScrollFrame = aFrame; } michael@0: /** michael@0: * Get the scrollframe to ignore, if any. michael@0: */ michael@0: nsIFrame* GetIgnoreScrollFrame() { return mIgnoreScrollFrame; } michael@0: /** michael@0: * Get the ViewID of the nearest scrolling ancestor frame. michael@0: */ michael@0: ViewID GetCurrentScrollParentId() const { return mCurrentScrollParentId; } michael@0: /** michael@0: * Calling this setter makes us include all out-of-flow descendant michael@0: * frames in the display list, wherever they may be positioned (even michael@0: * outside the dirty rects). michael@0: */ michael@0: void SetIncludeAllOutOfFlows() { mIncludeAllOutOfFlows = true; } michael@0: bool GetIncludeAllOutOfFlows() const { return mIncludeAllOutOfFlows; } michael@0: /** michael@0: * Calling this setter makes us exclude all leaf frames that aren't michael@0: * selected. michael@0: */ michael@0: void SetSelectedFramesOnly() { mSelectedFramesOnly = true; } michael@0: bool GetSelectedFramesOnly() { return mSelectedFramesOnly; } michael@0: /** michael@0: * Calling this setter makes us compute accurate visible regions at the cost michael@0: * of performance if regions get very complex. michael@0: */ michael@0: void SetAccurateVisibleRegions() { mAccurateVisibleRegions = true; } michael@0: bool GetAccurateVisibleRegions() { return mAccurateVisibleRegions; } michael@0: /** michael@0: * Allows callers to selectively override the regular paint suppression checks, michael@0: * so that methods like GetFrameForPoint work when painting is suppressed. michael@0: */ michael@0: void IgnorePaintSuppression() { mIgnoreSuppression = true; } michael@0: /** michael@0: * @return Returns if this builder will ignore paint suppression. michael@0: */ michael@0: bool IsIgnoringPaintSuppression() { return mIgnoreSuppression; } michael@0: /** michael@0: * @return Returns if this builder had to ignore painting suppression on some michael@0: * document when building the display list. michael@0: */ michael@0: bool GetHadToIgnorePaintSuppression() { return mHadToIgnoreSuppression; } michael@0: /** michael@0: * Call this if we're doing normal painting to the window. michael@0: */ michael@0: void SetPaintingToWindow(bool aToWindow) { mIsPaintingToWindow = aToWindow; } michael@0: bool IsPaintingToWindow() const { return mIsPaintingToWindow; } michael@0: /** michael@0: * Call this to prevent descending into subdocuments. michael@0: */ michael@0: void SetDescendIntoSubdocuments(bool aDescend) { mDescendIntoSubdocuments = aDescend; } michael@0: bool GetDescendIntoSubdocuments() { return mDescendIntoSubdocuments; } michael@0: michael@0: /** michael@0: * Returns true if merging and flattening of display lists should be michael@0: * performed while computing visibility. michael@0: */ michael@0: bool AllowMergingAndFlattening() { return mAllowMergingAndFlattening; } michael@0: void SetAllowMergingAndFlattening(bool aAllow) { mAllowMergingAndFlattening = aAllow; } michael@0: michael@0: nsDisplayLayerEventRegions* GetLayerEventRegions() { return mLayerEventRegions; } michael@0: void SetLayerEventRegions(nsDisplayLayerEventRegions* aItem) michael@0: { michael@0: mLayerEventRegions = aItem; michael@0: } michael@0: bool IsBuildingLayerEventRegions() michael@0: { michael@0: // Disable for now. michael@0: return false; michael@0: // return mMode == PAINTING; michael@0: } michael@0: michael@0: bool GetAncestorHasTouchEventHandler() { return mAncestorHasTouchEventHandler; } michael@0: void SetAncestorHasTouchEventHandler(bool aValue) michael@0: { michael@0: mAncestorHasTouchEventHandler = aValue; michael@0: } michael@0: michael@0: bool HaveScrollableDisplayPort() const { return mHaveScrollableDisplayPort; } michael@0: void SetHaveScrollableDisplayPort() { mHaveScrollableDisplayPort = true; } michael@0: michael@0: bool SetIsCompositingCheap(bool aCompositingCheap) { michael@0: bool temp = mIsCompositingCheap; michael@0: mIsCompositingCheap = aCompositingCheap; michael@0: return temp; michael@0: } michael@0: bool IsCompositingCheap() const { return mIsCompositingCheap; } michael@0: /** michael@0: * Display the caret if needed. michael@0: */ michael@0: void DisplayCaret(nsIFrame* aFrame, const nsRect& aDirtyRect, michael@0: nsDisplayList* aList) { michael@0: nsIFrame* frame = GetCaretFrame(); michael@0: if (aFrame == frame) { michael@0: frame->DisplayCaret(this, aDirtyRect, aList); michael@0: } michael@0: } michael@0: /** michael@0: * Get the frame that the caret is supposed to draw in. michael@0: * If the caret is currently invisible, this will be null. michael@0: */ michael@0: nsIFrame* GetCaretFrame() { michael@0: return CurrentPresShellState()->mCaretFrame; michael@0: } michael@0: /** michael@0: * Get the caret associated with the current presshell. michael@0: */ michael@0: nsCaret* GetCaret(); michael@0: /** michael@0: * Notify the display list builder that we're entering a presshell. michael@0: * aReferenceFrame should be a frame in the new presshell and aDirtyRect michael@0: * should be the current dirty rect in aReferenceFrame's coordinate space. michael@0: */ michael@0: void EnterPresShell(nsIFrame* aReferenceFrame, const nsRect& aDirtyRect); michael@0: /** michael@0: * For print-preview documents, we sometimes need to build display items for michael@0: * the same frames multiple times in the same presentation, with different michael@0: * clipping. Between each such batch of items, call michael@0: * ResetMarkedFramesForDisplayList to make sure that the results of michael@0: * MarkFramesForDisplayList do not carry over between batches. michael@0: */ michael@0: void ResetMarkedFramesForDisplayList(); michael@0: /** michael@0: * Notify the display list builder that we're leaving a presshell. michael@0: */ michael@0: void LeavePresShell(nsIFrame* aReferenceFrame, const nsRect& aDirtyRect); michael@0: michael@0: /** michael@0: * Returns true if we're currently building a display list that's michael@0: * directly or indirectly under an nsDisplayTransform. michael@0: */ michael@0: bool IsInTransform() const { return mInTransform; } michael@0: /** michael@0: * Indicate whether or not we're directly or indirectly under and michael@0: * nsDisplayTransform or SVG foreignObject. michael@0: */ michael@0: void SetInTransform(bool aInTransform) { mInTransform = aInTransform; } michael@0: michael@0: /** michael@0: * Returns true if we're currently building display items that are in michael@0: * true fixed position subtree. michael@0: */ michael@0: bool IsInFixedPos() const { return mInFixedPos; } michael@0: michael@0: /** michael@0: * @return true if images have been set to decode synchronously. michael@0: */ michael@0: bool ShouldSyncDecodeImages() { return mSyncDecodeImages; } michael@0: michael@0: /** michael@0: * Indicates whether we should synchronously decode images. If true, we decode michael@0: * and draw whatever image data has been loaded. If false, we just draw michael@0: * whatever has already been decoded. michael@0: */ michael@0: void SetSyncDecodeImages(bool aSyncDecodeImages) { michael@0: mSyncDecodeImages = aSyncDecodeImages; michael@0: } michael@0: michael@0: /** michael@0: * Helper method to generate background painting flags based on the michael@0: * information available in the display list builder. Currently only michael@0: * accounts for mSyncDecodeImages. michael@0: */ michael@0: uint32_t GetBackgroundPaintFlags(); michael@0: michael@0: /** michael@0: * Subtracts aRegion from *aVisibleRegion. We avoid letting michael@0: * aVisibleRegion become overcomplex by simplifying it if necessary --- michael@0: * unless mAccurateVisibleRegions is set, in which case we let it michael@0: * get arbitrarily complex. michael@0: */ michael@0: void SubtractFromVisibleRegion(nsRegion* aVisibleRegion, michael@0: const nsRegion& aRegion); michael@0: michael@0: /** michael@0: * Mark the frames in aFrames to be displayed if they intersect aDirtyRect michael@0: * (which is relative to aDirtyFrame). If the frames have placeholders michael@0: * that might not be displayed, we mark the placeholders and their ancestors michael@0: * to ensure that display list construction descends into them michael@0: * anyway. nsDisplayListBuilder will take care of unmarking them when it is michael@0: * destroyed. michael@0: */ michael@0: void MarkFramesForDisplayList(nsIFrame* aDirtyFrame, michael@0: const nsFrameList& aFrames, michael@0: const nsRect& aDirtyRect); michael@0: /** michael@0: * Mark all child frames that Preserve3D() as needing display. michael@0: * Because these frames include transforms set on their parent, dirty rects michael@0: * for intermediate frames may be empty, yet child frames could still be visible. michael@0: */ michael@0: void MarkPreserve3DFramesForDisplayList(nsIFrame* aDirtyFrame, const nsRect& aDirtyRect); michael@0: michael@0: /** michael@0: * Get the area of the final transparent region. michael@0: */ michael@0: const nsRegion* GetFinalTransparentRegion() { return mFinalTransparentRegion; } michael@0: /** michael@0: * Record the area of the final transparent region after all visibility michael@0: * calculations were performed. michael@0: */ michael@0: void SetFinalTransparentRegion(const nsRegion& aFinalTransparentRegion) michael@0: { michael@0: mFinalTransparentRegion = &aFinalTransparentRegion; michael@0: } michael@0: michael@0: const nsTArray& GetThemeGeometries() { return mThemeGeometries; } michael@0: michael@0: /** michael@0: * Returns true if we need to descend into this frame when building michael@0: * the display list, even though it doesn't intersect the dirty michael@0: * rect, because it may have out-of-flows that do so. michael@0: */ michael@0: bool ShouldDescendIntoFrame(nsIFrame* aFrame) const { michael@0: return michael@0: (aFrame->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO) || michael@0: GetIncludeAllOutOfFlows(); michael@0: } michael@0: michael@0: /** michael@0: * Notifies the builder that a particular themed widget exists michael@0: * at the given rectangle within the currently built display list. michael@0: * For certain appearance values (currently only michael@0: * NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR, NS_THEME_TOOLBAR and michael@0: * NS_THEME_WINDOW_TITLEBAR) this gets called during every display list michael@0: * construction, for every themed widget of the right type within the michael@0: * display list, except for themed widgets which are transformed or have michael@0: * effects applied to them (e.g. CSS opacity or filters). michael@0: * michael@0: * @param aWidgetType the -moz-appearance value for the themed widget michael@0: * @param aRect the device-pixel rect relative to the widget's displayRoot michael@0: * for the themed widget michael@0: */ michael@0: void RegisterThemeGeometry(uint8_t aWidgetType, michael@0: const nsIntRect& aRect) { michael@0: if (mIsPaintingToWindow && mPresShellStates.Length() == 1) { michael@0: ThemeGeometry geometry(aWidgetType, aRect); michael@0: mThemeGeometries.AppendElement(geometry); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Allocate memory in our arena. It will only be freed when this display list michael@0: * builder is destroyed. This memory holds nsDisplayItems. nsDisplayItem michael@0: * destructors are called as soon as the item is no longer used. michael@0: */ michael@0: void* Allocate(size_t aSize); michael@0: michael@0: /** michael@0: * Allocate a new DisplayListClip in the arena. Will be cleaned up michael@0: * automatically when the arena goes away. michael@0: */ michael@0: const DisplayItemClip* AllocateDisplayItemClip(const DisplayItemClip& aOriginal); michael@0: michael@0: /** michael@0: * Transfer off main thread animations to the layer. May be called michael@0: * with aBuilder and aItem both null, but only if the caller has michael@0: * already checked that off main thread animations should be sent to michael@0: * the layer. When they are both null, the animations are added to michael@0: * the layer as pending animations. michael@0: */ michael@0: static void AddAnimationsAndTransitionsToLayer(Layer* aLayer, michael@0: nsDisplayListBuilder* aBuilder, michael@0: nsDisplayItem* aItem, michael@0: nsIFrame* aFrame, michael@0: nsCSSProperty aProperty); michael@0: /** michael@0: * A helper class to temporarily set the value of michael@0: * mIsAtRootOfPseudoStackingContext, and temporarily michael@0: * update mCachedOffsetFrame/mCachedOffset from a frame to its child. michael@0: * Also saves and restores mClipState. michael@0: */ michael@0: class AutoBuildingDisplayList; michael@0: friend class AutoBuildingDisplayList; michael@0: class AutoBuildingDisplayList { michael@0: public: michael@0: AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder, bool aIsRoot) michael@0: : mBuilder(aBuilder), michael@0: mPrevCachedOffsetFrame(aBuilder->mCachedOffsetFrame), michael@0: mPrevCachedReferenceFrame(aBuilder->mCachedReferenceFrame), michael@0: mPrevLayerEventRegions(aBuilder->mLayerEventRegions), michael@0: mPrevCachedOffset(aBuilder->mCachedOffset), michael@0: mPrevIsAtRootOfPseudoStackingContext(aBuilder->mIsAtRootOfPseudoStackingContext), michael@0: mPrevAncestorHasTouchEventHandler(aBuilder->mAncestorHasTouchEventHandler) michael@0: { michael@0: aBuilder->mIsAtRootOfPseudoStackingContext = aIsRoot; michael@0: } michael@0: AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder, michael@0: nsIFrame* aForChild, bool aIsRoot) michael@0: : mBuilder(aBuilder), michael@0: mPrevCachedOffsetFrame(aBuilder->mCachedOffsetFrame), michael@0: mPrevCachedReferenceFrame(aBuilder->mCachedReferenceFrame), michael@0: mPrevLayerEventRegions(aBuilder->mLayerEventRegions), michael@0: mPrevCachedOffset(aBuilder->mCachedOffset), michael@0: mPrevIsAtRootOfPseudoStackingContext(aBuilder->mIsAtRootOfPseudoStackingContext), michael@0: mPrevAncestorHasTouchEventHandler(aBuilder->mAncestorHasTouchEventHandler) michael@0: { michael@0: if (aForChild->IsTransformed()) { michael@0: aBuilder->mCachedOffset = nsPoint(); michael@0: aBuilder->mCachedReferenceFrame = aForChild; michael@0: } else if (mPrevCachedOffsetFrame == aForChild->GetParent()) { michael@0: aBuilder->mCachedOffset += aForChild->GetPosition(); michael@0: } else { michael@0: aBuilder->mCachedOffset = aBuilder->ToReferenceFrame(aForChild); michael@0: } michael@0: aBuilder->mCachedOffsetFrame = aForChild; michael@0: aBuilder->mIsAtRootOfPseudoStackingContext = aIsRoot; michael@0: } michael@0: ~AutoBuildingDisplayList() { michael@0: mBuilder->mCachedOffsetFrame = mPrevCachedOffsetFrame; michael@0: mBuilder->mCachedReferenceFrame = mPrevCachedReferenceFrame; michael@0: mBuilder->mLayerEventRegions = mPrevLayerEventRegions; michael@0: mBuilder->mCachedOffset = mPrevCachedOffset; michael@0: mBuilder->mIsAtRootOfPseudoStackingContext = mPrevIsAtRootOfPseudoStackingContext; michael@0: mBuilder->mAncestorHasTouchEventHandler = mPrevAncestorHasTouchEventHandler; michael@0: } michael@0: private: michael@0: nsDisplayListBuilder* mBuilder; michael@0: const nsIFrame* mPrevCachedOffsetFrame; michael@0: const nsIFrame* mPrevCachedReferenceFrame; michael@0: nsDisplayLayerEventRegions* mPrevLayerEventRegions; michael@0: nsPoint mPrevCachedOffset; michael@0: bool mPrevIsAtRootOfPseudoStackingContext; michael@0: bool mPrevAncestorHasTouchEventHandler; michael@0: }; michael@0: michael@0: /** michael@0: * A helper class to temporarily set the value of mInTransform. michael@0: */ michael@0: class AutoInTransformSetter; michael@0: friend class AutoInTransformSetter; michael@0: class AutoInTransformSetter { michael@0: public: michael@0: AutoInTransformSetter(nsDisplayListBuilder* aBuilder, bool aInTransform) michael@0: : mBuilder(aBuilder), mOldValue(aBuilder->mInTransform) { michael@0: aBuilder->mInTransform = aInTransform; michael@0: } michael@0: ~AutoInTransformSetter() { michael@0: mBuilder->mInTransform = mOldValue; michael@0: } michael@0: private: michael@0: nsDisplayListBuilder* mBuilder; michael@0: bool mOldValue; michael@0: }; michael@0: michael@0: /** michael@0: * A helper class to temporarily set the value of mInFixedPos. michael@0: */ michael@0: class AutoInFixedPosSetter; michael@0: friend class AutoInFixedPosSetter; michael@0: class AutoInFixedPosSetter { michael@0: public: michael@0: AutoInFixedPosSetter(nsDisplayListBuilder* aBuilder, bool aInFixedPos) michael@0: : mBuilder(aBuilder), mOldValue(aBuilder->mInFixedPos) { michael@0: aBuilder->mInFixedPos = aInFixedPos; michael@0: } michael@0: ~AutoInFixedPosSetter() { michael@0: mBuilder->mInFixedPos = mOldValue; michael@0: } michael@0: private: michael@0: nsDisplayListBuilder* mBuilder; michael@0: bool mOldValue; michael@0: }; michael@0: michael@0: /** michael@0: * A helper class to temporarily set the value of mCurrentScrollParentId. michael@0: */ michael@0: class AutoCurrentScrollParentIdSetter; michael@0: friend class AutoCurrentScrollParentIdSetter; michael@0: class AutoCurrentScrollParentIdSetter { michael@0: public: michael@0: AutoCurrentScrollParentIdSetter(nsDisplayListBuilder* aBuilder, ViewID aScrollId) michael@0: : mBuilder(aBuilder), mOldValue(aBuilder->mCurrentScrollParentId) { michael@0: aBuilder->mCurrentScrollParentId = aScrollId; michael@0: } michael@0: ~AutoCurrentScrollParentIdSetter() { michael@0: mBuilder->mCurrentScrollParentId = mOldValue; michael@0: } michael@0: private: michael@0: nsDisplayListBuilder* mBuilder; michael@0: ViewID mOldValue; michael@0: }; michael@0: michael@0: // Helpers for tables michael@0: nsDisplayTableItem* GetCurrentTableItem() { return mCurrentTableItem; } michael@0: void SetCurrentTableItem(nsDisplayTableItem* aTableItem) { mCurrentTableItem = aTableItem; } michael@0: michael@0: struct OutOfFlowDisplayData { michael@0: OutOfFlowDisplayData(const DisplayItemClip& aContainingBlockClip, michael@0: const nsRect &aDirtyRect) michael@0: : mContainingBlockClip(aContainingBlockClip) michael@0: , mDirtyRect(aDirtyRect) michael@0: {} michael@0: OutOfFlowDisplayData(const nsRect &aDirtyRect) michael@0: : mDirtyRect(aDirtyRect) michael@0: {} michael@0: DisplayItemClip mContainingBlockClip; michael@0: nsRect mDirtyRect; michael@0: }; michael@0: static void DestroyOutOfFlowDisplayData(void* aPropertyValue) michael@0: { michael@0: delete static_cast(aPropertyValue); michael@0: } michael@0: michael@0: NS_DECLARE_FRAME_PROPERTY(OutOfFlowDisplayDataProperty, DestroyOutOfFlowDisplayData) michael@0: NS_DECLARE_FRAME_PROPERTY(Preserve3DDirtyRectProperty, nsIFrame::DestroyRect) michael@0: michael@0: nsPresContext* CurrentPresContext() { michael@0: return CurrentPresShellState()->mPresShell->GetPresContext(); michael@0: } michael@0: michael@0: /** michael@0: * Accumulates the bounds of box frames that have moz-appearance michael@0: * -moz-win-exclude-glass style. Used in setting glass margins on michael@0: * Windows. michael@0: */ michael@0: void AddExcludedGlassRegion(nsRect &bounds) { michael@0: mExcludedGlassRegion.Or(mExcludedGlassRegion, bounds); michael@0: } michael@0: const nsRegion& GetExcludedGlassRegion() { michael@0: return mExcludedGlassRegion; michael@0: } michael@0: void SetGlassDisplayItem(nsDisplayItem* aItem) { michael@0: if (mGlassDisplayItem) { michael@0: // Web pages or extensions could trigger this by using michael@0: // -moz-appearance:win-borderless-glass etc on their own elements. michael@0: // Keep the first one, since that will be the background of the root michael@0: // window michael@0: NS_WARNING("Multiple glass backgrounds found?"); michael@0: } else { michael@0: mGlassDisplayItem = aItem; michael@0: } michael@0: } michael@0: bool NeedToForceTransparentSurfaceForItem(nsDisplayItem* aItem) { michael@0: return aItem == mGlassDisplayItem; michael@0: } michael@0: michael@0: void SetContainsPluginItem() { mContainsPluginItem = true; } michael@0: bool ContainsPluginItem() { return mContainsPluginItem; } michael@0: michael@0: /** michael@0: * mContainsBlendMode is true if we processed a display item that michael@0: * has a blend mode attached. We do this so we can insert a michael@0: * nsDisplayBlendContainer in the parent stacking context. michael@0: */ michael@0: void SetContainsBlendMode(bool aContainsBlendMode) { mContainsBlendMode = aContainsBlendMode; } michael@0: bool ContainsBlendMode() const { return mContainsBlendMode; } michael@0: michael@0: DisplayListClipState& ClipState() { return mClipState; } michael@0: michael@0: private: michael@0: void MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame, nsIFrame* aFrame, michael@0: const nsRect& aDirtyRect); michael@0: michael@0: struct PresShellState { michael@0: nsIPresShell* mPresShell; michael@0: nsIFrame* mCaretFrame; michael@0: uint32_t mFirstFrameMarkedForDisplay; michael@0: bool mIsBackgroundOnly; michael@0: }; michael@0: PresShellState* CurrentPresShellState() { michael@0: NS_ASSERTION(mPresShellStates.Length() > 0, michael@0: "Someone forgot to enter a presshell"); michael@0: return &mPresShellStates[mPresShellStates.Length() - 1]; michael@0: } michael@0: michael@0: nsIFrame* mReferenceFrame; michael@0: nsIFrame* mIgnoreScrollFrame; michael@0: nsDisplayLayerEventRegions* mLayerEventRegions; michael@0: PLArenaPool mPool; michael@0: nsCOMPtr mBoundingSelection; michael@0: nsAutoTArray mPresShellStates; michael@0: nsAutoTArray mFramesMarkedForDisplay; michael@0: nsAutoTArray mThemeGeometries; michael@0: nsDisplayTableItem* mCurrentTableItem; michael@0: DisplayListClipState mClipState; michael@0: const nsRegion* mFinalTransparentRegion; michael@0: // When mCachedOffsetFrame is non-null, mCachedOffset is the offset from michael@0: // mCachedOffsetFrame to mReferenceFrame. michael@0: const nsIFrame* mCachedOffsetFrame; michael@0: const nsIFrame* mCachedReferenceFrame; michael@0: nsPoint mCachedOffset; michael@0: nsRegion mExcludedGlassRegion; michael@0: // The display item for the Windows window glass background, if any michael@0: nsDisplayItem* mGlassDisplayItem; michael@0: nsTArray mDisplayItemClipsToDestroy; michael@0: Mode mMode; michael@0: ViewID mCurrentScrollParentId; michael@0: bool mBuildCaret; michael@0: bool mIgnoreSuppression; michael@0: bool mHadToIgnoreSuppression; michael@0: bool mIsAtRootOfPseudoStackingContext; michael@0: bool mIncludeAllOutOfFlows; michael@0: bool mDescendIntoSubdocuments; michael@0: bool mSelectedFramesOnly; michael@0: bool mAccurateVisibleRegions; michael@0: bool mAllowMergingAndFlattening; michael@0: bool mWillComputePluginGeometry; michael@0: // True when we're building a display list that's directly or indirectly michael@0: // under an nsDisplayTransform michael@0: bool mInTransform; michael@0: bool mInFixedPos; michael@0: bool mSyncDecodeImages; michael@0: bool mIsPaintingToWindow; michael@0: bool mIsCompositingCheap; michael@0: bool mContainsPluginItem; michael@0: bool mContainsBlendMode; michael@0: bool mAncestorHasTouchEventHandler; michael@0: // True when the first async-scrollable scroll frame for which we build a michael@0: // display list has a display port. An async-scrollable scroll frame is one michael@0: // which WantsAsyncScroll(). michael@0: bool mHaveScrollableDisplayPort; michael@0: }; michael@0: michael@0: class nsDisplayItem; michael@0: class nsDisplayList; michael@0: /** michael@0: * nsDisplayItems are put in singly-linked lists rooted in an nsDisplayList. michael@0: * nsDisplayItemLink holds the link. The lists are linked from lowest to michael@0: * highest in z-order. michael@0: */ michael@0: class nsDisplayItemLink { michael@0: // This is never instantiated directly, so no need to count constructors and michael@0: // destructors. michael@0: protected: michael@0: nsDisplayItemLink() : mAbove(nullptr) {} michael@0: nsDisplayItem* mAbove; michael@0: michael@0: friend class nsDisplayList; michael@0: }; michael@0: michael@0: /** michael@0: * This is the unit of rendering and event testing. Each instance of this michael@0: * class represents an entity that can be drawn on the screen, e.g., a michael@0: * frame's CSS background, or a frame's text string. michael@0: * michael@0: * nsDisplayListItems can be containers --- i.e., they can perform hit testing michael@0: * and painting by recursively traversing a list of child items. michael@0: * michael@0: * These are arena-allocated during display list construction. A typical michael@0: * subclass would just have a frame pointer, so its object would be just three michael@0: * pointers (vtable, next-item, frame). michael@0: * michael@0: * Display items belong to a list at all times (except temporarily as they michael@0: * move from one list to another). michael@0: */ michael@0: class nsDisplayItem : public nsDisplayItemLink { michael@0: public: michael@0: typedef mozilla::ContainerLayerParameters ContainerLayerParameters; michael@0: typedef mozilla::DisplayItemClip DisplayItemClip; michael@0: typedef mozilla::layers::FrameMetrics::ViewID ViewID; michael@0: typedef mozilla::layers::Layer Layer; michael@0: typedef mozilla::layers::LayerManager LayerManager; michael@0: typedef mozilla::LayerState LayerState; michael@0: michael@0: // This is never instantiated directly (it has pure virtual methods), so no michael@0: // need to count constructors and destructors. michael@0: nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) michael@0: : mFrame(aFrame) michael@0: , mClip(aBuilder->ClipState().GetCurrentCombinedClip(aBuilder)) michael@0: , mInFixedPos(aBuilder->IsInFixedPos()) michael@0: #ifdef MOZ_DUMP_PAINTING michael@0: , mPainted(false) michael@0: #endif michael@0: { michael@0: mReferenceFrame = aBuilder->FindReferenceFrameFor(aFrame); michael@0: mToReferenceFrame = aBuilder->ToReferenceFrame(aFrame); michael@0: } michael@0: nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, michael@0: const nsIFrame* aReferenceFrame, michael@0: const nsPoint& aToReferenceFrame) michael@0: : mFrame(aFrame) michael@0: , mClip(aBuilder->ClipState().GetCurrentCombinedClip(aBuilder)) michael@0: , mReferenceFrame(aReferenceFrame) michael@0: , mToReferenceFrame(aToReferenceFrame) michael@0: , mInFixedPos(aBuilder->IsInFixedPos()) michael@0: #ifdef MOZ_DUMP_PAINTING michael@0: , mPainted(false) michael@0: #endif michael@0: { michael@0: } michael@0: /** michael@0: * This constructor is only used in rare cases when we need to construct michael@0: * temporary items. michael@0: */ michael@0: nsDisplayItem(nsIFrame* aFrame) michael@0: : mFrame(aFrame) michael@0: , mClip(nullptr) michael@0: , mReferenceFrame(nullptr) michael@0: , mInFixedPos(false) michael@0: #ifdef MOZ_DUMP_PAINTING michael@0: , mPainted(false) michael@0: #endif michael@0: { michael@0: } michael@0: virtual ~nsDisplayItem() {} michael@0: michael@0: void* operator new(size_t aSize, michael@0: nsDisplayListBuilder* aBuilder) CPP_THROW_NEW { michael@0: return aBuilder->Allocate(aSize); michael@0: } michael@0: michael@0: // Contains all the type integers for each display list item type michael@0: #include "nsDisplayItemTypes.h" michael@0: michael@0: struct HitTestState { michael@0: typedef nsTArray ShadowArray; michael@0: michael@0: HitTestState(ShadowArray* aShadows = nullptr) michael@0: : mShadows(aShadows) { michael@0: } michael@0: michael@0: ~HitTestState() { michael@0: NS_ASSERTION(mItemBuffer.Length() == 0, michael@0: "mItemBuffer should have been cleared"); michael@0: } michael@0: michael@0: nsAutoTArray mItemBuffer; michael@0: michael@0: // It is sometimes useful to hit test for frames that are not in this michael@0: // process. Display items may append IDs into this array if it is michael@0: // non-null. michael@0: ShadowArray* mShadows; michael@0: }; michael@0: michael@0: /** michael@0: * Some consecutive items should be rendered together as a unit, e.g., michael@0: * outlines for the same element. For this, we need a way for items to michael@0: * identify their type. We use the type for other purposes too. michael@0: */ michael@0: virtual Type GetType() = 0; michael@0: /** michael@0: * Pairing this with the GetUnderlyingFrame() pointer gives a key that michael@0: * uniquely identifies this display item in the display item tree. michael@0: * XXX check ScrollLayerWrapper/nsOptionEventGrabberWrapper/nsXULEventRedirectorWrapper michael@0: */ michael@0: virtual uint32_t GetPerFrameKey() { return uint32_t(GetType()); } michael@0: /** michael@0: * This is called after we've constructed a display list for event handling. michael@0: * When this is called, we've already ensured that aRect intersects the michael@0: * item's bounds and that clipping has been taking into account. michael@0: * michael@0: * @param aRect the point or rect being tested, relative to the reference michael@0: * frame. If the width and height are both 1 app unit, it indicates we're michael@0: * hit testing a point, not a rect. michael@0: * @param aState must point to a HitTestState. If you don't have one, michael@0: * just create one with the default constructor and pass it in. michael@0: * @param aOutFrames each item appends the frame(s) in this display item that michael@0: * the rect is considered over (if any) to aOutFrames. michael@0: */ michael@0: virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, michael@0: HitTestState* aState, nsTArray *aOutFrames) {} michael@0: /** michael@0: * @return the frame that this display item is based on. This is used to sort michael@0: * items by z-index and content order and for some other uses. Never michael@0: * returns null. michael@0: */ michael@0: inline nsIFrame* Frame() const { return mFrame; } michael@0: /** michael@0: * Compute the used z-index of our frame; returns zero for elements to which michael@0: * z-index does not apply, and for z-index:auto. michael@0: * @note This can be overridden, @see nsDisplayWrapList::SetOverrideZIndex. michael@0: */ michael@0: virtual int32_t ZIndex() const; michael@0: /** michael@0: * The default bounds is the frame border rect. michael@0: * @param aSnap *aSnap is set to true if the returned rect will be michael@0: * snapped to nearest device pixel edges during actual drawing. michael@0: * It might be set to false and snap anyway, so code computing the set of michael@0: * pixels affected by this display item needs to round outwards to pixel michael@0: * boundaries when *aSnap is set to false. michael@0: * This does not take the item's clipping into account. michael@0: * @return a rectangle relative to aBuilder->ReferenceFrame() that michael@0: * contains the area drawn by this display item michael@0: */ michael@0: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) michael@0: { michael@0: *aSnap = false; michael@0: return nsRect(ToReferenceFrame(), Frame()->GetSize()); michael@0: } michael@0: /** michael@0: * Returns the result of GetBounds intersected with the item's clip. michael@0: * The intersection is approximate since rounded corners are not taking into michael@0: * account. michael@0: */ michael@0: nsRect GetClippedBounds(nsDisplayListBuilder* aBuilder); michael@0: nsRect GetBorderRect() { michael@0: return nsRect(ToReferenceFrame(), Frame()->GetSize()); michael@0: } michael@0: nsRect GetPaddingRect() { michael@0: return Frame()->GetPaddingRectRelativeToSelf() + ToReferenceFrame(); michael@0: } michael@0: nsRect GetContentRect() { michael@0: return Frame()->GetContentRectRelativeToSelf() + ToReferenceFrame(); michael@0: } michael@0: michael@0: /** michael@0: * Checks if the frame(s) owning this display item have been marked as invalid, michael@0: * and needing repainting. michael@0: */ michael@0: virtual bool IsInvalid(nsRect& aRect) { michael@0: bool result = mFrame ? mFrame->IsInvalid(aRect) : false; michael@0: aRect += ToReferenceFrame(); michael@0: return result; michael@0: } michael@0: michael@0: /** michael@0: * Creates and initializes an nsDisplayItemGeometry object that retains the current michael@0: * areas covered by this display item. These need to retain enough information michael@0: * such that they can be compared against a future nsDisplayItem of the same type, michael@0: * and determine if repainting needs to happen. michael@0: * michael@0: * Subclasses wishing to store more information need to override both this michael@0: * and ComputeInvalidationRegion, as well as implementing an nsDisplayItemGeometry michael@0: * subclass. michael@0: * michael@0: * The default implementation tracks both the display item bounds, and the frame's michael@0: * border rect. michael@0: */ michael@0: virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) michael@0: { michael@0: return new nsDisplayItemGenericGeometry(this, aBuilder); michael@0: } michael@0: michael@0: /** michael@0: * Compares an nsDisplayItemGeometry object from a previous paint against the michael@0: * current item. Computes if the geometry of the item has changed, and the michael@0: * invalidation area required for correct repainting. michael@0: * michael@0: * The existing geometry will have been created from a display item with a michael@0: * matching GetPerFrameKey()/mFrame pair to the current item. michael@0: * michael@0: * The default implementation compares the display item bounds, and the frame's michael@0: * border rect, and invalidates the entire bounds if either rect changes. michael@0: * michael@0: * @param aGeometry The geometry of the matching display item from the michael@0: * previous paint. michael@0: * @param aInvalidRegion Output param, the region to invalidate, or michael@0: * unchanged if none. michael@0: */ michael@0: virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, michael@0: const nsDisplayItemGeometry* aGeometry, michael@0: nsRegion* aInvalidRegion) michael@0: { michael@0: const nsDisplayItemGenericGeometry* geometry = static_cast(aGeometry); michael@0: bool snap; michael@0: if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) || michael@0: !geometry->mBorderRect.IsEqualInterior(GetBorderRect())) { michael@0: aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * An alternative default implementation of ComputeInvalidationRegion, michael@0: * that instead invalidates only the changed area between the two items. michael@0: */ michael@0: void ComputeInvalidationRegionDifference(nsDisplayListBuilder* aBuilder, michael@0: const nsDisplayItemBoundsGeometry* aGeometry, michael@0: nsRegion* aInvalidRegion) michael@0: { michael@0: bool snap; michael@0: nsRect bounds = GetBounds(aBuilder, &snap); michael@0: michael@0: if (!aGeometry->mBounds.IsEqualInterior(bounds)) { michael@0: nscoord radii[8]; michael@0: if (aGeometry->mHasRoundedCorners || michael@0: Frame()->GetBorderRadii(radii)) { michael@0: aInvalidRegion->Or(aGeometry->mBounds, bounds); michael@0: } else { michael@0: aInvalidRegion->Xor(aGeometry->mBounds, bounds); michael@0: } michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * For display items types that just draw a background we use this function michael@0: * to do any invalidation that might be needed if we are asked to sync decode michael@0: * images. michael@0: */ michael@0: void AddInvalidRegionForSyncDecodeBackgroundImages( michael@0: nsDisplayListBuilder* aBuilder, michael@0: const nsDisplayItemGeometry* aGeometry, michael@0: nsRegion* aInvalidRegion); michael@0: michael@0: /** michael@0: * Called when the area rendered by this display item has changed (been michael@0: * invalidated or changed geometry) since the last paint. This includes michael@0: * when the display item was not rendered at all in the last paint. michael@0: * It does NOT get called when a display item was being rendered and no michael@0: * longer is, because generally that means there is no display item to michael@0: * call this method on. michael@0: */ michael@0: virtual void NotifyRenderingChanged() {} michael@0: michael@0: /** michael@0: * @param aSnap set to true if the edges of the rectangles of the opaque michael@0: * region would be snapped to device pixels when drawing michael@0: * @return a region of the item that is opaque --- that is, every pixel michael@0: * that is visible (according to ComputeVisibility) is painted with an opaque michael@0: * color. This is useful for determining when one piece michael@0: * of content completely obscures another so that we can do occlusion michael@0: * culling. michael@0: * This does not take clipping into account. michael@0: */ michael@0: virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, michael@0: bool* aSnap) michael@0: { michael@0: *aSnap = false; michael@0: return nsRegion(); michael@0: } michael@0: /** michael@0: * If this returns true, then aColor is set to the uniform color michael@0: * @return true if the item is guaranteed to paint every pixel in its michael@0: * bounds with the same (possibly translucent) color michael@0: */ michael@0: virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) { return false; } michael@0: /** michael@0: * @return false if the painting performed by the item is invariant michael@0: * when the item's underlying frame is moved relative to aFrame. michael@0: * In other words, if you render the item at locations P and P', the rendering michael@0: * only differs by the translation. michael@0: * It return true for all wrapped lists. michael@0: */ michael@0: virtual bool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder, michael@0: nsIFrame* aFrame) michael@0: { return false; } michael@0: /** michael@0: * @return true if the contents of this item are rendered fixed relative michael@0: * to the nearest viewport. michael@0: */ michael@0: virtual bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder) michael@0: { return false; } michael@0: michael@0: /** michael@0: * Returns true if all layers that can be active should be forced to be michael@0: * active. Requires setting the pref layers.force-active=true. michael@0: */ michael@0: static bool ForceActiveLayers(); michael@0: michael@0: /** michael@0: * Returns the maximum number of layers that should be created michael@0: * or -1 for no limit. Requires setting the pref layers.max-acitve. michael@0: */ michael@0: static int32_t MaxActiveLayers(); michael@0: michael@0: /** michael@0: * @return LAYER_NONE if BuildLayer will return null. In this case michael@0: * there is no layer for the item, and Paint should be called instead michael@0: * to paint the content using Thebes. michael@0: * Return LAYER_INACTIVE if there is a layer --- BuildLayer will michael@0: * not return null (unless there's an error) --- but the layer contents michael@0: * are not changing frequently. In this case it makes sense to composite michael@0: * the layer into a ThebesLayer with other content, so we don't have to michael@0: * recomposite it every time we paint. michael@0: * Note: GetLayerState is only allowed to return LAYER_INACTIVE if all michael@0: * descendant display items returned LAYER_INACTIVE or LAYER_NONE. Also, michael@0: * all descendant display item frames must have an active scrolled root michael@0: * that's either the same as this item's frame's active scrolled root, or michael@0: * a descendant of this item's frame. This ensures that the entire michael@0: * set of display items can be collapsed onto a single ThebesLayer. michael@0: * Return LAYER_ACTIVE if the layer is active, that is, its contents are michael@0: * changing frequently. In this case it makes sense to keep the layer michael@0: * as a separate buffer in VRAM and composite it into the destination michael@0: * every time we paint. michael@0: * michael@0: * Users of GetLayerState should check ForceActiveLayers() and if it returns michael@0: * true, change a returned value of LAYER_INACTIVE to LAYER_ACTIVE. michael@0: */ michael@0: virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aParameters) michael@0: { return mozilla::LAYER_NONE; } michael@0: /** michael@0: * Return true to indicate the layer should be constructed even if it's michael@0: * completely invisible. michael@0: */ michael@0: virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) michael@0: { return false; } michael@0: /** michael@0: * Actually paint this item to some rendering context. michael@0: * Content outside mVisibleRect need not be painted. michael@0: * aCtx must be set up as for nsDisplayList::Paint. michael@0: */ michael@0: virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) {} michael@0: michael@0: #ifdef MOZ_DUMP_PAINTING michael@0: /** michael@0: * Mark this display item as being painted via FrameLayerBuilder::DrawThebesLayer. michael@0: */ michael@0: bool Painted() { return mPainted; } michael@0: michael@0: /** michael@0: * Check if this display item has been painted. michael@0: */ michael@0: void SetPainted() { mPainted = true; } michael@0: #endif michael@0: michael@0: /** michael@0: * Get the layer drawn by this display item. Call this only if michael@0: * GetLayerState() returns something other than LAYER_NONE. michael@0: * If GetLayerState returned LAYER_NONE then Paint will be called michael@0: * instead. michael@0: * This is called while aManager is in the construction phase. michael@0: * michael@0: * The caller (nsDisplayList) is responsible for setting the visible michael@0: * region of the layer. michael@0: * michael@0: * @param aContainerParameters should be passed to michael@0: * FrameLayerBuilder::BuildContainerLayerFor if a ContainerLayer is michael@0: * constructed. michael@0: */ michael@0: virtual already_AddRefed BuildLayer(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aContainerParameters) michael@0: { return nullptr; } michael@0: michael@0: /** michael@0: * On entry, aVisibleRegion contains the region (relative to ReferenceFrame()) michael@0: * which may be visible. If the display item opaquely covers an area, it michael@0: * can remove that area from aVisibleRegion before returning. michael@0: * nsDisplayList::ComputeVisibility automatically subtracts the region michael@0: * returned by GetOpaqueRegion, and automatically removes items whose bounds michael@0: * do not intersect the visible area, so implementations of michael@0: * nsDisplayItem::ComputeVisibility do not need to do these things. michael@0: * nsDisplayList::ComputeVisibility will already have set mVisibleRect on michael@0: * this item to the intersection of *aVisibleRegion and this item's bounds. michael@0: * We rely on that, so this should only be called by michael@0: * nsDisplayList::ComputeVisibility or nsDisplayItem::RecomputeVisibility. michael@0: * aAllowVisibleRegionExpansion is a rect where we are allowed to michael@0: * expand the visible region and is only used for making sure the michael@0: * background behind a plugin is visible. michael@0: * This method needs to be idempotent. michael@0: * michael@0: * @return true if the item is visible, false if no part of the item michael@0: * is visible. michael@0: */ michael@0: virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, michael@0: nsRegion* aVisibleRegion, michael@0: const nsRect& aAllowVisibleRegionExpansion) michael@0: { return !mVisibleRect.IsEmpty(); } michael@0: michael@0: /** michael@0: * Try to merge with the other item (which is below us in the display michael@0: * list). This gets used by nsDisplayClip to coalesce clipping operations michael@0: * (optimization), by nsDisplayOpacity to merge rendering for the same michael@0: * content element into a single opacity group (correctness), and will be michael@0: * used by nsDisplayOutline to merge multiple outlines for the same element michael@0: * (also for correctness). michael@0: * @return true if the merge was successful and the other item should be deleted michael@0: */ michael@0: virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) { michael@0: return false; michael@0: } michael@0: michael@0: /** michael@0: * Appends the underlying frames of all display items that have been michael@0: * merged into this one (excluding this item's own underlying frame) michael@0: * to aFrames. michael@0: */ michael@0: virtual void GetMergedFrames(nsTArray* aFrames) {} michael@0: michael@0: /** michael@0: * During the visibility computation and after TryMerge, display lists may michael@0: * return true here to flatten themselves away, removing them. This michael@0: * flattening is distinctly different from FlattenTo, which occurs before michael@0: * items are merged together. michael@0: */ michael@0: virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) { michael@0: return false; michael@0: } michael@0: michael@0: /** michael@0: * If this has a child list where the children are in the same coordinate michael@0: * system as this item (i.e., they have the same reference frame), michael@0: * return the list. michael@0: */ michael@0: virtual nsDisplayList* GetSameCoordinateSystemChildren() { return nullptr; } michael@0: virtual void UpdateBounds(nsDisplayListBuilder* aBuilder) {} michael@0: michael@0: /** michael@0: * If this has a child list, return it, even if the children are in michael@0: * a different coordinate system to this item. michael@0: */ michael@0: virtual nsDisplayList* GetChildren() { return nullptr; } michael@0: michael@0: /** michael@0: * Returns the visible rect. Should only be called after ComputeVisibility michael@0: * has happened. michael@0: */ michael@0: const nsRect& GetVisibleRect() { return mVisibleRect; } michael@0: michael@0: /** michael@0: * Stores the given opacity value to be applied when drawing. Returns michael@0: * false if this isn't supported for this display item. michael@0: */ michael@0: virtual bool ApplyOpacity(nsDisplayListBuilder* aBuilder, michael@0: float aOpacity, michael@0: const DisplayItemClip* aClip) { michael@0: return false; michael@0: } michael@0: michael@0: #ifdef MOZ_DUMP_PAINTING michael@0: /** michael@0: * For debugging and stuff michael@0: */ michael@0: virtual const char* Name() = 0; michael@0: michael@0: virtual void WriteDebugInfo(nsACString& aTo) {} michael@0: #endif michael@0: michael@0: nsDisplayItem* GetAbove() { return mAbove; } michael@0: michael@0: /** michael@0: * Like ComputeVisibility, but does the work that nsDisplayList michael@0: * does per-item: michael@0: * -- Intersects GetBounds with aVisibleRegion and puts the result michael@0: * in mVisibleRect michael@0: * -- Subtracts bounds from aVisibleRegion if the item is opaque michael@0: */ michael@0: bool RecomputeVisibility(nsDisplayListBuilder* aBuilder, michael@0: nsRegion* aVisibleRegion); michael@0: michael@0: /** michael@0: * Returns the result of aBuilder->ToReferenceFrame(GetUnderlyingFrame()) michael@0: */ michael@0: const nsPoint& ToReferenceFrame() const { michael@0: NS_ASSERTION(mFrame, "No frame?"); michael@0: return mToReferenceFrame; michael@0: } michael@0: /** michael@0: * @return the root of the display list's frame (sub)tree, whose origin michael@0: * establishes the coordinate system for the display list michael@0: */ michael@0: const nsIFrame* ReferenceFrame() const { return mReferenceFrame; } michael@0: michael@0: /** michael@0: * Returns the reference frame for display item children of this item. michael@0: */ michael@0: virtual const nsIFrame* ReferenceFrameForChildren() const { return mReferenceFrame; } michael@0: michael@0: /** michael@0: * Checks if this display item (or any children) contains content that might michael@0: * be rendered with component alpha (e.g. subpixel antialiasing). Returns the michael@0: * bounds of the area that needs component alpha, or an empty rect if nothing michael@0: * in the item does. michael@0: */ michael@0: virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) { return nsRect(); } michael@0: michael@0: /** michael@0: * Disable usage of component alpha. Currently only relevant for items that have text. michael@0: */ michael@0: virtual void DisableComponentAlpha() {} michael@0: michael@0: /** michael@0: * Check if we can add async animations to the layer for this display item. michael@0: */ michael@0: virtual bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) { michael@0: return false; michael@0: } michael@0: michael@0: virtual bool SupportsOptimizingToImage() { return false; } michael@0: michael@0: const DisplayItemClip& GetClip() michael@0: { michael@0: return mClip ? *mClip : DisplayItemClip::NoClip(); michael@0: } michael@0: void SetClip(nsDisplayListBuilder* aBuilder, const DisplayItemClip& aClip) michael@0: { michael@0: if (!aClip.HasClip()) { michael@0: mClip = nullptr; michael@0: return; michael@0: } michael@0: mClip = aBuilder->AllocateDisplayItemClip(aClip); michael@0: } michael@0: michael@0: void IntersectClip(nsDisplayListBuilder* aBuilder, const DisplayItemClip& aClip) michael@0: { michael@0: if (mClip) { michael@0: DisplayItemClip temp = *mClip; michael@0: temp.IntersectWith(aClip); michael@0: SetClip(aBuilder, temp); michael@0: } else { michael@0: SetClip(aBuilder, aClip); michael@0: } michael@0: } michael@0: michael@0: // If we return false here it means that if this item creates a layer then michael@0: // ProcessDisplayItems will not set the visible region on the layer. The item michael@0: // should set the visible region, usually in BuildContainerLayer. michael@0: virtual bool SetVisibleRegionOnLayer() { return true; } michael@0: michael@0: bool IsInFixedPos() { return mInFixedPos; } michael@0: michael@0: protected: michael@0: friend class nsDisplayList; michael@0: michael@0: nsDisplayItem() { mAbove = nullptr; } michael@0: michael@0: nsIFrame* mFrame; michael@0: const DisplayItemClip* mClip; michael@0: // Result of FindReferenceFrameFor(mFrame), if mFrame is non-null michael@0: const nsIFrame* mReferenceFrame; michael@0: // Result of ToReferenceFrame(mFrame), if mFrame is non-null michael@0: nsPoint mToReferenceFrame; michael@0: // This is the rectangle that needs to be painted. michael@0: // nsDisplayList::ComputeVisibility sets this to the visible region michael@0: // of the item by intersecting the current visible region with the bounds michael@0: // of the item. Paint implementations can use this to limit their drawing. michael@0: // Guaranteed to be contained in GetBounds(). michael@0: nsRect mVisibleRect; michael@0: bool mInFixedPos; michael@0: #ifdef MOZ_DUMP_PAINTING michael@0: // True if this frame has been painted. michael@0: bool mPainted; michael@0: #endif michael@0: }; michael@0: michael@0: /** michael@0: * Manages a singly-linked list of display list items. michael@0: * michael@0: * mSentinel is the sentinel list value, the first value in the null-terminated michael@0: * linked list of items. mTop is the last item in the list (whose 'above' michael@0: * pointer is null). This class has no virtual methods. So list objects are just michael@0: * two pointers. michael@0: * michael@0: * Stepping upward through this list is very fast. Stepping downward is very michael@0: * slow so we don't support it. The methods that need to step downward michael@0: * (HitTest(), ComputeVisibility()) internally build a temporary array of all michael@0: * the items while they do the downward traversal, so overall they're still michael@0: * linear time. We have optimized for efficient AppendToTop() of both michael@0: * items and lists, with minimal codesize. AppendToBottom() is efficient too. michael@0: */ michael@0: class nsDisplayList { michael@0: public: michael@0: typedef mozilla::layers::Layer Layer; michael@0: typedef mozilla::layers::LayerManager LayerManager; michael@0: typedef mozilla::layers::ThebesLayer ThebesLayer; michael@0: michael@0: /** michael@0: * Create an empty list. michael@0: */ michael@0: nsDisplayList() : michael@0: mIsOpaque(false) michael@0: { michael@0: mTop = &mSentinel; michael@0: mSentinel.mAbove = nullptr; michael@0: #if defined(DEBUG) || defined(MOZ_DUMP_PAINTING) michael@0: mDidComputeVisibility = false; michael@0: #endif michael@0: } michael@0: ~nsDisplayList() { michael@0: if (mSentinel.mAbove) { michael@0: NS_WARNING("Nonempty list left over?"); michael@0: } michael@0: DeleteAll(); michael@0: } michael@0: michael@0: /** michael@0: * Append an item to the top of the list. The item must not currently michael@0: * be in a list and cannot be null. michael@0: */ michael@0: void AppendToTop(nsDisplayItem* aItem) { michael@0: NS_ASSERTION(aItem, "No item to append!"); michael@0: NS_ASSERTION(!aItem->mAbove, "Already in a list!"); michael@0: mTop->mAbove = aItem; michael@0: mTop = aItem; michael@0: } michael@0: michael@0: /** michael@0: * Append a new item to the top of the list. If the item is null we return michael@0: * NS_ERROR_OUT_OF_MEMORY. The intended usage is AppendNewToTop(new ...); michael@0: */ michael@0: void AppendNewToTop(nsDisplayItem* aItem) { michael@0: if (aItem) { michael@0: AppendToTop(aItem); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Append a new item to the bottom of the list. If the item is null we return michael@0: * NS_ERROR_OUT_OF_MEMORY. The intended usage is AppendNewToBottom(new ...); michael@0: */ michael@0: void AppendNewToBottom(nsDisplayItem* aItem) { michael@0: if (aItem) { michael@0: AppendToBottom(aItem); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Append a new item to the bottom of the list. The item must be non-null michael@0: * and not already in a list. michael@0: */ michael@0: void AppendToBottom(nsDisplayItem* aItem) { michael@0: NS_ASSERTION(aItem, "No item to append!"); michael@0: NS_ASSERTION(!aItem->mAbove, "Already in a list!"); michael@0: aItem->mAbove = mSentinel.mAbove; michael@0: mSentinel.mAbove = aItem; michael@0: if (mTop == &mSentinel) { michael@0: mTop = aItem; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Removes all items from aList and appends them to the top of this list michael@0: */ michael@0: void AppendToTop(nsDisplayList* aList) { michael@0: if (aList->mSentinel.mAbove) { michael@0: mTop->mAbove = aList->mSentinel.mAbove; michael@0: mTop = aList->mTop; michael@0: aList->mTop = &aList->mSentinel; michael@0: aList->mSentinel.mAbove = nullptr; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Removes all items from aList and prepends them to the bottom of this list michael@0: */ michael@0: void AppendToBottom(nsDisplayList* aList) { michael@0: if (aList->mSentinel.mAbove) { michael@0: aList->mTop->mAbove = mSentinel.mAbove; michael@0: mSentinel.mAbove = aList->mSentinel.mAbove; michael@0: if (mTop == &mSentinel) { michael@0: mTop = aList->mTop; michael@0: } michael@0: michael@0: aList->mTop = &aList->mSentinel; michael@0: aList->mSentinel.mAbove = nullptr; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Remove an item from the bottom of the list and return it. michael@0: */ michael@0: nsDisplayItem* RemoveBottom(); michael@0: michael@0: /** michael@0: * Remove all items from the list and call their destructors. michael@0: */ michael@0: void DeleteAll(); michael@0: michael@0: /** michael@0: * @return the item at the top of the list, or null if the list is empty michael@0: */ michael@0: nsDisplayItem* GetTop() const { michael@0: return mTop != &mSentinel ? static_cast(mTop) : nullptr; michael@0: } michael@0: /** michael@0: * @return the item at the bottom of the list, or null if the list is empty michael@0: */ michael@0: nsDisplayItem* GetBottom() const { return mSentinel.mAbove; } michael@0: bool IsEmpty() const { return mTop == &mSentinel; } michael@0: michael@0: /** michael@0: * This is *linear time*! michael@0: * @return the number of items in the list michael@0: */ michael@0: uint32_t Count() const; michael@0: /** michael@0: * Stable sort the list by the z-order of GetUnderlyingFrame() on michael@0: * each item. 'auto' is counted as zero. Content order is used as the michael@0: * secondary order. michael@0: * @param aCommonAncestor a common ancestor of all the content elements michael@0: * associated with the display items, for speeding up tree order michael@0: * checks, or nullptr if not known; it's only a hint, if it is not an michael@0: * ancestor of some elements, then we lose performance but not correctness michael@0: */ michael@0: void SortByZOrder(nsDisplayListBuilder* aBuilder, nsIContent* aCommonAncestor); michael@0: /** michael@0: * Stable sort the list by the tree order of the content of michael@0: * GetUnderlyingFrame() on each item. z-index is ignored. michael@0: * @param aCommonAncestor a common ancestor of all the content elements michael@0: * associated with the display items, for speeding up tree order michael@0: * checks, or nullptr if not known; it's only a hint, if it is not an michael@0: * ancestor of some elements, then we lose performance but not correctness michael@0: */ michael@0: void SortByContentOrder(nsDisplayListBuilder* aBuilder, nsIContent* aCommonAncestor); michael@0: michael@0: /** michael@0: * Generic stable sort. Take care, because some of the items might be nsDisplayLists michael@0: * themselves. michael@0: * aCmp(item1, item2) should return true if item1 <= item2. We sort the items michael@0: * into increasing order. michael@0: */ michael@0: typedef bool (* SortLEQ)(nsDisplayItem* aItem1, nsDisplayItem* aItem2, michael@0: void* aClosure); michael@0: void Sort(nsDisplayListBuilder* aBuilder, SortLEQ aCmp, void* aClosure); michael@0: michael@0: /** michael@0: * Compute visiblity for the items in the list. michael@0: * We put this logic here so it can be shared by top-level michael@0: * painting and also display items that maintain child lists. michael@0: * This is also a good place to put ComputeVisibility-related logic michael@0: * that must be applied to every display item. In particular, this michael@0: * sets mVisibleRect on each display item. michael@0: * This sets mIsOpaque if the entire visible area of this list has michael@0: * been removed from aVisibleRegion when we return. michael@0: * This does not remove any items from the list, so we can recompute michael@0: * visiblity with different regions later (see michael@0: * FrameLayerBuilder::DrawThebesLayer). michael@0: * This method needs to be idempotent. michael@0: * michael@0: * @param aVisibleRegion the area that is visible, relative to the michael@0: * reference frame; on return, this contains the area visible under the list. michael@0: * I.e., opaque contents of this list are subtracted from aVisibleRegion. michael@0: * @param aListVisibleBounds must be equal to the bounds of the intersection michael@0: * of aVisibleRegion and GetBounds() for this list. michael@0: * @param aDisplayPortFrame If the item for which this list corresponds is michael@0: * within a displayport, the scroll frame for which that display port michael@0: * applies. For root scroll frames, you can pass the the root frame instead. michael@0: * @return true if any item in the list is visible. michael@0: */ michael@0: bool ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder, michael@0: nsRegion* aVisibleRegion, michael@0: const nsRect& aListVisibleBounds, michael@0: const nsRect& aAllowVisibleRegionExpansion, michael@0: nsIFrame* aDisplayPortFrame = nullptr); michael@0: michael@0: /** michael@0: * As ComputeVisibilityForSublist, but computes visibility for a root michael@0: * list (a list that does not belong to an nsDisplayItem). michael@0: * This method needs to be idempotent. michael@0: * michael@0: * @param aVisibleRegion the area that is visible michael@0: * @param aDisplayPortFrame The root scroll frame, if a displayport is set michael@0: */ michael@0: bool ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder, michael@0: nsRegion* aVisibleRegion, michael@0: nsIFrame* aDisplayPortFrame = nullptr); michael@0: michael@0: /** michael@0: * Returns true if the visible region output from ComputeVisiblity was michael@0: * empty, i.e. everything visible in this list is opaque. michael@0: */ michael@0: bool IsOpaque() const { michael@0: NS_ASSERTION(mDidComputeVisibility, "Need to have called ComputeVisibility"); michael@0: return mIsOpaque; michael@0: } michael@0: michael@0: /** michael@0: * Returns true if during ComputeVisibility any display item michael@0: * set the surface to be transparent. michael@0: */ michael@0: bool NeedsTransparentSurface() const { michael@0: NS_ASSERTION(mDidComputeVisibility, "Need to have called ComputeVisibility"); michael@0: return mForceTransparentSurface; michael@0: } michael@0: /** michael@0: * Paint the list to the rendering context. We assume that (0,0) in aCtx michael@0: * corresponds to the origin of the reference frame. For best results, michael@0: * aCtx's current transform should make (0,0) pixel-aligned. The michael@0: * rectangle in aDirtyRect is painted, which *must* be contained in the michael@0: * dirty rect used to construct the display list. michael@0: * michael@0: * If aFlags contains PAINT_USE_WIDGET_LAYERS and michael@0: * ShouldUseWidgetLayerManager() is set, then we will paint using michael@0: * the reference frame's widget's layer manager (and ctx may be null), michael@0: * otherwise we will use a temporary BasicLayerManager and ctx must michael@0: * not be null. michael@0: * michael@0: * If PAINT_FLUSH_LAYERS is set, we'll force a completely new layer michael@0: * tree to be created for this paint *and* the next paint. michael@0: * michael@0: * If PAINT_EXISTING_TRANSACTION is set, the reference frame's widget's michael@0: * layer manager has already had BeginTransaction() called on it and michael@0: * we should not call it again. michael@0: * michael@0: * If PAINT_COMPRESSED is set, the FrameLayerBuilder should be set to compressed mode michael@0: * to avoid short cut optimizations. michael@0: * michael@0: * ComputeVisibility must be called before Paint. michael@0: * michael@0: * This must only be called on the root display list of the display list michael@0: * tree. michael@0: */ michael@0: enum { michael@0: PAINT_DEFAULT = 0, michael@0: PAINT_USE_WIDGET_LAYERS = 0x01, michael@0: PAINT_FLUSH_LAYERS = 0x02, michael@0: PAINT_EXISTING_TRANSACTION = 0x04, michael@0: PAINT_NO_COMPOSITE = 0x08, michael@0: PAINT_COMPRESSED = 0x10 michael@0: }; michael@0: void PaintRoot(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx, michael@0: uint32_t aFlags) const; michael@0: /** michael@0: * Like PaintRoot, but used for internal display sublists. michael@0: * aForFrame is the frame that the list is associated with. michael@0: */ michael@0: void PaintForFrame(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx, michael@0: nsIFrame* aForFrame, uint32_t aFlags) const; michael@0: /** michael@0: * Get the bounds. Takes the union of the bounds of all children. michael@0: */ michael@0: nsRect GetBounds(nsDisplayListBuilder* aBuilder) const; michael@0: /** michael@0: * Find the topmost display item that returns a non-null frame, and return michael@0: * the frame. michael@0: */ michael@0: void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, michael@0: nsDisplayItem::HitTestState* aState, michael@0: nsTArray *aOutFrames) const; michael@0: michael@0: #if defined(DEBUG) || defined(MOZ_DUMP_PAINTING) michael@0: bool DidComputeVisibility() const { return mDidComputeVisibility; } michael@0: #endif michael@0: michael@0: nsRect GetVisibleRect() const { return mVisibleRect; } michael@0: michael@0: private: michael@0: // This class is only used on stack, so we don't have to worry about leaking michael@0: // it. Don't let us be heap-allocated! michael@0: void* operator new(size_t sz) CPP_THROW_NEW; michael@0: michael@0: // Utility function used to massage the list during ComputeVisibility. michael@0: void FlattenTo(nsTArray* aElements); michael@0: michael@0: nsDisplayItemLink mSentinel; michael@0: nsDisplayItemLink* mTop; michael@0: michael@0: // This is set by ComputeVisibility michael@0: nsRect mVisibleRect; michael@0: // This is set to true by ComputeVisibility if the final visible region michael@0: // is empty (i.e. everything that was visible is covered by some michael@0: // opaque content in this list). michael@0: bool mIsOpaque; michael@0: // This is set to true by ComputeVisibility if any display item in this michael@0: // list needs to force the surface containing this list to be transparent. michael@0: bool mForceTransparentSurface; michael@0: #if defined(DEBUG) || defined(MOZ_DUMP_PAINTING) michael@0: bool mDidComputeVisibility; michael@0: #endif michael@0: }; michael@0: michael@0: /** michael@0: * This is passed as a parameter to nsIFrame::BuildDisplayList. That method michael@0: * will put any generated items onto the appropriate list given here. It's michael@0: * basically just a collection with one list for each separate stacking layer. michael@0: * The lists themselves are external to this object and thus can be shared michael@0: * with others. Some of the list pointers may even refer to the same list. michael@0: */ michael@0: class nsDisplayListSet { michael@0: public: michael@0: /** michael@0: * @return a list where one should place the border and/or background for michael@0: * this frame (everything from steps 1 and 2 of CSS 2.1 appendix E) michael@0: */ michael@0: nsDisplayList* BorderBackground() const { return mBorderBackground; } michael@0: /** michael@0: * @return a list where one should place the borders and/or backgrounds for michael@0: * block-level in-flow descendants (step 4 of CSS 2.1 appendix E) michael@0: */ michael@0: nsDisplayList* BlockBorderBackgrounds() const { return mBlockBorderBackgrounds; } michael@0: /** michael@0: * @return a list where one should place descendant floats (step 5 of michael@0: * CSS 2.1 appendix E) michael@0: */ michael@0: nsDisplayList* Floats() const { return mFloats; } michael@0: /** michael@0: * @return a list where one should place the (pseudo) stacking contexts michael@0: * for descendants of this frame (everything from steps 3, 7 and 8 michael@0: * of CSS 2.1 appendix E) michael@0: */ michael@0: nsDisplayList* PositionedDescendants() const { return mPositioned; } michael@0: /** michael@0: * @return a list where one should place the outlines michael@0: * for this frame and its descendants (step 9 of CSS 2.1 appendix E) michael@0: */ michael@0: nsDisplayList* Outlines() const { return mOutlines; } michael@0: /** michael@0: * @return a list where one should place all other content michael@0: */ michael@0: nsDisplayList* Content() const { return mContent; } michael@0: michael@0: nsDisplayListSet(nsDisplayList* aBorderBackground, michael@0: nsDisplayList* aBlockBorderBackgrounds, michael@0: nsDisplayList* aFloats, michael@0: nsDisplayList* aContent, michael@0: nsDisplayList* aPositionedDescendants, michael@0: nsDisplayList* aOutlines) : michael@0: mBorderBackground(aBorderBackground), michael@0: mBlockBorderBackgrounds(aBlockBorderBackgrounds), michael@0: mFloats(aFloats), michael@0: mContent(aContent), michael@0: mPositioned(aPositionedDescendants), michael@0: mOutlines(aOutlines) { michael@0: } michael@0: michael@0: /** michael@0: * A copy constructor that lets the caller override the BorderBackground michael@0: * list. michael@0: */ michael@0: nsDisplayListSet(const nsDisplayListSet& aLists, michael@0: nsDisplayList* aBorderBackground) : michael@0: mBorderBackground(aBorderBackground), michael@0: mBlockBorderBackgrounds(aLists.BlockBorderBackgrounds()), michael@0: mFloats(aLists.Floats()), michael@0: mContent(aLists.Content()), michael@0: mPositioned(aLists.PositionedDescendants()), michael@0: mOutlines(aLists.Outlines()) { michael@0: } michael@0: michael@0: /** michael@0: * Move all display items in our lists to top of the corresponding lists in the michael@0: * destination. michael@0: */ michael@0: void MoveTo(const nsDisplayListSet& aDestination) const; michael@0: michael@0: private: michael@0: // This class is only used on stack, so we don't have to worry about leaking michael@0: // it. Don't let us be heap-allocated! michael@0: void* operator new(size_t sz) CPP_THROW_NEW; michael@0: michael@0: protected: michael@0: nsDisplayList* mBorderBackground; michael@0: nsDisplayList* mBlockBorderBackgrounds; michael@0: nsDisplayList* mFloats; michael@0: nsDisplayList* mContent; michael@0: nsDisplayList* mPositioned; michael@0: nsDisplayList* mOutlines; michael@0: }; michael@0: michael@0: /** michael@0: * A specialization of nsDisplayListSet where the lists are actually internal michael@0: * to the object, and all distinct. michael@0: */ michael@0: struct nsDisplayListCollection : public nsDisplayListSet { michael@0: nsDisplayListCollection() : michael@0: nsDisplayListSet(&mLists[0], &mLists[1], &mLists[2], &mLists[3], &mLists[4], michael@0: &mLists[5]) {} michael@0: nsDisplayListCollection(nsDisplayList* aBorderBackground) : michael@0: nsDisplayListSet(aBorderBackground, &mLists[1], &mLists[2], &mLists[3], &mLists[4], michael@0: &mLists[5]) {} michael@0: michael@0: /** michael@0: * Sort all lists by content order. michael@0: */ michael@0: void SortAllByContentOrder(nsDisplayListBuilder* aBuilder, nsIContent* aCommonAncestor) { michael@0: for (int32_t i = 0; i < 6; ++i) { michael@0: mLists[i].SortByContentOrder(aBuilder, aCommonAncestor); michael@0: } michael@0: } michael@0: michael@0: private: michael@0: // This class is only used on stack, so we don't have to worry about leaking michael@0: // it. Don't let us be heap-allocated! michael@0: void* operator new(size_t sz) CPP_THROW_NEW; michael@0: michael@0: nsDisplayList mLists[6]; michael@0: }; michael@0: michael@0: michael@0: class nsDisplayImageContainer : public nsDisplayItem { michael@0: public: michael@0: typedef mozilla::layers::ImageContainer ImageContainer; michael@0: typedef mozilla::layers::ImageLayer ImageLayer; michael@0: michael@0: nsDisplayImageContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) michael@0: : nsDisplayItem(aBuilder, aFrame) michael@0: {} michael@0: michael@0: virtual already_AddRefed GetContainer(LayerManager* aManager, michael@0: nsDisplayListBuilder* aBuilder) = 0; michael@0: virtual void ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset) = 0; michael@0: michael@0: virtual bool SupportsOptimizingToImage() MOZ_OVERRIDE { return true; } michael@0: }; michael@0: michael@0: /** michael@0: * Use this class to implement not-very-frequently-used display items michael@0: * that are not opaque, do not receive events, and are bounded by a frame's michael@0: * border-rect. michael@0: * michael@0: * This should not be used for display items which are created frequently, michael@0: * because each item is one or two pointers bigger than an item from a michael@0: * custom display item class could be, and fractionally slower. However it does michael@0: * save code size. We use this for infrequently-used item types. michael@0: */ michael@0: class nsDisplayGeneric : public nsDisplayItem { michael@0: public: michael@0: typedef void (* PaintCallback)(nsIFrame* aFrame, nsRenderingContext* aCtx, michael@0: const nsRect& aDirtyRect, nsPoint aFramePt); michael@0: michael@0: nsDisplayGeneric(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, michael@0: PaintCallback aPaint, const char* aName, Type aType) michael@0: : nsDisplayItem(aBuilder, aFrame), mPaint(aPaint) michael@0: #ifdef MOZ_DUMP_PAINTING michael@0: , mName(aName) michael@0: #endif michael@0: , mType(aType) michael@0: { michael@0: MOZ_COUNT_CTOR(nsDisplayGeneric); michael@0: } michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayGeneric() { michael@0: MOZ_COUNT_DTOR(nsDisplayGeneric); michael@0: } michael@0: #endif michael@0: michael@0: virtual void Paint(nsDisplayListBuilder* aBuilder, michael@0: nsRenderingContext* aCtx) MOZ_OVERRIDE { michael@0: mPaint(mFrame, aCtx, mVisibleRect, ToReferenceFrame()); michael@0: } michael@0: NS_DISPLAY_DECL_NAME(mName, mType) michael@0: michael@0: virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE { michael@0: if (mType == nsDisplayItem::TYPE_HEADER_FOOTER) { michael@0: bool snap; michael@0: return GetBounds(aBuilder, &snap); michael@0: } michael@0: return nsRect(); michael@0: } michael@0: michael@0: protected: michael@0: PaintCallback mPaint; michael@0: #ifdef MOZ_DUMP_PAINTING michael@0: const char* mName; michael@0: #endif michael@0: Type mType; michael@0: }; michael@0: michael@0: /** michael@0: * Generic display item that can contain overflow. Use this in lieu of michael@0: * nsDisplayGeneric if you have a frame that should use the visual overflow michael@0: * rect of its frame when drawing items, instead of the frame's bounds. michael@0: */ michael@0: class nsDisplayGenericOverflow : public nsDisplayGeneric { michael@0: public: michael@0: nsDisplayGenericOverflow(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, michael@0: PaintCallback aPaint, const char* aName, Type aType) michael@0: : nsDisplayGeneric(aBuilder, aFrame, aPaint, aName, aType) michael@0: { michael@0: MOZ_COUNT_CTOR(nsDisplayGenericOverflow); michael@0: } michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayGenericOverflow() { michael@0: MOZ_COUNT_DTOR(nsDisplayGenericOverflow); michael@0: } michael@0: #endif michael@0: michael@0: /** michael@0: * Returns the frame's visual overflow rect instead of the frame's bounds. michael@0: */ michael@0: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, michael@0: bool* aSnap) MOZ_OVERRIDE michael@0: { michael@0: *aSnap = false; michael@0: return Frame()->GetVisualOverflowRect() + ToReferenceFrame(); michael@0: } michael@0: }; michael@0: michael@0: #if defined(MOZ_REFLOW_PERF_DSP) && defined(MOZ_REFLOW_PERF) michael@0: /** michael@0: * This class implements painting of reflow counts. Ideally, we would simply michael@0: * make all the frame names be those returned by nsFrame::GetFrameName michael@0: * (except that tosses in the content tag name!) and support only one color michael@0: * and eliminate this class altogether in favor of nsDisplayGeneric, but for michael@0: * the time being we can't pass args to a PaintCallback, so just have a michael@0: * separate class to do the right thing. Sadly, this alsmo means we need to michael@0: * hack all leaf frame classes to handle this. michael@0: * michael@0: * XXXbz the color thing is a bit of a mess, but 0 basically means "not set" michael@0: * here... I could switch it all to nscolor, but why bother? michael@0: */ michael@0: class nsDisplayReflowCount : public nsDisplayItem { michael@0: public: michael@0: nsDisplayReflowCount(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, michael@0: const char* aFrameName, michael@0: uint32_t aColor = 0) michael@0: : nsDisplayItem(aBuilder, aFrame), michael@0: mFrameName(aFrameName), michael@0: mColor(aColor) michael@0: { michael@0: MOZ_COUNT_CTOR(nsDisplayReflowCount); michael@0: } michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayReflowCount() { michael@0: MOZ_COUNT_DTOR(nsDisplayReflowCount); michael@0: } michael@0: #endif michael@0: michael@0: virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE { michael@0: mFrame->PresContext()->PresShell()->PaintCount(mFrameName, aCtx, michael@0: mFrame->PresContext(), michael@0: mFrame, ToReferenceFrame(), michael@0: mColor); michael@0: } michael@0: NS_DISPLAY_DECL_NAME("nsDisplayReflowCount", TYPE_REFLOW_COUNT) michael@0: protected: michael@0: const char* mFrameName; michael@0: nscolor mColor; michael@0: }; michael@0: michael@0: #define DO_GLOBAL_REFLOW_COUNT_DSP(_name) \ michael@0: PR_BEGIN_MACRO \ michael@0: if (!aBuilder->IsBackgroundOnly() && !aBuilder->IsForEventDelivery() && \ michael@0: PresContext()->PresShell()->IsPaintingFrameCounts()) { \ michael@0: aLists.Outlines()->AppendNewToTop( \ michael@0: new (aBuilder) nsDisplayReflowCount(aBuilder, this, _name)); \ michael@0: } \ michael@0: PR_END_MACRO michael@0: michael@0: #define DO_GLOBAL_REFLOW_COUNT_DSP_COLOR(_name, _color) \ michael@0: PR_BEGIN_MACRO \ michael@0: if (!aBuilder->IsBackgroundOnly() && !aBuilder->IsForEventDelivery() && \ michael@0: PresContext()->PresShell()->IsPaintingFrameCounts()) { \ michael@0: aLists.Outlines()->AppendNewToTop( \ michael@0: new (aBuilder) nsDisplayReflowCount(aBuilder, this, _name, _color)); \ michael@0: } \ michael@0: PR_END_MACRO michael@0: michael@0: /* michael@0: Macro to be used for classes that don't actually implement BuildDisplayList michael@0: */ michael@0: #define DECL_DO_GLOBAL_REFLOW_COUNT_DSP(_class, _super) \ michael@0: void BuildDisplayList(nsDisplayListBuilder* aBuilder, \ michael@0: const nsRect& aDirtyRect, \ michael@0: const nsDisplayListSet& aLists) { \ michael@0: DO_GLOBAL_REFLOW_COUNT_DSP(#_class); \ michael@0: _super::BuildDisplayList(aBuilder, aDirtyRect, aLists); \ michael@0: } michael@0: michael@0: #else // MOZ_REFLOW_PERF_DSP && MOZ_REFLOW_PERF michael@0: michael@0: #define DO_GLOBAL_REFLOW_COUNT_DSP(_name) michael@0: #define DO_GLOBAL_REFLOW_COUNT_DSP_COLOR(_name, _color) michael@0: #define DECL_DO_GLOBAL_REFLOW_COUNT_DSP(_class, _super) michael@0: michael@0: #endif // MOZ_REFLOW_PERF_DSP && MOZ_REFLOW_PERF michael@0: michael@0: class nsDisplayCaret : public nsDisplayItem { michael@0: public: michael@0: nsDisplayCaret(nsDisplayListBuilder* aBuilder, nsIFrame* aCaretFrame, michael@0: nsCaret *aCaret) michael@0: : nsDisplayItem(aBuilder, aCaretFrame), mCaret(aCaret) { michael@0: MOZ_COUNT_CTOR(nsDisplayCaret); michael@0: } michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayCaret() { michael@0: MOZ_COUNT_DTOR(nsDisplayCaret); michael@0: } michael@0: #endif michael@0: michael@0: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE { michael@0: *aSnap = false; michael@0: // The caret returns a rect in the coordinates of mFrame. michael@0: return mCaret->GetCaretRect() + ToReferenceFrame(); michael@0: } michael@0: virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE; michael@0: NS_DISPLAY_DECL_NAME("Caret", TYPE_CARET) michael@0: protected: michael@0: nsRefPtr mCaret; michael@0: }; michael@0: michael@0: /** michael@0: * The standard display item to paint the CSS borders of a frame. michael@0: */ michael@0: class nsDisplayBorder : public nsDisplayItem { michael@0: public: michael@0: nsDisplayBorder(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) : michael@0: nsDisplayItem(aBuilder, aFrame) michael@0: { michael@0: MOZ_COUNT_CTOR(nsDisplayBorder); michael@0: } michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayBorder() { michael@0: MOZ_COUNT_DTOR(nsDisplayBorder); michael@0: } michael@0: #endif michael@0: michael@0: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE; michael@0: virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE; michael@0: virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, michael@0: nsRegion* aVisibleRegion, michael@0: const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; michael@0: NS_DISPLAY_DECL_NAME("Border", TYPE_BORDER) michael@0: michael@0: virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE; michael@0: michael@0: virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, michael@0: const nsDisplayItemGeometry* aGeometry, michael@0: nsRegion* aInvalidRegion) MOZ_OVERRIDE; michael@0: michael@0: protected: michael@0: nsRect CalculateBounds(const nsStyleBorder& aStyleBorder); michael@0: }; michael@0: michael@0: /** michael@0: * A simple display item that just renders a solid color across the michael@0: * specified bounds. For canvas frames (in the CSS sense) we split off the michael@0: * drawing of the background color into this class (from nsDisplayBackground michael@0: * via nsDisplayCanvasBackground). This is done so that we can always draw a michael@0: * background color to avoid ugly flashes of white when we can't draw a full michael@0: * frame tree (ie when a page is loading). The bounds can differ from the michael@0: * frame's bounds -- this is needed when a frame/iframe is loading and there michael@0: * is not yet a frame tree to go in the frame/iframe so we use the subdoc michael@0: * frame of the parent document as a standin. michael@0: */ michael@0: class nsDisplaySolidColor : public nsDisplayItem { michael@0: public: michael@0: nsDisplaySolidColor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, michael@0: const nsRect& aBounds, nscolor aColor) michael@0: : nsDisplayItem(aBuilder, aFrame), mBounds(aBounds), mColor(aColor) michael@0: { michael@0: NS_ASSERTION(NS_GET_A(aColor) > 0, "Don't create invisible nsDisplaySolidColors!"); michael@0: MOZ_COUNT_CTOR(nsDisplaySolidColor); michael@0: } michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplaySolidColor() { michael@0: MOZ_COUNT_DTOR(nsDisplaySolidColor); michael@0: } michael@0: #endif michael@0: michael@0: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE; michael@0: michael@0: virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, michael@0: bool* aSnap) MOZ_OVERRIDE { michael@0: *aSnap = false; michael@0: nsRegion result; michael@0: if (NS_GET_A(mColor) == 255) { michael@0: result = GetBounds(aBuilder, aSnap); michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) MOZ_OVERRIDE michael@0: { michael@0: *aColor = mColor; michael@0: return true; michael@0: } michael@0: michael@0: virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE; michael@0: michael@0: virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE michael@0: { michael@0: return new nsDisplaySolidColorGeometry(this, aBuilder, mColor); michael@0: } michael@0: michael@0: virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, michael@0: const nsDisplayItemGeometry* aGeometry, michael@0: nsRegion* aInvalidRegion) MOZ_OVERRIDE michael@0: { michael@0: const nsDisplaySolidColorGeometry* geometry = michael@0: static_cast(aGeometry); michael@0: if (mColor != geometry->mColor) { michael@0: bool dummy; michael@0: aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &dummy)); michael@0: return; michael@0: } michael@0: ComputeInvalidationRegionDifference(aBuilder, geometry, aInvalidRegion); michael@0: } michael@0: michael@0: #ifdef MOZ_DUMP_PAINTING michael@0: virtual void WriteDebugInfo(nsACString& aTo) MOZ_OVERRIDE; michael@0: #endif michael@0: michael@0: NS_DISPLAY_DECL_NAME("SolidColor", TYPE_SOLID_COLOR) michael@0: michael@0: private: michael@0: nsRect mBounds; michael@0: nscolor mColor; michael@0: }; michael@0: michael@0: /** michael@0: * A display item to paint one background-image for a frame. Each background michael@0: * image layer gets its own nsDisplayBackgroundImage. michael@0: */ michael@0: class nsDisplayBackgroundImage : public nsDisplayImageContainer { michael@0: public: michael@0: /** michael@0: * aLayer signifies which background layer this item represents. michael@0: * aIsThemed should be the value of aFrame->IsThemed. michael@0: * aBackgroundStyle should be the result of michael@0: * nsCSSRendering::FindBackground, or null if FindBackground returned false. michael@0: */ michael@0: nsDisplayBackgroundImage(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, michael@0: uint32_t aLayer, michael@0: const nsStyleBackground* aBackgroundStyle); michael@0: virtual ~nsDisplayBackgroundImage(); michael@0: michael@0: // This will create and append new items for all the layers of the michael@0: // background. Returns whether we appended a themed background. michael@0: static bool AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuilder, michael@0: nsIFrame* aFrame, michael@0: nsDisplayList* aList); michael@0: michael@0: virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aParameters) MOZ_OVERRIDE; michael@0: michael@0: virtual already_AddRefed BuildLayer(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE; michael@0: michael@0: virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, michael@0: HitTestState* aState, nsTArray *aOutFrames) MOZ_OVERRIDE; michael@0: virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, michael@0: nsRegion* aVisibleRegion, michael@0: const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; michael@0: virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, michael@0: bool* aSnap) MOZ_OVERRIDE; michael@0: virtual bool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder, michael@0: nsIFrame* aFrame) MOZ_OVERRIDE; michael@0: virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) MOZ_OVERRIDE; michael@0: /** michael@0: * GetBounds() returns the background painting area. michael@0: */ michael@0: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE; michael@0: virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE; michael@0: virtual uint32_t GetPerFrameKey() MOZ_OVERRIDE; michael@0: NS_DISPLAY_DECL_NAME("Background", TYPE_BACKGROUND) michael@0: michael@0: /** michael@0: * Return the background positioning area. michael@0: * (GetBounds() returns the background painting area.) michael@0: * Can be called only when mBackgroundStyle is non-null. michael@0: */ michael@0: nsRect GetPositioningArea(); michael@0: michael@0: /** michael@0: * Returns true if existing rendered pixels of this display item may need michael@0: * to be redrawn if the positioning area size changes but its position does michael@0: * not. michael@0: * If false, only the changed painting area needs to be redrawn when the michael@0: * positioning area size changes but its position does not. michael@0: */ michael@0: bool RenderingMightDependOnPositioningAreaSizeChange(); michael@0: michael@0: virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE michael@0: { michael@0: return new nsDisplayBackgroundGeometry(this, aBuilder); michael@0: } michael@0: michael@0: virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, michael@0: const nsDisplayItemGeometry* aGeometry, michael@0: nsRegion* aInvalidRegion) MOZ_OVERRIDE; michael@0: michael@0: virtual already_AddRefed GetContainer(LayerManager* aManager, michael@0: nsDisplayListBuilder *aBuilder) MOZ_OVERRIDE; michael@0: virtual void ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset) MOZ_OVERRIDE; michael@0: michael@0: static nsRegion GetInsideClipRegion(nsDisplayItem* aItem, nsPresContext* aPresContext, uint8_t aClip, michael@0: const nsRect& aRect, bool* aSnap); michael@0: michael@0: protected: michael@0: typedef class mozilla::layers::ImageContainer ImageContainer; michael@0: typedef class mozilla::layers::ImageLayer ImageLayer; michael@0: michael@0: bool TryOptimizeToImageLayer(LayerManager* aManager, nsDisplayListBuilder* aBuilder); michael@0: bool IsSingleFixedPositionImage(nsDisplayListBuilder* aBuilder, michael@0: const nsRect& aClipRect, michael@0: gfxRect* aDestRect); michael@0: nsRect GetBoundsInternal(nsDisplayListBuilder* aBuilder); michael@0: michael@0: void PaintInternal(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx, michael@0: const nsRect& aBounds, nsRect* aClipRect); michael@0: michael@0: // Cache the result of nsCSSRendering::FindBackground. Always null if michael@0: // mIsThemed is true or if FindBackground returned false. michael@0: const nsStyleBackground* mBackgroundStyle; michael@0: /* If this background can be a simple image layer, we store the format here. */ michael@0: nsRefPtr mImageContainer; michael@0: gfxRect mDestRect; michael@0: /* Bounds of this display item */ michael@0: nsRect mBounds; michael@0: uint32_t mLayer; michael@0: }; michael@0: michael@0: michael@0: /** michael@0: * A display item to paint the native theme background for a frame. michael@0: */ michael@0: class nsDisplayThemedBackground : public nsDisplayItem { michael@0: public: michael@0: nsDisplayThemedBackground(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame); michael@0: virtual ~nsDisplayThemedBackground(); michael@0: michael@0: virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, michael@0: HitTestState* aState, nsTArray *aOutFrames) MOZ_OVERRIDE; michael@0: virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, michael@0: bool* aSnap) MOZ_OVERRIDE; michael@0: virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) MOZ_OVERRIDE; michael@0: /** michael@0: * GetBounds() returns the background painting area. michael@0: */ michael@0: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE; michael@0: virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE; michael@0: NS_DISPLAY_DECL_NAME("ThemedBackground", TYPE_THEMED_BACKGROUND) michael@0: michael@0: /** michael@0: * Return the background positioning area. michael@0: * (GetBounds() returns the background painting area.) michael@0: * Can be called only when mBackgroundStyle is non-null. michael@0: */ michael@0: nsRect GetPositioningArea(); michael@0: michael@0: /** michael@0: * Return whether our frame's document does not have the state michael@0: * NS_DOCUMENT_STATE_WINDOW_INACTIVE. michael@0: */ michael@0: bool IsWindowActive(); michael@0: michael@0: virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE michael@0: { michael@0: return new nsDisplayThemedBackgroundGeometry(this, aBuilder); michael@0: } michael@0: michael@0: virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, michael@0: const nsDisplayItemGeometry* aGeometry, michael@0: nsRegion* aInvalidRegion) MOZ_OVERRIDE; michael@0: michael@0: #ifdef MOZ_DUMP_PAINTING michael@0: virtual void WriteDebugInfo(nsACString& aTo) MOZ_OVERRIDE; michael@0: #endif michael@0: protected: michael@0: nsRect GetBoundsInternal(); michael@0: michael@0: void PaintInternal(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx, michael@0: const nsRect& aBounds, nsRect* aClipRect); michael@0: michael@0: nsRect mBounds; michael@0: nsITheme::Transparency mThemeTransparency; michael@0: uint8_t mAppearance; michael@0: }; michael@0: michael@0: class nsDisplayBackgroundColor : public nsDisplayItem michael@0: { michael@0: public: michael@0: nsDisplayBackgroundColor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, michael@0: const nsStyleBackground* aBackgroundStyle, michael@0: nscolor aColor) michael@0: : nsDisplayItem(aBuilder, aFrame) michael@0: , mBackgroundStyle(aBackgroundStyle) michael@0: , mColor(aColor) michael@0: { } michael@0: michael@0: virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE; michael@0: michael@0: virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, michael@0: bool* aSnap) MOZ_OVERRIDE; michael@0: virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) MOZ_OVERRIDE; michael@0: virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, michael@0: HitTestState* aState, nsTArray *aOutFrames) MOZ_OVERRIDE; michael@0: michael@0: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE michael@0: { michael@0: *aSnap = true; michael@0: return nsRect(ToReferenceFrame(), Frame()->GetSize()); michael@0: } michael@0: michael@0: virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE michael@0: { michael@0: return new nsDisplayItemBoundsGeometry(this, aBuilder); michael@0: } michael@0: michael@0: virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, michael@0: const nsDisplayItemGeometry* aGeometry, michael@0: nsRegion* aInvalidRegion) MOZ_OVERRIDE michael@0: { michael@0: const nsDisplayItemBoundsGeometry* geometry = static_cast(aGeometry); michael@0: ComputeInvalidationRegionDifference(aBuilder, geometry, aInvalidRegion); michael@0: } michael@0: michael@0: NS_DISPLAY_DECL_NAME("BackgroundColor", TYPE_BACKGROUND_COLOR) michael@0: #ifdef MOZ_DUMP_PAINTING michael@0: virtual void WriteDebugInfo(nsACString& aTo) MOZ_OVERRIDE; michael@0: #endif michael@0: michael@0: protected: michael@0: const nsStyleBackground* mBackgroundStyle; michael@0: nscolor mColor; michael@0: }; michael@0: michael@0: /** michael@0: * The standard display item to paint the outer CSS box-shadows of a frame. michael@0: */ michael@0: class nsDisplayBoxShadowOuter : public nsDisplayItem { michael@0: public: michael@0: nsDisplayBoxShadowOuter(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) michael@0: : nsDisplayItem(aBuilder, aFrame) michael@0: , mOpacity(1.0) { michael@0: MOZ_COUNT_CTOR(nsDisplayBoxShadowOuter); michael@0: mBounds = GetBoundsInternal(); michael@0: } michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayBoxShadowOuter() { michael@0: MOZ_COUNT_DTOR(nsDisplayBoxShadowOuter); michael@0: } michael@0: #endif michael@0: michael@0: virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE; michael@0: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE; michael@0: virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, michael@0: nsRegion* aVisibleRegion, michael@0: const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; michael@0: NS_DISPLAY_DECL_NAME("BoxShadowOuter", TYPE_BOX_SHADOW_OUTER) michael@0: michael@0: virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, michael@0: const nsDisplayItemGeometry* aGeometry, michael@0: nsRegion* aInvalidRegion) MOZ_OVERRIDE; michael@0: michael@0: virtual bool ApplyOpacity(nsDisplayListBuilder* aBuilder, michael@0: float aOpacity, michael@0: const DisplayItemClip* aClip) MOZ_OVERRIDE michael@0: { michael@0: mOpacity = aOpacity; michael@0: if (aClip) { michael@0: IntersectClip(aBuilder, *aClip); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: nsRect GetBoundsInternal(); michael@0: michael@0: private: michael@0: nsRegion mVisibleRegion; michael@0: nsRect mBounds; michael@0: float mOpacity; michael@0: }; michael@0: michael@0: /** michael@0: * The standard display item to paint the inner CSS box-shadows of a frame. michael@0: */ michael@0: class nsDisplayBoxShadowInner : public nsDisplayItem { michael@0: public: michael@0: nsDisplayBoxShadowInner(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) michael@0: : nsDisplayItem(aBuilder, aFrame) { michael@0: MOZ_COUNT_CTOR(nsDisplayBoxShadowInner); michael@0: } michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayBoxShadowInner() { michael@0: MOZ_COUNT_DTOR(nsDisplayBoxShadowInner); michael@0: } michael@0: #endif michael@0: michael@0: virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE; michael@0: virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, michael@0: nsRegion* aVisibleRegion, michael@0: const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; michael@0: NS_DISPLAY_DECL_NAME("BoxShadowInner", TYPE_BOX_SHADOW_INNER) michael@0: michael@0: virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE michael@0: { michael@0: return new nsDisplayBoxShadowInnerGeometry(this, aBuilder); michael@0: } michael@0: michael@0: virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, michael@0: const nsDisplayItemGeometry* aGeometry, michael@0: nsRegion* aInvalidRegion) MOZ_OVERRIDE michael@0: { michael@0: const nsDisplayBoxShadowInnerGeometry* geometry = static_cast(aGeometry); michael@0: if (!geometry->mPaddingRect.IsEqualInterior(GetPaddingRect())) { michael@0: // nsDisplayBoxShadowInner is based around the padding rect, but it can michael@0: // touch pixels outside of this. We should invalidate the entire bounds. michael@0: bool snap; michael@0: aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &snap)); michael@0: } michael@0: } michael@0: michael@0: private: michael@0: nsRegion mVisibleRegion; michael@0: }; michael@0: michael@0: /** michael@0: * The standard display item to paint the CSS outline of a frame. michael@0: */ michael@0: class nsDisplayOutline : public nsDisplayItem { michael@0: public: michael@0: nsDisplayOutline(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) : michael@0: nsDisplayItem(aBuilder, aFrame) { michael@0: MOZ_COUNT_CTOR(nsDisplayOutline); michael@0: } michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayOutline() { michael@0: MOZ_COUNT_DTOR(nsDisplayOutline); michael@0: } michael@0: #endif michael@0: michael@0: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE; michael@0: virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE; michael@0: virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, michael@0: nsRegion* aVisibleRegion, michael@0: const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; michael@0: NS_DISPLAY_DECL_NAME("Outline", TYPE_OUTLINE) michael@0: }; michael@0: michael@0: /** michael@0: * A class that lets you receive events within the frame bounds but never paints. michael@0: */ michael@0: class nsDisplayEventReceiver : public nsDisplayItem { michael@0: public: michael@0: nsDisplayEventReceiver(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) michael@0: : nsDisplayItem(aBuilder, aFrame) { michael@0: MOZ_COUNT_CTOR(nsDisplayEventReceiver); michael@0: } michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayEventReceiver() { michael@0: MOZ_COUNT_DTOR(nsDisplayEventReceiver); michael@0: } michael@0: #endif michael@0: michael@0: virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, michael@0: HitTestState* aState, nsTArray *aOutFrames) MOZ_OVERRIDE; michael@0: NS_DISPLAY_DECL_NAME("EventReceiver", TYPE_EVENT_RECEIVER) michael@0: }; michael@0: michael@0: /** michael@0: * A display item that tracks event-sensitive regions which will be set michael@0: * on the ContainerLayer that eventually contains this item. michael@0: * michael@0: * One of these is created for each stacking context and pseudo-stacking-context. michael@0: * It accumulates regions for event targets contributed by the border-boxes of michael@0: * frames in its (pseudo) stacking context. A nsDisplayLayerEventRegions michael@0: * eventually contributes its regions to the ThebesLayer it is placed in by michael@0: * FrameLayerBuilder. (We don't create a display item for every frame that michael@0: * could be an event target (i.e. almost all frames), because that would be michael@0: * high overhead.) michael@0: * michael@0: * We always make leaf layers other than ThebesLayers transparent to events. michael@0: * For example, an event targeting a canvas or video will actually target the michael@0: * background of that element, which is logically in the ThebesLayer behind the michael@0: * CanvasFrame or ImageFrame. We only need to create a michael@0: * nsDisplayLayerEventRegions when an element's background could be in front michael@0: * of a lower z-order element with its own layer. michael@0: */ michael@0: class nsDisplayLayerEventRegions MOZ_FINAL : public nsDisplayItem { michael@0: public: michael@0: nsDisplayLayerEventRegions(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) michael@0: : nsDisplayItem(aBuilder, aFrame) michael@0: { michael@0: MOZ_COUNT_CTOR(nsDisplayEventReceiver); michael@0: AddFrame(aBuilder, aFrame); michael@0: } michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayLayerEventRegions() { michael@0: MOZ_COUNT_DTOR(nsDisplayEventReceiver); michael@0: } michael@0: #endif michael@0: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE michael@0: { michael@0: *aSnap = false; michael@0: return mHitRegion.GetBounds().Union(mMaybeHitRegion.GetBounds()); michael@0: } michael@0: michael@0: NS_DISPLAY_DECL_NAME("LayerEventRegions", TYPE_LAYER_EVENT_REGIONS) michael@0: michael@0: // Indicate that aFrame's border-box contributes to the event regions for michael@0: // this layer. aFrame must have the same reference frame as mFrame. michael@0: void AddFrame(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame); michael@0: michael@0: const nsRegion& HitRegion() { return mHitRegion; } michael@0: const nsRegion& MaybeHitRegion() { return mMaybeHitRegion; } michael@0: const nsRegion& DispatchToContentHitRegion() { return mDispatchToContentHitRegion; } michael@0: michael@0: private: michael@0: // Relative to aFrame's reference frame. michael@0: // These are the points that are definitely in the hit region. michael@0: nsRegion mHitRegion; michael@0: // These are points that may or may not be in the hit region. Only main-thread michael@0: // event handling can tell for sure (e.g. because complex shapes are present). michael@0: nsRegion mMaybeHitRegion; michael@0: // These are points that need to be dispatched to the content thread for michael@0: // resolution. Always contained in the union of mHitRegion and mMaybeHitRegion. michael@0: nsRegion mDispatchToContentHitRegion; michael@0: }; michael@0: michael@0: /** michael@0: * A class that lets you wrap a display list as a display item. michael@0: * michael@0: * GetUnderlyingFrame() is troublesome for wrapped lists because if the wrapped michael@0: * list has many items, it's not clear which one has the 'underlying frame'. michael@0: * Thus we force the creator to specify what the underlying frame is. The michael@0: * underlying frame should be the root of a stacking context, because sorting michael@0: * a list containing this item will not get at the children. michael@0: * michael@0: * In some cases (e.g., clipping) we want to wrap a list but we don't have a michael@0: * particular underlying frame that is a stacking context root. In that case michael@0: * we allow the frame to be nullptr. Callers to GetUnderlyingFrame must michael@0: * detect and handle this case. michael@0: */ michael@0: class nsDisplayWrapList : public nsDisplayItem { michael@0: // This is never instantiated directly, so no need to count constructors and michael@0: // destructors. michael@0: michael@0: public: michael@0: /** michael@0: * Takes all the items from aList and puts them in our list. michael@0: */ michael@0: nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, michael@0: nsDisplayList* aList); michael@0: nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, michael@0: nsDisplayItem* aItem); michael@0: nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, michael@0: nsDisplayItem* aItem, const nsIFrame* aReferenceFrame, const nsPoint& aToReferenceFrame); michael@0: nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) michael@0: : nsDisplayItem(aBuilder, aFrame), mOverrideZIndex(0) {} michael@0: virtual ~nsDisplayWrapList(); michael@0: /** michael@0: * Call this if the wrapped list is changed. michael@0: */ michael@0: virtual void UpdateBounds(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE michael@0: { michael@0: mBounds = mList.GetBounds(aBuilder); michael@0: } michael@0: virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, michael@0: HitTestState* aState, nsTArray *aOutFrames) MOZ_OVERRIDE; michael@0: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE; michael@0: virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, michael@0: bool* aSnap) MOZ_OVERRIDE; michael@0: virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) MOZ_OVERRIDE; michael@0: virtual bool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder, michael@0: nsIFrame* aFrame) MOZ_OVERRIDE; michael@0: virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE; michael@0: virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, michael@0: nsRegion* aVisibleRegion, michael@0: const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; michael@0: virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE { michael@0: NS_WARNING("This list should already have been flattened!!!"); michael@0: return false; michael@0: } michael@0: virtual void GetMergedFrames(nsTArray* aFrames) MOZ_OVERRIDE michael@0: { michael@0: aFrames->AppendElements(mMergedFrames); michael@0: } michael@0: virtual bool IsInvalid(nsRect& aRect) MOZ_OVERRIDE michael@0: { michael@0: if (mFrame->IsInvalid(aRect) && aRect.IsEmpty()) { michael@0: return true; michael@0: } michael@0: nsRect temp; michael@0: for (uint32_t i = 0; i < mMergedFrames.Length(); i++) { michael@0: if (mMergedFrames[i]->IsInvalid(temp) && temp.IsEmpty()) { michael@0: aRect.SetEmpty(); michael@0: return true; michael@0: } michael@0: aRect = aRect.Union(temp); michael@0: } michael@0: aRect += ToReferenceFrame(); michael@0: return !aRect.IsEmpty(); michael@0: } michael@0: NS_DISPLAY_DECL_NAME("WrapList", TYPE_WRAP_LIST) michael@0: michael@0: virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE; michael@0: michael@0: virtual nsDisplayList* GetSameCoordinateSystemChildren() MOZ_OVERRIDE michael@0: { michael@0: NS_ASSERTION(mList.IsEmpty() || !ReferenceFrame() || michael@0: !mList.GetBottom()->ReferenceFrame() || michael@0: mList.GetBottom()->ReferenceFrame() == ReferenceFrame(), michael@0: "Children must have same reference frame"); michael@0: return &mList; michael@0: } michael@0: virtual nsDisplayList* GetChildren() MOZ_OVERRIDE { return &mList; } michael@0: michael@0: virtual int32_t ZIndex() const MOZ_OVERRIDE michael@0: { michael@0: return (mOverrideZIndex > 0) ? mOverrideZIndex : nsDisplayItem::ZIndex(); michael@0: } michael@0: michael@0: void SetOverrideZIndex(int32_t aZIndex) michael@0: { michael@0: mOverrideZIndex = aZIndex; michael@0: } michael@0: michael@0: /** michael@0: * This creates a copy of this item, but wrapping aItem instead of michael@0: * our existing list. Only gets called if this item returned nullptr michael@0: * for GetUnderlyingFrame(). aItem is guaranteed to return non-null from michael@0: * GetUnderlyingFrame(). michael@0: */ michael@0: virtual nsDisplayWrapList* WrapWithClone(nsDisplayListBuilder* aBuilder, michael@0: nsDisplayItem* aItem) { michael@0: NS_NOTREACHED("We never returned nullptr for GetUnderlyingFrame!"); michael@0: return nullptr; michael@0: } michael@0: michael@0: protected: michael@0: nsDisplayWrapList() {} michael@0: michael@0: void MergeFrom(nsDisplayWrapList* aOther) michael@0: { michael@0: mList.AppendToBottom(&aOther->mList); michael@0: mBounds.UnionRect(mBounds, aOther->mBounds); michael@0: } michael@0: void MergeFromTrackingMergedFrames(nsDisplayWrapList* aOther) michael@0: { michael@0: MergeFrom(aOther); michael@0: mMergedFrames.AppendElement(aOther->mFrame); michael@0: mMergedFrames.MoveElementsFrom(aOther->mMergedFrames); michael@0: } michael@0: michael@0: nsDisplayList mList; michael@0: // The frames from items that have been merged into this item, excluding michael@0: // this item's own frame. michael@0: nsTArray mMergedFrames; michael@0: nsRect mBounds; michael@0: // Overrides the ZIndex of our frame if > 0. michael@0: int32_t mOverrideZIndex; michael@0: }; michael@0: michael@0: /** michael@0: * We call WrapDisplayList on the in-flow lists: BorderBackground(), michael@0: * BlockBorderBackgrounds() and Content(). michael@0: * We call WrapDisplayItem on each item of Outlines(), PositionedDescendants(), michael@0: * and Floats(). This is done to support special wrapping processing for frames michael@0: * that may not be in-flow descendants of the current frame. michael@0: */ michael@0: class nsDisplayWrapper { michael@0: public: michael@0: // This is never instantiated directly (it has pure virtual methods), so no michael@0: // need to count constructors and destructors. michael@0: michael@0: virtual bool WrapBorderBackground() { return true; } michael@0: virtual nsDisplayItem* WrapList(nsDisplayListBuilder* aBuilder, michael@0: nsIFrame* aFrame, nsDisplayList* aList) = 0; michael@0: virtual nsDisplayItem* WrapItem(nsDisplayListBuilder* aBuilder, michael@0: nsDisplayItem* aItem) = 0; michael@0: michael@0: nsresult WrapLists(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, michael@0: const nsDisplayListSet& aIn, const nsDisplayListSet& aOut); michael@0: nsresult WrapListsInPlace(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, michael@0: const nsDisplayListSet& aLists); michael@0: protected: michael@0: nsDisplayWrapper() {} michael@0: }; michael@0: michael@0: /** michael@0: * The standard display item to paint a stacking context with translucency michael@0: * set by the stacking context root frame's 'opacity' style. michael@0: */ michael@0: class nsDisplayOpacity : public nsDisplayWrapList { michael@0: public: michael@0: nsDisplayOpacity(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, michael@0: nsDisplayList* aList); michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayOpacity(); michael@0: #endif michael@0: michael@0: virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, michael@0: bool* aSnap) MOZ_OVERRIDE; michael@0: virtual already_AddRefed BuildLayer(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE; michael@0: virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aParameters) MOZ_OVERRIDE; michael@0: virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, michael@0: nsRegion* aVisibleRegion, michael@0: const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; michael@0: virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE; michael@0: virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, michael@0: const nsDisplayItemGeometry* aGeometry, michael@0: nsRegion* aInvalidRegion) MOZ_OVERRIDE michael@0: { michael@0: // We don't need to compute an invalidation region since we have LayerTreeInvalidation michael@0: } michael@0: virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE; michael@0: bool NeedsActiveLayer(); michael@0: NS_DISPLAY_DECL_NAME("Opacity", TYPE_OPACITY) michael@0: #ifdef MOZ_DUMP_PAINTING michael@0: virtual void WriteDebugInfo(nsACString& aTo) MOZ_OVERRIDE; michael@0: #endif michael@0: michael@0: bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE; michael@0: }; michael@0: michael@0: class nsDisplayMixBlendMode : public nsDisplayWrapList { michael@0: public: michael@0: nsDisplayMixBlendMode(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, michael@0: nsDisplayList* aList, uint32_t aFlags = 0); michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayMixBlendMode(); michael@0: #endif michael@0: michael@0: nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, michael@0: bool* aSnap) MOZ_OVERRIDE; michael@0: michael@0: virtual already_AddRefed BuildLayer(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE; michael@0: virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, michael@0: const nsDisplayItemGeometry* aGeometry, michael@0: nsRegion* aInvalidRegion) MOZ_OVERRIDE michael@0: { michael@0: // We don't need to compute an invalidation region since we have LayerTreeInvalidation michael@0: } michael@0: virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aParameters) MOZ_OVERRIDE michael@0: { michael@0: return mozilla::LAYER_INACTIVE; michael@0: } michael@0: virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, michael@0: nsRegion* aVisibleRegion, michael@0: const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; michael@0: virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE; michael@0: NS_DISPLAY_DECL_NAME("MixBlendMode", TYPE_MIX_BLEND_MODE) michael@0: }; michael@0: michael@0: class nsDisplayBlendContainer : public nsDisplayWrapList { michael@0: public: michael@0: nsDisplayBlendContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, michael@0: nsDisplayList* aList, uint32_t aFlags = 0); michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayBlendContainer(); michael@0: #endif michael@0: michael@0: virtual already_AddRefed BuildLayer(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE; michael@0: virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aParameters) MOZ_OVERRIDE michael@0: { michael@0: return mozilla::LAYER_INACTIVE; michael@0: } michael@0: virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE; michael@0: NS_DISPLAY_DECL_NAME("BlendContainer", TYPE_BLEND_CONTAINER) michael@0: }; michael@0: michael@0: /** michael@0: * A display item that has no purpose but to ensure its contents get michael@0: * their own layer. michael@0: */ michael@0: class nsDisplayOwnLayer : public nsDisplayWrapList { michael@0: public: michael@0: michael@0: /** michael@0: * nsDisplayOwnLayer constructor flags michael@0: */ michael@0: enum { michael@0: GENERATE_SUBDOC_INVALIDATIONS = 0x01, michael@0: VERTICAL_SCROLLBAR = 0x02, michael@0: HORIZONTAL_SCROLLBAR = 0x04, michael@0: GENERATE_SCROLLABLE_LAYER = 0x08 michael@0: }; michael@0: michael@0: /** michael@0: * @param aFlags GENERATE_SUBDOC_INVALIDATIONS : michael@0: * Add UserData to the created ContainerLayer, so that invalidations michael@0: * for this layer are send to our nsPresContext. michael@0: * GENERATE_SCROLLABLE_LAYER : only valid on nsDisplaySubDocument (and michael@0: * subclasses), indicates this layer is to be a scrollable layer, so call michael@0: * RecordFrameMetrics, etc. michael@0: * @param aScrollTarget when VERTICAL_SCROLLBAR or HORIZONTAL_SCROLLBAR michael@0: * is set in the flags, this parameter should be the ViewID of the michael@0: * scrollable content this scrollbar is for. michael@0: */ michael@0: nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, michael@0: nsDisplayList* aList, uint32_t aFlags = 0, michael@0: ViewID aScrollTarget = mozilla::layers::FrameMetrics::NULL_SCROLL_ID); michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayOwnLayer(); michael@0: #endif michael@0: michael@0: virtual already_AddRefed BuildLayer(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE; michael@0: virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aParameters) MOZ_OVERRIDE michael@0: { michael@0: return mozilla::LAYER_ACTIVE_FORCE; michael@0: } michael@0: virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE michael@0: { michael@0: // Don't allow merging, each sublist must have its own layer michael@0: return false; michael@0: } michael@0: uint32_t GetFlags() { return mFlags; } michael@0: NS_DISPLAY_DECL_NAME("OwnLayer", TYPE_OWN_LAYER) michael@0: protected: michael@0: uint32_t mFlags; michael@0: ViewID mScrollTarget; michael@0: }; michael@0: michael@0: /** michael@0: * A display item for subdocuments. This is more or less the same as nsDisplayOwnLayer, michael@0: * except that it always populates the FrameMetrics instance on the ContainerLayer it michael@0: * builds. michael@0: */ michael@0: class nsDisplaySubDocument : public nsDisplayOwnLayer { michael@0: public: michael@0: nsDisplaySubDocument(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, michael@0: nsDisplayList* aList, uint32_t aFlags); michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplaySubDocument(); michael@0: #endif michael@0: michael@0: virtual already_AddRefed BuildLayer(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE; michael@0: michael@0: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE; michael@0: michael@0: virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, michael@0: nsRegion* aVisibleRegion, michael@0: const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; michael@0: michael@0: virtual bool SetVisibleRegionOnLayer() MOZ_OVERRIDE { return !(mFlags & GENERATE_SCROLLABLE_LAYER); } michael@0: michael@0: virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE; michael@0: michael@0: virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE; michael@0: michael@0: NS_DISPLAY_DECL_NAME("SubDocument", TYPE_SUBDOCUMENT) michael@0: protected: michael@0: ViewID mScrollParentId; michael@0: }; michael@0: michael@0: /** michael@0: * A display item for subdocuments to capture the resolution from the presShell michael@0: * and ensure that it gets applied to all the right elements. This item creates michael@0: * a container layer. michael@0: */ michael@0: class nsDisplayResolution : public nsDisplaySubDocument { michael@0: public: michael@0: nsDisplayResolution(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, michael@0: nsDisplayList* aList, uint32_t aFlags); michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayResolution(); michael@0: #endif michael@0: michael@0: virtual already_AddRefed BuildLayer(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE; michael@0: NS_DISPLAY_DECL_NAME("Resolution", TYPE_RESOLUTION) michael@0: }; michael@0: michael@0: /** michael@0: * A display item used to represent sticky position elements. The contents michael@0: * gets its own layer and creates a stacking context, and the layer will have michael@0: * position-related metadata set on it. michael@0: */ michael@0: class nsDisplayStickyPosition : public nsDisplayOwnLayer { michael@0: public: michael@0: nsDisplayStickyPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, michael@0: nsDisplayList* aList); michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayStickyPosition(); michael@0: #endif michael@0: michael@0: virtual already_AddRefed BuildLayer(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE; michael@0: NS_DISPLAY_DECL_NAME("StickyPosition", TYPE_STICKY_POSITION) michael@0: virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aParameters) MOZ_OVERRIDE michael@0: { michael@0: return mozilla::LAYER_ACTIVE; michael@0: } michael@0: virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE; michael@0: }; michael@0: michael@0: /** michael@0: * This potentially creates a layer for the given list of items, whose michael@0: * visibility is determined by the displayport for the given frame instead of michael@0: * what is passed in to ComputeVisibility. michael@0: * michael@0: * Here in content, we can use this to render more content than is actually michael@0: * visible. Then, the compositing process can manipulate the generated layer michael@0: * through transformations so that asynchronous scrolling can be implemented. michael@0: * michael@0: * Note that setting the displayport will not change any hit testing! The michael@0: * content process will know nothing about what the user is actually seeing, michael@0: * so it can only do hit testing for what is supposed to be the visible region. michael@0: * michael@0: * It is possible for scroll boxes to have content that can be both above and michael@0: * below content outside of the scroll box. We cannot create layers for these michael@0: * cases. This is accomplished by wrapping display items with michael@0: * nsDisplayScrollLayers. nsDisplayScrollLayers with the same scroll frame will michael@0: * be merged together. If more than one nsDisplayScrollLayer exists after michael@0: * merging, all nsDisplayScrollLayers will be flattened out so that no new michael@0: * layer is created at all. michael@0: */ michael@0: class nsDisplayScrollLayer : public nsDisplayWrapList michael@0: { michael@0: public: michael@0: /** michael@0: * @param aScrolledFrame This will determine what the displayport is. It should be michael@0: * the root content frame of the scrolled area. Note michael@0: * that nsDisplayScrollLayer will expect for michael@0: * ScrollLayerCount to be defined on aScrolledFrame. michael@0: * @param aScrollFrame The viewport frame you see this content through. michael@0: */ michael@0: nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder, nsDisplayList* aList, michael@0: nsIFrame* aForFrame, nsIFrame* aScrolledFrame, michael@0: nsIFrame* aScrollFrame); michael@0: nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem, michael@0: nsIFrame* aForFrame, nsIFrame* aScrolledFrame, michael@0: nsIFrame* aScrollFrame); michael@0: nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder, michael@0: nsIFrame* aForFrame, nsIFrame* aScrolledFrame, michael@0: nsIFrame* aScrollFrame); michael@0: NS_DISPLAY_DECL_NAME("ScrollLayer", TYPE_SCROLL_LAYER) michael@0: michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayScrollLayer(); michael@0: #endif michael@0: michael@0: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE; michael@0: michael@0: virtual already_AddRefed BuildLayer(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE; michael@0: michael@0: virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE; michael@0: michael@0: virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, michael@0: bool* aSnap) MOZ_OVERRIDE { michael@0: *aSnap = false; michael@0: return nsRegion(); michael@0: } michael@0: michael@0: virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, michael@0: nsRegion* aVisibleRegion, michael@0: const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; michael@0: michael@0: virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aParameters) MOZ_OVERRIDE; michael@0: michael@0: virtual bool TryMerge(nsDisplayListBuilder* aBuilder, michael@0: nsDisplayItem* aItem) MOZ_OVERRIDE; michael@0: michael@0: virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE; michael@0: michael@0: // Get the number of nsDisplayScrollLayers for a scroll frame. Note that this michael@0: // number does not include nsDisplayScrollInfoLayers. If this number is not 1 michael@0: // after merging, all the nsDisplayScrollLayers should flatten away. michael@0: intptr_t GetScrollLayerCount(); michael@0: michael@0: virtual nsIFrame* GetScrollFrame() { return mScrollFrame; } michael@0: virtual nsIFrame* GetScrolledFrame() { return mScrolledFrame; } michael@0: michael@0: virtual bool SetVisibleRegionOnLayer() MOZ_OVERRIDE { return false; } michael@0: michael@0: #ifdef MOZ_DUMP_PAINTING michael@0: virtual void WriteDebugInfo(nsACString& aTo) MOZ_OVERRIDE; michael@0: #endif michael@0: michael@0: protected: michael@0: nsIFrame* mScrollFrame; michael@0: nsIFrame* mScrolledFrame; michael@0: ViewID mScrollParentId; michael@0: }; michael@0: michael@0: /** michael@0: * Like nsDisplayScrollLayer, but only has metadata on the scroll frame. This michael@0: * creates a layer that has no Thebes child layer, but still allows the michael@0: * compositor process to know of the scroll frame's existence. michael@0: * michael@0: * After visibility computation, nsDisplayScrollInfoLayers should only exist if michael@0: * nsDisplayScrollLayers were all flattened away. michael@0: * michael@0: * Important!! Add info layers to the bottom of the list so they are only michael@0: * considered after the others have flattened out! michael@0: */ michael@0: class nsDisplayScrollInfoLayer : public nsDisplayScrollLayer michael@0: { michael@0: public: michael@0: nsDisplayScrollInfoLayer(nsDisplayListBuilder* aBuilder, michael@0: nsIFrame* aScrolledFrame, nsIFrame* aScrollFrame); michael@0: NS_DISPLAY_DECL_NAME("ScrollInfoLayer", TYPE_SCROLL_INFO_LAYER) michael@0: michael@0: virtual ~nsDisplayScrollInfoLayer(); michael@0: michael@0: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE; michael@0: michael@0: virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aParameters) MOZ_OVERRIDE; michael@0: virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE michael@0: { return true; } michael@0: virtual bool TryMerge(nsDisplayListBuilder* aBuilder, michael@0: nsDisplayItem* aItem) MOZ_OVERRIDE; michael@0: michael@0: virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE; michael@0: }; michael@0: michael@0: /** michael@0: * nsDisplayZoom is used for subdocuments that have a different full zoom than michael@0: * their parent documents. This item creates a container layer. michael@0: */ michael@0: class nsDisplayZoom : public nsDisplaySubDocument { michael@0: public: michael@0: /** michael@0: * @param aFrame is the root frame of the subdocument. michael@0: * @param aList contains the display items for the subdocument. michael@0: * @param aAPD is the app units per dev pixel ratio of the subdocument. michael@0: * @param aParentAPD is the app units per dev pixel ratio of the parent michael@0: * document. michael@0: * @param aFlags GENERATE_SUBDOC_INVALIDATIONS : michael@0: * Add UserData to the created ContainerLayer, so that invalidations michael@0: * for this layer are send to our nsPresContext. michael@0: */ michael@0: nsDisplayZoom(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, michael@0: nsDisplayList* aList, michael@0: int32_t aAPD, int32_t aParentAPD, michael@0: uint32_t aFlags = 0); michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayZoom(); michael@0: #endif michael@0: michael@0: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE; michael@0: virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE; michael@0: virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, michael@0: HitTestState* aState, nsTArray *aOutFrames) MOZ_OVERRIDE; michael@0: virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, michael@0: nsRegion* aVisibleRegion, michael@0: const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; michael@0: virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aParameters) MOZ_OVERRIDE michael@0: { michael@0: return mozilla::LAYER_ACTIVE; michael@0: } michael@0: NS_DISPLAY_DECL_NAME("Zoom", TYPE_ZOOM) michael@0: michael@0: // Get the app units per dev pixel ratio of the child document. michael@0: int32_t GetChildAppUnitsPerDevPixel() { return mAPD; } michael@0: // Get the app units per dev pixel ratio of the parent document. michael@0: int32_t GetParentAppUnitsPerDevPixel() { return mParentAPD; } michael@0: michael@0: private: michael@0: int32_t mAPD, mParentAPD; michael@0: }; michael@0: michael@0: /** michael@0: * A display item to paint a stacking context with effects michael@0: * set by the stacking context root frame's style. michael@0: */ michael@0: class nsDisplaySVGEffects : public nsDisplayWrapList { michael@0: public: michael@0: nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, michael@0: nsDisplayList* aList); michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplaySVGEffects(); michael@0: #endif michael@0: michael@0: virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, michael@0: bool* aSnap) MOZ_OVERRIDE; michael@0: virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, michael@0: HitTestState* aState, michael@0: nsTArray *aOutFrames) MOZ_OVERRIDE; michael@0: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, michael@0: bool* aSnap) MOZ_OVERRIDE { michael@0: *aSnap = false; michael@0: return mEffectsBounds + ToReferenceFrame(); michael@0: } michael@0: virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, michael@0: nsRegion* aVisibleRegion, michael@0: const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; michael@0: virtual bool TryMerge(nsDisplayListBuilder* aBuilder, michael@0: nsDisplayItem* aItem) MOZ_OVERRIDE; michael@0: NS_DISPLAY_DECL_NAME("SVGEffects", TYPE_SVG_EFFECTS) michael@0: michael@0: virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aParameters) MOZ_OVERRIDE; michael@0: michael@0: virtual already_AddRefed BuildLayer(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE; michael@0: michael@0: virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, michael@0: const nsDisplayItemGeometry* aGeometry, michael@0: nsRegion* aInvalidRegion) MOZ_OVERRIDE michael@0: { michael@0: // We don't need to compute an invalidation region since we have LayerTreeInvalidation michael@0: } michael@0: michael@0: void PaintAsLayer(nsDisplayListBuilder* aBuilder, michael@0: nsRenderingContext* aCtx, michael@0: LayerManager* aManager); michael@0: michael@0: #ifdef MOZ_DUMP_PAINTING michael@0: void PrintEffects(nsACString& aTo); michael@0: #endif michael@0: michael@0: private: michael@0: // relative to mFrame michael@0: nsRect mEffectsBounds; michael@0: }; michael@0: michael@0: /* A display item that applies a transformation to all of its descendant michael@0: * elements. This wrapper should only be used if there is a transform applied michael@0: * to the root element. michael@0: * michael@0: * The reason that a "bounds" rect is involved in transform calculations is michael@0: * because CSS-transforms allow percentage values for the x and y components michael@0: * of s, where percentages are percentages of the element's michael@0: * border box. michael@0: * michael@0: * INVARIANT: The wrapped frame is transformed or we supplied a transform getter michael@0: * function. michael@0: * INVARIANT: The wrapped frame is non-null. michael@0: */ michael@0: class nsDisplayTransform: public nsDisplayItem michael@0: { michael@0: public: michael@0: /** michael@0: * Returns a matrix (in pixels) for the current frame. The matrix should be relative to michael@0: * the current frame's coordinate space. michael@0: * michael@0: * @param aFrame The frame to compute the transform for. michael@0: * @param aAppUnitsPerPixel The number of app units per graphics unit. michael@0: */ michael@0: typedef gfx3DMatrix (* ComputeTransformFunction)(nsIFrame* aFrame, float aAppUnitsPerPixel); michael@0: michael@0: /* Constructor accepts a display list, empties it, and wraps it up. It also michael@0: * ferries the underlying frame to the nsDisplayItem constructor. michael@0: */ michael@0: nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame, michael@0: nsDisplayList *aList, uint32_t aIndex = 0); michael@0: nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame, michael@0: nsDisplayItem *aItem, uint32_t aIndex = 0); michael@0: nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame, michael@0: nsDisplayList *aList, ComputeTransformFunction aTransformGetter, uint32_t aIndex = 0); michael@0: michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayTransform() michael@0: { michael@0: MOZ_COUNT_DTOR(nsDisplayTransform); michael@0: } michael@0: #endif michael@0: michael@0: NS_DISPLAY_DECL_NAME("nsDisplayTransform", TYPE_TRANSFORM) michael@0: michael@0: virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE michael@0: { michael@0: if (mStoredList.GetComponentAlphaBounds(aBuilder).IsEmpty()) michael@0: return nsRect(); michael@0: bool snap; michael@0: return GetBounds(aBuilder, &snap); michael@0: } michael@0: michael@0: virtual nsDisplayList* GetChildren() MOZ_OVERRIDE { return mStoredList.GetChildren(); } michael@0: michael@0: virtual void HitTest(nsDisplayListBuilder *aBuilder, const nsRect& aRect, michael@0: HitTestState *aState, nsTArray *aOutFrames) MOZ_OVERRIDE; michael@0: virtual nsRect GetBounds(nsDisplayListBuilder *aBuilder, bool* aSnap) MOZ_OVERRIDE; michael@0: virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder *aBuilder, michael@0: bool* aSnap) MOZ_OVERRIDE; michael@0: virtual bool IsUniform(nsDisplayListBuilder *aBuilder, nscolor* aColor) MOZ_OVERRIDE; michael@0: virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aParameters) MOZ_OVERRIDE; michael@0: virtual already_AddRefed BuildLayer(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE; michael@0: virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE; michael@0: virtual bool ComputeVisibility(nsDisplayListBuilder *aBuilder, michael@0: nsRegion *aVisibleRegion, michael@0: const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; michael@0: virtual bool TryMerge(nsDisplayListBuilder *aBuilder, nsDisplayItem *aItem) MOZ_OVERRIDE; michael@0: michael@0: virtual uint32_t GetPerFrameKey() MOZ_OVERRIDE { return (mIndex << nsDisplayItem::TYPE_BITS) | nsDisplayItem::GetPerFrameKey(); } michael@0: michael@0: virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, michael@0: const nsDisplayItemGeometry* aGeometry, michael@0: nsRegion* aInvalidRegion) MOZ_OVERRIDE michael@0: { michael@0: // We don't need to compute an invalidation region since we have LayerTreeInvalidation michael@0: } michael@0: michael@0: virtual const nsIFrame* ReferenceFrameForChildren() const MOZ_OVERRIDE { michael@0: // If we were created using a transform-getter, then we don't michael@0: // belong to a transformed frame, and aren't a reference frame michael@0: // for our children. michael@0: if (!mTransformGetter) { michael@0: return mFrame; michael@0: } michael@0: return nsDisplayItem::ReferenceFrameForChildren(); michael@0: } michael@0: michael@0: enum { michael@0: INDEX_MAX = UINT32_MAX >> nsDisplayItem::TYPE_BITS michael@0: }; michael@0: michael@0: const gfx3DMatrix& GetTransform(); michael@0: michael@0: float GetHitDepthAtPoint(nsDisplayListBuilder* aBuilder, const nsPoint& aPoint); michael@0: michael@0: /** michael@0: * TransformRect takes in as parameters a rectangle (in aFrame's coordinate michael@0: * space) and returns the smallest rectangle (in aFrame's coordinate space) michael@0: * containing the transformed image of that rectangle. That is, it takes michael@0: * the four corners of the rectangle, transforms them according to the michael@0: * matrix associated with the specified frame, then returns the smallest michael@0: * rectangle containing the four transformed points. michael@0: * michael@0: * @param untransformedBounds The rectangle (in app units) to transform. michael@0: * @param aFrame The frame whose transformation should be applied. This michael@0: * function raises an assertion if aFrame is null or doesn't have a michael@0: * transform applied to it. michael@0: * @param aOrigin The origin of the transform relative to aFrame's local michael@0: * coordinate space. michael@0: * @param aBoundsOverride (optional) Rather than using the frame's computed michael@0: * bounding rect as frame bounds, use this rectangle instead. Pass michael@0: * nullptr (or nothing at all) to use the default. michael@0: */ michael@0: static nsRect TransformRect(const nsRect &aUntransformedBounds, michael@0: const nsIFrame* aFrame, michael@0: const nsPoint &aOrigin, michael@0: const nsRect* aBoundsOverride = nullptr); michael@0: michael@0: static nsRect TransformRectOut(const nsRect &aUntransformedBounds, michael@0: const nsIFrame* aFrame, michael@0: const nsPoint &aOrigin, michael@0: const nsRect* aBoundsOverride = nullptr); michael@0: michael@0: /* UntransformRect is like TransformRect, except that it inverts the michael@0: * transform. michael@0: */ michael@0: static bool UntransformRect(const nsRect &aTransformedBounds, michael@0: const nsRect &aChildBounds, michael@0: const nsIFrame* aFrame, michael@0: const nsPoint &aOrigin, michael@0: nsRect *aOutRect); michael@0: michael@0: bool UntransformVisibleRect(nsDisplayListBuilder* aBuilder, michael@0: nsRect* aOutRect); michael@0: michael@0: static gfxPoint3D GetDeltaToTransformOrigin(const nsIFrame* aFrame, michael@0: float aAppUnitsPerPixel, michael@0: const nsRect* aBoundsOverride); michael@0: michael@0: static gfxPoint3D GetDeltaToPerspectiveOrigin(const nsIFrame* aFrame, michael@0: float aAppUnitsPerPixel); michael@0: michael@0: /** michael@0: * Returns the bounds of a frame as defined for resolving percentage michael@0: * s in CSS transforms. If michael@0: * UNIFIED_CONTINUATIONS is not defined, this is simply the frame's bounding michael@0: * rectangle, translated to the origin. Otherwise, returns the smallest michael@0: * rectangle containing a frame and all of its continuations. For example, michael@0: * if there is a element with several continuations split over michael@0: * several lines, this function will return the rectangle containing all of michael@0: * those continuations. This rectangle is relative to the origin of the michael@0: * frame's local coordinate space. michael@0: * michael@0: * @param aFrame The frame to get the bounding rect for. michael@0: * @return The frame's bounding rect, as described above. michael@0: */ michael@0: static nsRect GetFrameBoundsForTransform(const nsIFrame* aFrame); michael@0: michael@0: struct FrameTransformProperties michael@0: { michael@0: FrameTransformProperties(const nsIFrame* aFrame, michael@0: float aAppUnitsPerPixel, michael@0: const nsRect* aBoundsOverride); michael@0: FrameTransformProperties(nsCSSValueSharedList* aTransformList, michael@0: const gfxPoint3D& aToTransformOrigin, michael@0: const gfxPoint3D& aToPerspectiveOrigin, michael@0: nscoord aChildPerspective) michael@0: : mFrame(nullptr) michael@0: , mTransformList(aTransformList) michael@0: , mToTransformOrigin(aToTransformOrigin) michael@0: , mToPerspectiveOrigin(aToPerspectiveOrigin) michael@0: , mChildPerspective(aChildPerspective) michael@0: {} michael@0: michael@0: const nsIFrame* mFrame; michael@0: nsRefPtr mTransformList; michael@0: const gfxPoint3D mToTransformOrigin; michael@0: const gfxPoint3D mToPerspectiveOrigin; michael@0: nscoord mChildPerspective; michael@0: }; michael@0: michael@0: /** michael@0: * Given a frame with the -moz-transform property or an SVG transform, michael@0: * returns the transformation matrix for that frame. michael@0: * michael@0: * @param aFrame The frame to get the matrix from. michael@0: * @param aOrigin Relative to which point this transform should be applied. michael@0: * @param aAppUnitsPerPixel The number of app units per graphics unit. michael@0: * @param aBoundsOverride [optional] If this is nullptr (the default), the michael@0: * computation will use the value of GetFrameBoundsForTransform(aFrame) michael@0: * for the frame's bounding rectangle. Otherwise, it will use the michael@0: * value of aBoundsOverride. This is mostly for internal use and in michael@0: * most cases you will not need to specify a value. michael@0: */ michael@0: static gfx3DMatrix GetResultingTransformMatrix(const nsIFrame* aFrame, michael@0: const nsPoint& aOrigin, michael@0: float aAppUnitsPerPixel, michael@0: const nsRect* aBoundsOverride = nullptr, michael@0: nsIFrame** aOutAncestor = nullptr); michael@0: static gfx3DMatrix GetResultingTransformMatrix(const FrameTransformProperties& aProperties, michael@0: const nsPoint& aOrigin, michael@0: float aAppUnitsPerPixel, michael@0: const nsRect* aBoundsOverride = nullptr, michael@0: nsIFrame** aOutAncestor = nullptr); michael@0: /** michael@0: * Return true when we should try to prerender the entire contents of the michael@0: * transformed frame even when it's not completely visible (yet). michael@0: */ michael@0: static bool ShouldPrerenderTransformedContent(nsDisplayListBuilder* aBuilder, michael@0: nsIFrame* aFrame, michael@0: bool aLogAnimations = false); michael@0: bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE; michael@0: michael@0: virtual bool SetVisibleRegionOnLayer() MOZ_OVERRIDE { return false; } michael@0: michael@0: private: michael@0: static gfx3DMatrix GetResultingTransformMatrixInternal(const FrameTransformProperties& aProperties, michael@0: const nsPoint& aOrigin, michael@0: float aAppUnitsPerPixel, michael@0: const nsRect* aBoundsOverride, michael@0: nsIFrame** aOutAncestor); michael@0: michael@0: nsDisplayWrapList mStoredList; michael@0: gfx3DMatrix mTransform; michael@0: ComputeTransformFunction mTransformGetter; michael@0: uint32_t mIndex; michael@0: }; michael@0: michael@0: /** michael@0: * This class adds basic support for limiting the rendering to the part inside michael@0: * the specified edges. It's a base class for the display item classes that michael@0: * does the actual work. The two members, mLeftEdge and mRightEdge, are michael@0: * relative to the edges of the frame's scrollable overflow rectangle and is michael@0: * the amount to suppress on each side. michael@0: * michael@0: * Setting none, both or only one edge is allowed. michael@0: * The values must be non-negative. michael@0: * The default value for both edges is zero, which means everything is painted. michael@0: */ michael@0: class nsCharClipDisplayItem : public nsDisplayItem { michael@0: public: michael@0: nsCharClipDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) michael@0: : nsDisplayItem(aBuilder, aFrame), mLeftEdge(0), mRightEdge(0) {} michael@0: michael@0: nsCharClipDisplayItem(nsIFrame* aFrame) michael@0: : nsDisplayItem(aFrame) {} michael@0: michael@0: struct ClipEdges { michael@0: ClipEdges(const nsDisplayItem& aItem, michael@0: nscoord aLeftEdge, nscoord aRightEdge) { michael@0: nsRect r = aItem.Frame()->GetScrollableOverflowRect() + michael@0: aItem.ToReferenceFrame(); michael@0: mX = aLeftEdge > 0 ? r.x + aLeftEdge : nscoord_MIN; michael@0: mXMost = aRightEdge > 0 ? std::max(r.XMost() - aRightEdge, mX) : nscoord_MAX; michael@0: } michael@0: void Intersect(nscoord* aX, nscoord* aWidth) const { michael@0: nscoord xmost1 = *aX + *aWidth; michael@0: *aX = std::max(*aX, mX); michael@0: *aWidth = std::max(std::min(xmost1, mXMost) - *aX, 0); michael@0: } michael@0: nscoord mX; michael@0: nscoord mXMost; michael@0: }; michael@0: michael@0: ClipEdges Edges() const { return ClipEdges(*this, mLeftEdge, mRightEdge); } michael@0: michael@0: static nsCharClipDisplayItem* CheckCast(nsDisplayItem* aItem) { michael@0: nsDisplayItem::Type t = aItem->GetType(); michael@0: return (t == nsDisplayItem::TYPE_TEXT || michael@0: t == nsDisplayItem::TYPE_TEXT_DECORATION || michael@0: t == nsDisplayItem::TYPE_TEXT_SHADOW) michael@0: ? static_cast(aItem) : nullptr; michael@0: } michael@0: michael@0: nscoord mLeftEdge; // length from the left side michael@0: nscoord mRightEdge; // length from the right side michael@0: }; michael@0: michael@0: #endif /*NSDISPLAYLIST_H_*/