gecko/layout/base/FrameLayerBuilder.h

745 lines
28 KiB
C
Raw Normal View History

/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2012-05-21 04:12:37 -07:00
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef FRAMELAYERBUILDER_H_
#define FRAMELAYERBUILDER_H_
#include "nsTHashtable.h"
#include "nsHashKeys.h"
#include "nsTArray.h"
#include "nsRegion.h"
#include "nsIFrame.h"
#include "Layers.h"
#include "nsDisplayListInvalidation.h"
#include "LayerTreeInvalidation.h"
class nsDisplayListBuilder;
class nsDisplayList;
class nsDisplayItem;
class gfxContext;
class nsRootPresContext;
namespace mozilla {
class FrameLayerBuilder;
class LayerManagerData;
enum LayerState {
LAYER_NONE,
LAYER_INACTIVE,
LAYER_ACTIVE,
// Force an active layer even if it causes incorrect rendering, e.g.
// when the layer has rounded rect clips.
LAYER_ACTIVE_FORCE,
// Special layer that is metadata only.
LAYER_ACTIVE_EMPTY,
// Inactive style layer for rendering SVG effects.
LAYER_SVG_EFFECTS
};
extern PRUint8 gLayerManagerLayerBuilder;
extern PRUint8 gLayerManagerSecondary;
class LayerManagerSecondary : public layers::LayerUserData {
};
/**
* The FrameLayerBuilder belongs to an nsDisplayListBuilder and is
* responsible for converting display lists into layer trees.
*
* The most important API in this class is BuildContainerLayerFor. This
* method takes a display list as input and constructs a ContainerLayer
* with child layers that render the contents of the display list. It
* also updates userdata for the retained layer manager, and
* DisplayItemDataProperty data for frames, to record the relationship
* between frames and layers.
*
* That data enables us to retain layer trees. When constructing a
* ContainerLayer, we first check to see if there's an existing
* ContainerLayer for the same frame that can be recycled. If we recycle
* it, we also try to reuse its existing ThebesLayer children to render
* the display items without layers of their own. The idea is that by
* recycling layers deterministically, we can ensure that when nothing
* changes in a display list, we will reuse the existing layers without
* changes.
*
* We expose a GetLeafLayerFor method that can be called by display items
* that make their own layers (e.g. canvas and video); this method
* locates the last layer used to render the display item, if any, and
* return it as a candidate for recycling.
*
* FrameLayerBuilder sets up ThebesLayers so that 0,0 in the Thebes layer
* corresponds to the (pixel-snapped) top-left of the aActiveScrolledRoot.
* It sets up ContainerLayers so that 0,0 in the container layer
* corresponds to the snapped top-left of the display list reference frame.
Bug 637852. Part 6: Implement resolution scaling in FrameLayerBuilder. r=tnikkel FrameLayerBuilder::BuildContainerLayerFor takes responsibility for resolution scaling. The ContainerParameters passed in are added to any transform requested. Then we extract the scale part of the transform, round the scale up to the nearest power of two if the transform may be actively animated (so we don't have to redraw layer contents constantly), pass that scale down to be applied by each child and set the residual transform on the ContainerLayer. For child layers built via BuildLayer, we just pass the requested scale factor in via the ContainerParameters. If the returned layer is a ContainerLayer then BuildLayer is guaranteed to have already done necessary scaling. If the returned layer is not a ContainerLayer then we apply the scale ourselves by adding the scale to the child layer's transform. For child ThebesLayers containing non-layer display items, we scale the drawing of those display items so that the child ThebesLayers are simply larger or smaller (larger or smaller visible regions). We have to scale all visible rects, clip rects etc that are in the coordinates of ThebesLayers or the parent ContainerLayer. To keep things simple we do this whenever we convert from appunits to integer layer coordinates. When a ThebesLayer's resolution changes we need to rerender the whole thing. nsDisplayList::PaintForFrame needs to respect the presshell's resolution setting. We do that by building a layer tree with a ContainerParameters requesting a scale up by the presshell resolution; once that layer tree is built, we adjust the root layer transform to scale back down by the resolution.
2011-06-22 05:11:27 -07:00
*
* When we construct a container layer, we know the transform that will be
* applied to the layer. If the transform scales the content, we can get
* better results when intermediate buffers are used by pushing some scale
* from the container's transform down to the children. For ThebesLayer
* children, the scaling can be achieved by changing the size of the layer
* and drawing into it with increased or decreased resolution. By convention,
* integer types (nsIntPoint/nsIntSize/nsIntRect/nsIntRegion) are all in layer
* coordinates, post-scaling, whereas appunit types are all pre-scaling.
*/
class FrameLayerBuilder : public layers::LayerUserData {
public:
typedef layers::ContainerLayer ContainerLayer;
typedef layers::Layer Layer;
typedef layers::ThebesLayer ThebesLayer;
typedef layers::LayerManager LayerManager;
FrameLayerBuilder() :
mRetainingManager(nsnull),
mDetectedDOMModification(false),
mInvalidateAllLayers(false),
mContainerLayerGeneration(0),
mMaxContainerLayerGeneration(0)
{
MOZ_COUNT_CTOR(FrameLayerBuilder);
mNewDisplayItemData.Init();
mThebesLayerItems.Init();
}
~FrameLayerBuilder()
{
MOZ_COUNT_DTOR(FrameLayerBuilder);
}
static void Shutdown();
void Init(nsDisplayListBuilder* aBuilder);
/**
* Call this to notify that we have just started a transaction on the
* retained layer manager aManager.
*/
void DidBeginRetainedLayerTransaction(LayerManager* aManager);
/**
* Call this just before we end a transaction on aManager. If aManager
* is not the retained layer manager then it must be a temporary layer
* manager that will not be used again.
*/
void WillEndTransaction();
/**
* Call this after we end a transaction on aManager. If aManager
* is not the retained layer manager then it must be a temporary layer
* manager that will not be used again.
*/
void DidEndTransaction();
struct ContainerParameters {
ContainerParameters() :
mXScale(1), mYScale(1),
mInTransformedSubtree(false), mInActiveTransformedSubtree(false),
mDisableSubpixelAntialiasingInDescendants(false)
{}
Bug 637852. Part 6: Implement resolution scaling in FrameLayerBuilder. r=tnikkel FrameLayerBuilder::BuildContainerLayerFor takes responsibility for resolution scaling. The ContainerParameters passed in are added to any transform requested. Then we extract the scale part of the transform, round the scale up to the nearest power of two if the transform may be actively animated (so we don't have to redraw layer contents constantly), pass that scale down to be applied by each child and set the residual transform on the ContainerLayer. For child layers built via BuildLayer, we just pass the requested scale factor in via the ContainerParameters. If the returned layer is a ContainerLayer then BuildLayer is guaranteed to have already done necessary scaling. If the returned layer is not a ContainerLayer then we apply the scale ourselves by adding the scale to the child layer's transform. For child ThebesLayers containing non-layer display items, we scale the drawing of those display items so that the child ThebesLayers are simply larger or smaller (larger or smaller visible regions). We have to scale all visible rects, clip rects etc that are in the coordinates of ThebesLayers or the parent ContainerLayer. To keep things simple we do this whenever we convert from appunits to integer layer coordinates. When a ThebesLayer's resolution changes we need to rerender the whole thing. nsDisplayList::PaintForFrame needs to respect the presshell's resolution setting. We do that by building a layer tree with a ContainerParameters requesting a scale up by the presshell resolution; once that layer tree is built, we adjust the root layer transform to scale back down by the resolution.
2011-06-22 05:11:27 -07:00
ContainerParameters(float aXScale, float aYScale) :
mXScale(aXScale), mYScale(aYScale),
mInTransformedSubtree(false), mInActiveTransformedSubtree(false),
mDisableSubpixelAntialiasingInDescendants(false)
{}
ContainerParameters(float aXScale, float aYScale,
const ContainerParameters& aParent) :
mXScale(aXScale), mYScale(aYScale),
mInTransformedSubtree(aParent.mInTransformedSubtree),
mInActiveTransformedSubtree(aParent.mInActiveTransformedSubtree),
mDisableSubpixelAntialiasingInDescendants(aParent.mDisableSubpixelAntialiasingInDescendants)
{}
Bug 637852. Part 6: Implement resolution scaling in FrameLayerBuilder. r=tnikkel FrameLayerBuilder::BuildContainerLayerFor takes responsibility for resolution scaling. The ContainerParameters passed in are added to any transform requested. Then we extract the scale part of the transform, round the scale up to the nearest power of two if the transform may be actively animated (so we don't have to redraw layer contents constantly), pass that scale down to be applied by each child and set the residual transform on the ContainerLayer. For child layers built via BuildLayer, we just pass the requested scale factor in via the ContainerParameters. If the returned layer is a ContainerLayer then BuildLayer is guaranteed to have already done necessary scaling. If the returned layer is not a ContainerLayer then we apply the scale ourselves by adding the scale to the child layer's transform. For child ThebesLayers containing non-layer display items, we scale the drawing of those display items so that the child ThebesLayers are simply larger or smaller (larger or smaller visible regions). We have to scale all visible rects, clip rects etc that are in the coordinates of ThebesLayers or the parent ContainerLayer. To keep things simple we do this whenever we convert from appunits to integer layer coordinates. When a ThebesLayer's resolution changes we need to rerender the whole thing. nsDisplayList::PaintForFrame needs to respect the presshell's resolution setting. We do that by building a layer tree with a ContainerParameters requesting a scale up by the presshell resolution; once that layer tree is built, we adjust the root layer transform to scale back down by the resolution.
2011-06-22 05:11:27 -07:00
float mXScale, mYScale;
bool mInTransformedSubtree;
bool mInActiveTransformedSubtree;
bool mDisableSubpixelAntialiasingInDescendants;
/**
* When this is false, ThebesLayer coordinates are drawn to with an integer
* translation and the scale in mXScale/mYScale.
*/
bool AllowResidualTranslation()
{
// If we're in a transformed subtree, but no ancestor transform is actively
// changing, we'll use the residual translation when drawing into the
// ThebesLayer to ensure that snapping exactly matches the ideal transform.
return mInTransformedSubtree && !mInActiveTransformedSubtree;
}
};
/**
* Build a container layer for a display item that contains a child
* list, either reusing an existing one or creating a new one. It
* sets the container layer children to layers which together render
* the contents of the display list. It reuses existing layers from
* the retained layer manager if possible.
* aContainer may be null, in which case we construct a root layer.
* This gets called by display list code. It calls BuildLayer on the
* items in the display list, making items with their own layers
* children of the new container, and assigning all other items to
* ThebesLayer children created and managed by the FrameLayerBuilder.
* Returns a layer with clip rect cleared; it is the
* caller's responsibility to add any clip rect. The visible region
* is set based on what's in the layer.
* The container layer is transformed by aTransform (if non-null), and
* the result is transformed by the scale factors in aContainerParameters.
*/
already_AddRefed<ContainerLayer>
BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
nsIFrame* aContainerFrame,
nsDisplayItem* aContainerItem,
const nsDisplayList& aChildren,
const ContainerParameters& aContainerParameters,
const gfx3DMatrix* aTransform);
/**
* Get a retained layer for a display item that needs to create its own
* layer for rendering (i.e. under nsDisplayItem::BuildLayer). Returns
* null if no retained layer is available, which usually means that this
* display item didn't have a layer before so the caller will
* need to create one.
* Returns a layer with clip rect cleared; it is the
* caller's responsibility to add any clip rect and set the visible
* region.
*/
Layer* GetLeafLayerFor(nsDisplayListBuilder* aBuilder,
nsDisplayItem* aItem);
/**
* Call this to force all retained layers to be discarded and recreated at
* the next paint.
*/
static void InvalidateAllLayers(LayerManager* aManager);
/**
* Call this to determine if a frame has a dedicated (non-Thebes) layer
* for the given display item key. If there isn't one, we return null,
* otherwise we return the layer.
*/
static Layer* GetDedicatedLayer(nsIFrame* aFrame, PRUint32 aDisplayItemKey);
/**
* This callback must be provided to EndTransaction. The callback data
* must be the nsDisplayListBuilder containing this FrameLayerBuilder.
*/
static void DrawThebesLayer(ThebesLayer* aLayer,
gfxContext* aContext,
const nsIntRegion& aRegionToDraw,
const nsIntRegion& aRegionToInvalidate,
void* aCallbackData);
#ifdef MOZ_DUMP_PAINTING
/**
* Dumps this FrameLayerBuilder's retained layer manager's retained
* layer tree to stderr.
*/
static void DumpRetainedLayerTree(LayerManager* aManager, FILE* aFile = stdout);
#endif
/******* PRIVATE METHODS to FrameLayerBuilder.cpp ********/
/* These are only in the public section because they need
* to be called by file-scope helper functions in FrameLayerBuilder.cpp.
*/
/**
* Record aItem as a display item that is rendered by aLayer.
*
* @param aLayer Layer that the display item will be rendered into
* @param aItem Display item to be drawn.
* @param aLayerState What LayerState the item is using.
* @param aManager If the layer is in the LAYER_INACTIVE state,
* then this is the temporary layer manager to draw with.
*/
void AddLayerDisplayItem(Layer* aLayer,
nsDisplayItem* aItem,
LayerState aLayerState,
LayerManager* aManager = nsnull);
/**
* Record aItem as a display item that is rendered by the ThebesLayer
* aLayer, with aClipRect, where aContainerLayerFrame is the frame
* for the container layer this ThebesItem belongs to.
* aItem must have an underlying frame.
*/
struct Clip;
void AddThebesDisplayItem(ThebesLayer* aLayer,
nsDisplayItem* aItem,
const Clip& aClip,
nsIFrame* aContainerLayerFrame,
LayerState aLayerState);
/**
* Set the current top-level LayerManager for the widget being
* painted.
*/
static void SetWidgetLayerManager(LayerManager* aManager)
{
LayerManagerSecondary* secondary =
static_cast<LayerManagerSecondary*>(aManager->GetUserData(&gLayerManagerSecondary));
sWidgetManagerSecondary = !!secondary;
}
/**
* Gets the frame property descriptor for the given manager, or for the current
* widget layer manager if nsnull is passed.
*/
static const FramePropertyDescriptor* GetDescriptorForManager(LayerManager* aManager);
/**
* Get the LayerManagerData for a given frame and layer manager. If no layer manager
* is passed, then the current widget layer manager is used.
*/
static LayerManagerData* GetManagerData(nsIFrame* aFrame, LayerManager* aManager = nsnull);
/**
* Set the LayerManagerData for a given frame and current widget layer manager.
* This replaces any existing data for the same frame/layer manager pair.
*/
static void SetManagerData(nsIFrame* aFrame, LayerManagerData* aData);
/**
* Clears the current LayerManagerData for the given frame and current widget
* layer manager.
*/
static void ClearManagerData(nsIFrame* aFrame);
/**
* Clears any references to the given LayerManagerData for the given frame
* and belonging to any layer manager.
*/
static void ClearManagerData(nsIFrame* aFrame, LayerManagerData* aData);
/**
* Given a frame and a display item key that uniquely identifies a
* display item for the frame, find the layer that was last used to
* render that display item. Returns null if there is no such layer.
* This could be a dedicated layer for the display item, or a ThebesLayer
* that renders many display items.
*/
Layer* GetOldLayerFor(nsIFrame* aFrame, PRUint32 aDisplayItemKey, nsDisplayItemGeometry** aOldGeometry = nsnull);
static Layer* GetDebugOldLayerFor(nsIFrame* aFrame, PRUint32 aDisplayItemKey);
/**
* If the display item was previously drawn as an inactive layer,
* then return the layer manager used for the inactive transaction.
* Returns nsnull if no manager could be found.
*/
LayerManager* GetInactiveLayerManagerFor(nsDisplayItem* aItem);
/**
* Try to determine whether the ThebesLayer aLayer paints an opaque
* single color everywhere it's visible in aRect.
* If successful, return that color, otherwise return NS_RGBA(0,0,0,0).
*/
nscolor FindOpaqueColorCovering(nsDisplayListBuilder* aBuilder,
ThebesLayer* aLayer, const nsRect& aRect);
/**
* Destroy any stored LayerManagerDataProperty and the associated data for
* aFrame.
*/
static void DestroyDisplayItemDataFor(nsIFrame* aFrame);
LayerManager* GetRetainingLayerManager() { return mRetainingManager; }
/**
* Returns true if the given item (which we assume here is
* background-attachment:fixed) needs to be repainted as we scroll in its
* document.
* Returns false if it doesn't need to be repainted because the layer system
* is ensuring its fixed-ness for us.
*/
static bool NeedToInvalidateFixedDisplayItem(nsDisplayListBuilder* aBuilder,
nsDisplayItem* aItem);
/**
* Returns true if the given display item was rendered directly
* into a retained layer.
* Returns false if it was rendered into a temporary layer manager and then
* into a retained layer.
*
* Since display items can belong to multiple retained LayerManagers, we need to
* specify which LayerManager to check.
*/
static bool HasRetainedLayerFor(nsIFrame* aFrame, PRUint32 aDisplayItemKey, LayerManager* aManager);
/**
* Save transform that was in aLayer when we last painted. It must be an integer
* translation.
*/
void SaveLastPaintOffset(ThebesLayer* aLayer);
/**
* Get the translation transform that was in aLayer when we last painted. It's either
* the transform saved by SaveLastPaintTransform, or else the transform
* that's currently in the layer (which must be an integer translation).
*/
nsIntPoint GetLastPaintOffset(ThebesLayer* aLayer);
/**
* Return resolution and scroll offset of ThebesLayer content associated
* with aFrame's subtree.
* Returns true if some ThebesLayer was found.
* This just looks for the first ThebesLayer and returns its data. There
* could be other ThebesLayers with different resolution and offsets.
*/
static bool GetThebesLayerResolutionForFrame(nsIFrame* aFrame,
double* aXRes, double* aYRes,
gfxPoint* aPoint);
/**
* Clip represents the intersection of an optional rectangle with a
* list of rounded rectangles.
*/
struct Clip {
struct RoundedRect {
nsRect mRect;
// Indices into mRadii are the NS_CORNER_* constants in nsStyleConsts.h
nscoord mRadii[8];
bool operator==(const RoundedRect& aOther) const {
if (!mRect.IsEqualInterior(aOther.mRect)) {
return false;
}
NS_FOR_CSS_HALF_CORNERS(corner) {
if (mRadii[corner] != aOther.mRadii[corner]) {
return false;
}
}
return true;
}
bool operator!=(const RoundedRect& aOther) const {
return !(*this == aOther);
}
};
nsRect mClipRect;
nsTArray<RoundedRect> mRoundedClipRects;
bool mHaveClipRect;
Clip() : mHaveClipRect(false) {}
// Construct as the intersection of aOther and aClipItem.
Clip(const Clip& aOther, nsDisplayItem* aClipItem);
// Apply this |Clip| to the given gfxContext. Any saving of state
// or clearing of other clips must be done by the caller.
// See aBegin/aEnd note on ApplyRoundedRectsTo.
void ApplyTo(gfxContext* aContext, nsPresContext* aPresContext,
PRUint32 aBegin = 0, PRUint32 aEnd = PR_UINT32_MAX);
void ApplyRectTo(gfxContext* aContext, PRInt32 A2D) const;
// Applies the rounded rects in this Clip to aContext
// Will only apply rounded rects from aBegin (inclusive) to aEnd
// (exclusive) or the number of rounded rects, whichever is smaller.
void ApplyRoundedRectsTo(gfxContext* aContext, PRInt32 A2DPRInt32,
PRUint32 aBegin, PRUint32 aEnd) const;
// Draw (fill) the rounded rects in this clip to aContext
void DrawRoundedRectsTo(gfxContext* aContext, PRInt32 A2D,
PRUint32 aBegin, PRUint32 aEnd) const;
// 'Draw' (create as a path, does not stroke or fill) aRoundRect to aContext
void AddRoundedRectPathTo(gfxContext* aContext, PRInt32 A2D,
const RoundedRect &aRoundRect) const;
// Return a rectangle contained in the intersection of aRect with this
// clip region. Tries to return the largest possible rectangle, but may
// not succeed.
nsRect ApproximateIntersect(const nsRect& aRect) const;
// Returns false if aRect is definitely not clipped by a rounded corner in
// this clip. Returns true if aRect is clipped by a rounded corner in this
// clip or it can not be quickly determined that it is not clipped by a
// rounded corner in this clip.
bool IsRectClippedByRoundedCorner(const nsRect& aRect) const;
// Intersection of all rects in this clip ignoring any rounded corners.
nsRect NonRoundedIntersection() const;
// Gets rid of any rounded corners in this clip.
void RemoveRoundedCorners();
bool operator==(const Clip& aOther) const {
return mHaveClipRect == aOther.mHaveClipRect &&
(!mHaveClipRect || mClipRect.IsEqualInterior(aOther.mClipRect)) &&
mRoundedClipRects == aOther.mRoundedClipRects;
}
bool operator!=(const Clip& aOther) const {
return !(*this == aOther);
}
};
NS_DECLARE_FRAME_PROPERTY_WITH_FRAME_IN_DTOR(LayerManagerDataProperty,
RemoveFrameFromLayerManager)
NS_DECLARE_FRAME_PROPERTY_WITH_FRAME_IN_DTOR(LayerManagerSecondaryDataProperty,
RemoveFrameFromLayerManager)
protected:
/**
* We store an array of these for each frame that is associated with
* one or more retained layers. Each DisplayItemData records the layer
* used to render one of the frame's display items.
*/
class DisplayItemData {
public:
DisplayItemData(Layer* aLayer, PRUint32 aKey, LayerState aLayerState, PRUint32 aGeneration)
: mLayer(aLayer)
, mDisplayItemKey(aKey)
, mContainerLayerGeneration(aGeneration)
, mLayerState(aLayerState)
, mUsed(false)
{}
DisplayItemData()
: mUsed(false)
{}
DisplayItemData(DisplayItemData &toCopy)
{
// This isn't actually a copy-constructor; notice that it steals toCopy's
// mGeometry pointer. Be careful.
mLayer = toCopy.mLayer;
mInactiveManager = toCopy.mInactiveManager;
mGeometry = toCopy.mGeometry;
mDisplayItemKey = toCopy.mDisplayItemKey;
mContainerLayerGeneration = toCopy.mContainerLayerGeneration;
mLayerState = toCopy.mLayerState;
mUsed = toCopy.mUsed;
}
nsRefPtr<Layer> mLayer;
nsRefPtr<LayerManager> mInactiveManager;
nsAutoPtr<nsDisplayItemGeometry> mGeometry;
PRUint32 mDisplayItemKey;
PRUint32 mContainerLayerGeneration;
LayerState mLayerState;
/**
* Used to track if data currently stored in mFramesWithLayers (from an existing
* paint) is also used in the current paint and has an equivalent data object
* in mNewDisplayItemData.
*/
bool mUsed;
};
// LayerManagerData needs to see DisplayItemDataEntry.
friend class LayerManagerData;
static void RemoveFrameFromLayerManager(nsIFrame* aFrame, void* aPropertyValue);
/**
* We accumulate DisplayItemData elements in a hashtable during
* the paint process, and store them in the frame property only when
* paint is complete. This is the hashentry for that hashtable.
*/
class DisplayItemDataEntry : public nsPtrHashKey<nsIFrame> {
public:
DisplayItemDataEntry(const nsIFrame *key) : nsPtrHashKey<nsIFrame>(key) { MOZ_COUNT_CTOR(DisplayItemDataEntry); }
DisplayItemDataEntry(DisplayItemDataEntry &toCopy) :
nsPtrHashKey<nsIFrame>(toCopy.mKey)
{
MOZ_COUNT_CTOR(DisplayItemDataEntry);
// This isn't actually a copy-constructor; notice that it steals toCopy's
// array. Be careful.
mData.SwapElements(toCopy.mData);
mContainerLayerGeneration = toCopy.mContainerLayerGeneration;
}
~DisplayItemDataEntry() { MOZ_COUNT_DTOR(DisplayItemDataEntry); }
bool HasNonEmptyContainerLayer();
nsAutoTArray<DisplayItemData, 1> mData;
PRUint32 mContainerLayerGeneration;
enum { ALLOW_MEMMOVE = false };
};
/**
* Stores DisplayItemData associated with aFrame, stores the data in
* mNewDisplayItemData.
*/
void StoreDataForFrame(nsIFrame* aFrame, DisplayItemData& data);
// Flash the area within the context clip if paint flashing is enabled.
static void FlashPaint(gfxContext *aContext);
/*
* Get the DisplayItemData array associated with this frame, or null if one
* doesn't exist.
*
* Note that the pointer returned here is only valid so long as you don't
* poke the LayerManagerData's mFramesWithLayers hashtable.
*/
nsTArray<DisplayItemData>* GetDisplayItemDataArrayForFrame(nsIFrame *aFrame);
/*
* Get the DisplayItemData associated with this frame / display item pair,
* using the LayerManager instead of FrameLayerBuilder.
*/
static DisplayItemData* GetDisplayItemDataForManager(nsIFrame* aFrame,
PRUint32 aDisplayItemKey,
LayerManager* aManager);
static DisplayItemData* GetDisplayItemDataForManager(nsDisplayItem* aItem, LayerManager* aManager);
/**
* A useful hashtable iteration function that removes the
* DisplayItemData property for the frame, clears its
* NS_FRAME_HAS_CONTAINER_LAYER bit and returns PL_DHASH_REMOVE.
* aClosure is ignored.
*/
static PLDHashOperator RemoveDisplayItemDataForFrame(DisplayItemDataEntry* aEntry,
void* aClosure);
/**
* We store one of these for each display item associated with a
* ThebesLayer, in a hashtable that maps each ThebesLayer to an array
* of ClippedDisplayItems. (ThebesLayerItemsEntry is the hash entry
* for that hashtable.)
* These are only stored during the paint process, so that the
* DrawThebesLayer callback can figure out which items to draw for the
* ThebesLayer.
* mItem always has an underlying frame.
*/
struct ClippedDisplayItem {
ClippedDisplayItem(nsDisplayItem* aItem, const Clip& aClip, PRUint32 aGeneration)
: mItem(aItem), mClip(aClip), mContainerLayerGeneration(aGeneration)
{
}
~ClippedDisplayItem();
nsDisplayItem* mItem;
/**
* If the display item is being rendered as an inactive
* layer, then this stores the layer manager being
* used for the inactive transaction.
*/
nsRefPtr<LayerManager> mInactiveLayer;
Clip mClip;
PRUint32 mContainerLayerGeneration;
};
/**
* We accumulate ClippedDisplayItem elements in a hashtable during
* the paint process. This is the hashentry for that hashtable.
*/
public:
class ThebesLayerItemsEntry : public nsPtrHashKey<ThebesLayer> {
public:
ThebesLayerItemsEntry(const ThebesLayer *key) :
nsPtrHashKey<ThebesLayer>(key), mContainerLayerFrame(nsnull),
mHasExplicitLastPaintOffset(false), mCommonClipCount(0) {}
ThebesLayerItemsEntry(const ThebesLayerItemsEntry &toCopy) :
nsPtrHashKey<ThebesLayer>(toCopy.mKey), mItems(toCopy.mItems)
{
NS_ERROR("Should never be called, since we ALLOW_MEMMOVE");
}
nsTArray<ClippedDisplayItem> mItems;
nsIFrame* mContainerLayerFrame;
// The translation set on this ThebesLayer before we started updating the
// layer tree.
nsIntPoint mLastPaintOffset;
PRUint32 mContainerLayerGeneration;
bool mHasExplicitLastPaintOffset;
/**
* The first mCommonClipCount rounded rectangle clips are identical for
* all items in the layer. Computed in ThebesLayerData.
*/
PRUint32 mCommonClipCount;
enum { ALLOW_MEMMOVE = true };
};
/**
* Get the ThebesLayerItemsEntry object associated with aLayer in this
* FrameLayerBuilder
*/
ThebesLayerItemsEntry* GetThebesLayerItemsEntry(ThebesLayer* aLayer)
{
return mThebesLayerItems.GetEntry(aLayer);
}
static PLDHashOperator ProcessRemovedDisplayItems(DisplayItemDataEntry* aEntry,
void* aUserArg);
protected:
void RemoveThebesItemsForLayerSubtree(Layer* aLayer);
static PLDHashOperator UpdateDisplayItemDataForFrame(DisplayItemDataEntry* aEntry,
void* aUserArg);
static PLDHashOperator StoreNewDisplayItemData(DisplayItemDataEntry* aEntry,
void* aUserArg);
static PLDHashOperator RestoreDisplayItemData(DisplayItemDataEntry* aEntry,
void *aUserArg);
static PLDHashOperator RestoreThebesLayerItemEntries(ThebesLayerItemsEntry* aEntry,
void *aUserArg);
/**
* Returns true if the DOM has been modified since we started painting,
* in which case we should bail out and not paint anymore. This should
* never happen, but plugins can trigger it in some cases.
*/
bool CheckDOMModified();
/**
* The layer manager belonging to the widget that is being retained
* across paints.
*/
LayerManager* mRetainingManager;
/**
* The root prescontext for the display list builder reference frame
*/
nsRootPresContext* mRootPresContext;
/**
* The display list builder being used.
*/
nsDisplayListBuilder* mDisplayListBuilder;
/**
* A map from frames to a list of (display item key, layer) pairs that
* describes what layers various parts of the frame are assigned to.
*/
nsTHashtable<DisplayItemDataEntry> mNewDisplayItemData;
/**
* A map from ThebesLayers to the list of display items (plus
* clipping data) to be rendered in the layer.
*/
nsTHashtable<ThebesLayerItemsEntry> mThebesLayerItems;
/**
* Saved generation counter so we can detect DOM changes.
*/
PRUint32 mInitialDOMGeneration;
/**
* Set to true if we have detected and reported DOM modification during
* the current paint.
*/
bool mDetectedDOMModification;
/**
* Indicates that the entire layer tree should be rerendered
* during this paint.
*/
bool mInvalidateAllLayers;
PRUint32 mContainerLayerGeneration;
PRUint32 mMaxContainerLayerGeneration;
/**
* True if the current top-level LayerManager for the widget being
* painted is marked as being a 'secondary' LayerManager.
*/
static bool sWidgetManagerSecondary;
};
static inline FrameLayerBuilder *GetLayerBuilderForManager(layers::LayerManager* aManager)
{
return static_cast<FrameLayerBuilder*>(aManager->GetUserData(&gLayerManagerLayerBuilder));
}
}
#endif /* FRAMELAYERBUILDER_H_ */