1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is Mozilla Corporation code.
17 * The Initial Developer of the Original Code is Mozilla Foundation.
18 * Portions created by the Initial Developer are Copyright (C) 2010
19 * the Initial Developer. All Rights Reserved.
22 * Robert O'Callahan <robert@ocallahan.org>
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #ifndef FRAMELAYERBUILDER_H_
39 #define FRAMELAYERBUILDER_H_
41 #include "nsTHashtable.h"
42 #include "nsHashKeys.h"
48 class nsDisplayListBuilder
;
52 class nsRootPresContext
;
63 * The FrameLayerBuilder belongs to an nsDisplayListBuilder and is
64 * responsible for converting display lists into layer trees.
66 * The most important API in this class is BuildContainerLayerFor. This
67 * method takes a display list as input and constructs a ContainerLayer
68 * with child layers that render the contents of the display list. It
69 * also updates userdata for the retained layer manager, and
70 * DisplayItemDataProperty data for frames, to record the relationship
71 * between frames and layers.
73 * That data enables us to retain layer trees. When constructing a
74 * ContainerLayer, we first check to see if there's an existing
75 * ContainerLayer for the same frame that can be recycled. If we recycle
76 * it, we also try to reuse its existing ThebesLayer children to render
77 * the display items without layers of their own. The idea is that by
78 * recycling layers deterministically, we can ensure that when nothing
79 * changes in a display list, we will reuse the existing layers without
82 * We expose a GetLeafLayerFor method that can be called by display items
83 * that make their own layers (e.g. canvas and video); this method
84 * locates the last layer used to render the display item, if any, and
85 * return it as a candidate for recycling.
87 * FrameLayerBuilder sets up ThebesLayers so that 0,0 in the Thebes layer
88 * corresponds to the (pixel-snapped) top-left of the aActiveScrolledRoot.
89 * It sets up ContainerLayers so that 0,0 in the container layer
90 * corresponds to the snapped top-left of the display list reference frame.
92 class FrameLayerBuilder
{
94 typedef layers::ContainerLayer ContainerLayer
;
95 typedef layers::Layer Layer
;
96 typedef layers::ThebesLayer ThebesLayer
;
97 typedef layers::LayerManager LayerManager
;
100 mRetainingManager(nsnull
),
101 mDetectedDOMModification(PR_FALSE
),
102 mInvalidateAllLayers(PR_FALSE
)
104 mNewDisplayItemData
.Init();
105 mThebesLayerItems
.Init();
108 void Init(nsDisplayListBuilder
* aBuilder
);
111 * Call this to notify that we have just started a transaction on the
112 * retained layer manager aManager.
114 void DidBeginRetainedLayerTransaction(LayerManager
* aManager
);
117 * Call this just before we end a transaction on aManager. If aManager
118 * is not the retained layer manager then it must be a temporary layer
119 * manager that will not be used again.
121 void WillEndTransaction(LayerManager
* aManager
);
124 * Call this after we end a transaction on aManager. If aManager
125 * is not the retained layer manager then it must be a temporary layer
126 * manager that will not be used again.
128 void DidEndTransaction(LayerManager
* aManager
);
131 * Build a container layer for a display item that contains a child
132 * list, either reusing an existing one or creating a new one. It
133 * sets the container layer children to layers which together render
134 * the contents of the display list. It reuses existing layers from
135 * the retained layer manager if possible.
136 * aContainer may be null, in which case we construct a root layer.
137 * This gets called by display list code. It calls BuildLayer on the
138 * items in the display list, making items with their own layers
139 * children of the new container, and assigning all other items to
140 * ThebesLayer children created and managed by the FrameLayerBuilder.
141 * Returns a layer with clip rect cleared; it is the
142 * caller's responsibility to add any clip rect and set the visible
145 already_AddRefed
<ContainerLayer
>
146 BuildContainerLayerFor(nsDisplayListBuilder
* aBuilder
,
147 LayerManager
* aManager
,
148 nsIFrame
* aContainerFrame
,
149 nsDisplayItem
* aContainerItem
,
150 const nsDisplayList
& aChildren
);
153 * Get a retained layer for a display item that needs to create its own
154 * layer for rendering (i.e. under nsDisplayItem::BuildLayer). Returns
155 * null if no retained layer is available, which usually means that this
156 * display item didn't have a layer before so the caller will
157 * need to create one.
158 * Returns a layer with clip rect cleared; it is the
159 * caller's responsibility to add any clip rect and set the visible
162 Layer
* GetLeafLayerFor(nsDisplayListBuilder
* aBuilder
,
163 LayerManager
* aManager
,
164 nsDisplayItem
* aItem
);
167 * Call this during invalidation if aFrame has
168 * the NS_FRAME_HAS_CONTAINER_LAYER state bit. Only the nearest
169 * ancestor frame of the damaged frame that has
170 * NS_FRAME_HAS_CONTAINER_LAYER needs to be invalidated this way.
172 static void InvalidateThebesLayerContents(nsIFrame
* aFrame
,
173 const nsRect
& aRect
);
176 * For any descendant frame of aFrame (including across documents) that
177 * has an associated container layer, invalidate all the contents of
178 * all ThebesLayer children of the container. Useful when aFrame is
179 * being moved and we need to invalidate everything in aFrame's subtree.
181 static void InvalidateThebesLayersInSubtree(nsIFrame
* aFrame
);
184 * Call this to force all retained layers to be discarded and recreated at
187 static void InvalidateAllLayers(LayerManager
* aManager
);
190 * Call this to determine if a frame has a dedicated (non-Thebes) layer
191 * for the given display item key.
193 static PRBool
HasDedicatedLayer(nsIFrame
* aFrame
, PRUint32 aDisplayItemKey
);
196 * This callback must be provided to EndTransaction. The callback data
197 * must be the nsDisplayListBuilder containing this FrameLayerBuilder.
199 static void DrawThebesLayer(ThebesLayer
* aLayer
,
200 gfxContext
* aContext
,
201 const nsIntRegion
& aRegionToDraw
,
202 const nsIntRegion
& aRegionToInvalidate
,
203 void* aCallbackData
);
207 * Dumps this FrameLayerBuilder's retained layer manager's retained
208 * layer tree to stderr.
210 void DumpRetainedLayerTree();
213 /******* PRIVATE METHODS to FrameLayerBuilder.cpp ********/
214 /* These are only in the public section because they need
215 * to be called by file-scope helper functions in FrameLayerBuilder.cpp.
219 * Record aItem as a display item that is rendered by aLayer.
221 void AddLayerDisplayItem(Layer
* aLayer
, nsDisplayItem
* aItem
);
224 * Record aItem as a display item that is rendered by the ThebesLayer
225 * aLayer, with aClipRect, where aContainerLayerFrame is the frame
226 * for the container layer this ThebesItem belongs to.
227 * aItem must have an underlying frame.
230 void AddThebesDisplayItem(ThebesLayer
* aLayer
,
231 nsDisplayItem
* aItem
,
233 nsIFrame
* aContainerLayerFrame
,
234 LayerState aLayerState
);
237 * Given a frame and a display item key that uniquely identifies a
238 * display item for the frame, find the layer that was last used to
239 * render that display item. Returns null if there is no such layer.
240 * This could be a dedicated layer for the display item, or a ThebesLayer
241 * that renders many display items.
243 Layer
* GetOldLayerFor(nsIFrame
* aFrame
, PRUint32 aDisplayItemKey
);
246 * A useful hashtable iteration function that removes the
247 * DisplayItemData property for the frame, clears its
248 * NS_FRAME_HAS_CONTAINER_LAYER bit and returns PL_DHASH_REMOVE.
249 * aClosure is ignored.
251 static PLDHashOperator
RemoveDisplayItemDataForFrame(nsPtrHashKey
<nsIFrame
>* aEntry
,
254 return UpdateDisplayItemDataForFrame(aEntry
, nsnull
);
258 * Try to determine whether the ThebesLayer aLayer paints an opaque
259 * single color everywhere it's visible in aRect.
260 * If successful, return that color, otherwise return NS_RGBA(0,0,0,0).
262 nscolor
FindOpaqueColorCovering(nsDisplayListBuilder
* aBuilder
,
263 ThebesLayer
* aLayer
, const nsRect
& aRect
);
266 * Destroy any stored DisplayItemDataProperty for aFrame.
268 static void DestroyDisplayItemDataFor(nsIFrame
* aFrame
)
270 aFrame
->Properties().Delete(DisplayItemDataProperty());
273 LayerManager
* GetRetainingLayerManager() { return mRetainingManager
; }
276 * Returns true if the given item (which we assume here is
277 * background-attachment:fixed) needs to be repainted as we scroll in its
279 * Returns false if it doesn't need to be repainted because the layer system
280 * is ensuring its fixed-ness for us.
282 static PRBool
NeedToInvalidateFixedDisplayItem(nsDisplayListBuilder
* aBuilder
,
283 nsDisplayItem
* aItem
);
286 * Returns true if the given display item was rendered directly
287 * into a retained layer.
288 * Returns false if it was rendered into a temporary layer manager and then
289 * into a retained layer.
291 static PRBool
HasRetainedLayerFor(nsIFrame
* aFrame
, PRUint32 aDisplayItemKey
);
294 * Clip represents the intersection of an optional rectangle with a
295 * list of rounded rectangles.
300 // Indices into mRadii are the NS_CORNER_* constants in nsStyleConsts.h
303 bool operator==(const RoundedRect
& aOther
) const {
304 if (mRect
!= aOther
.mRect
) {
308 NS_FOR_CSS_HALF_CORNERS(corner
) {
309 if (mRadii
[corner
] != aOther
.mRadii
[corner
]) {
315 bool operator!=(const RoundedRect
& aOther
) const {
316 return !(*this == aOther
);
320 nsTArray
<RoundedRect
> mRoundedClipRects
;
321 PRPackedBool mHaveClipRect
;
323 Clip() : mHaveClipRect(PR_FALSE
) {}
325 // Construct as the intersection of aOther and aClipItem.
326 Clip(const Clip
& aOther
, nsDisplayItem
* aClipItem
);
328 // Apply this |Clip| to the given gfxContext. Any saving of state
329 // or clearing of other clips must be done by the caller.
330 void ApplyTo(gfxContext
* aContext
, nsPresContext
* aPresContext
);
332 // Return a rectangle contained in the intersection of aRect with this
333 // clip region. Tries to return the largest possible rectangle, but may
335 nsRect
ApproximateIntersect(const nsRect
& aRect
) const;
337 // Returns false if aRect is definitely not clipped by a rounded corner in
338 // this clip. Returns true if aRect is clipped by a rounded corner in this
339 // clip or it can not be quickly determined that it is not clipped by a
340 // rounded corner in this clip.
341 bool IsRectClippedByRoundedCorner(const nsRect
& aRect
) const;
343 // Intersection of all rects in this clip ignoring any rounded corners.
344 nsRect
NonRoundedIntersection() const;
346 // Gets rid of any rounded corners in this clip.
347 void RemoveRoundedCorners();
349 bool operator==(const Clip
& aOther
) const {
350 return mHaveClipRect
== aOther
.mHaveClipRect
&&
351 (!mHaveClipRect
|| mClipRect
== aOther
.mClipRect
) &&
352 mRoundedClipRects
== aOther
.mRoundedClipRects
;
354 bool operator!=(const Clip
& aOther
) const {
355 return !(*this == aOther
);
361 * We store an array of these for each frame that is associated with
362 * one or more retained layers. Each DisplayItemData records the layer
363 * used to render one of the frame's display items.
365 class DisplayItemData
{
367 DisplayItemData(Layer
* aLayer
, PRUint32 aKey
)
368 : mLayer(aLayer
), mDisplayItemKey(aKey
) {}
370 nsRefPtr
<Layer
> mLayer
;
371 PRUint32 mDisplayItemKey
;
374 static void InternalDestroyDisplayItemData(nsIFrame
* aFrame
,
375 void* aPropertyValue
,
376 PRBool aRemoveFromFramesWithLayers
);
377 static void DestroyDisplayItemData(nsIFrame
* aFrame
, void* aPropertyValue
);
380 * For DisplayItemDataProperty, the property value *is* an
381 * nsTArray<DisplayItemData>, not a pointer to an array. This works
382 * because sizeof(nsTArray<T>) == sizeof(void*).
384 NS_DECLARE_FRAME_PROPERTY_WITH_FRAME_IN_DTOR(DisplayItemDataProperty
,
385 DestroyDisplayItemData
)
388 * We accumulate DisplayItemData elements in a hashtable during
389 * the paint process, and store them in the frame property only when
390 * paint is complete. This is the hashentry for that hashtable.
392 class DisplayItemDataEntry
: public nsPtrHashKey
<nsIFrame
> {
394 DisplayItemDataEntry(const nsIFrame
*key
) : nsPtrHashKey
<nsIFrame
>(key
) {}
395 DisplayItemDataEntry(const DisplayItemDataEntry
&toCopy
) :
396 nsPtrHashKey
<nsIFrame
>(toCopy
.mKey
), mData(toCopy
.mData
)
398 NS_ERROR("Should never be called, since we ALLOW_MEMMOVE");
401 PRBool
HasContainerLayer();
403 nsTArray
<DisplayItemData
> mData
;
405 enum { ALLOW_MEMMOVE
= PR_TRUE
};
409 * We store one of these for each display item associated with a
410 * ThebesLayer, in a hashtable that maps each ThebesLayer to an array
411 * of ClippedDisplayItems. (ThebesLayerItemsEntry is the hash entry
412 * for that hashtable.)
413 * These are only stored during the paint process, so that the
414 * DrawThebesLayer callback can figure out which items to draw for the
416 * mItem always has an underlying frame.
418 struct ClippedDisplayItem
{
419 ClippedDisplayItem(nsDisplayItem
* aItem
, const Clip
& aClip
)
420 : mItem(aItem
), mClip(aClip
)
424 nsDisplayItem
* mItem
;
426 PRPackedBool mInactiveLayer
;
430 * We accumulate ClippedDisplayItem elements in a hashtable during
431 * the paint process. This is the hashentry for that hashtable.
433 class ThebesLayerItemsEntry
: public nsPtrHashKey
<ThebesLayer
> {
435 ThebesLayerItemsEntry(const ThebesLayer
*key
) : nsPtrHashKey
<ThebesLayer
>(key
) {}
436 ThebesLayerItemsEntry(const ThebesLayerItemsEntry
&toCopy
) :
437 nsPtrHashKey
<ThebesLayer
>(toCopy
.mKey
), mItems(toCopy
.mItems
)
439 NS_ERROR("Should never be called, since we ALLOW_MEMMOVE");
442 nsTArray
<ClippedDisplayItem
> mItems
;
443 nsIFrame
* mContainerLayerFrame
;
445 enum { ALLOW_MEMMOVE
= PR_TRUE
};
448 void RemoveThebesItemsForLayerSubtree(Layer
* aLayer
);
450 static PLDHashOperator
UpdateDisplayItemDataForFrame(nsPtrHashKey
<nsIFrame
>* aEntry
,
452 static PLDHashOperator
StoreNewDisplayItemData(DisplayItemDataEntry
* aEntry
,
456 * Returns true if the DOM has been modified since we started painting,
457 * in which case we should bail out and not paint anymore. This should
458 * never happen, but plugins can trigger it in some cases.
460 PRBool
CheckDOMModified();
463 * The layer manager belonging to the widget that is being retained
466 LayerManager
* mRetainingManager
;
468 * The root prescontext for the display list builder reference frame
470 nsRootPresContext
* mRootPresContext
;
472 * A map from frames to a list of (display item key, layer) pairs that
473 * describes what layers various parts of the frame are assigned to.
475 nsTHashtable
<DisplayItemDataEntry
> mNewDisplayItemData
;
477 * A map from ThebesLayers to the list of display items (plus
478 * clipping data) to be rendered in the layer.
480 nsTHashtable
<ThebesLayerItemsEntry
> mThebesLayerItems
;
482 * Saved generation counter so we can detect DOM changes.
484 PRUint32 mInitialDOMGeneration
;
486 * Set to true if we have detected and reported DOM modification during
489 PRPackedBool mDetectedDOMModification
;
491 * Indicates that the entire layer tree should be rerendered
494 PRPackedBool mInvalidateAllLayers
;
499 #endif /* FRAMELAYERBUILDER_H_ */