Merge mozilla-central and tracemonkey. (a=blockers)
[mozilla-central.git] / layout / base / FrameLayerBuilder.h
blob9142b9c4afa0377ad90113fd4559449e2711e021
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
13 * License.
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.
21 * Contributor(s):
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"
43 #include "nsTArray.h"
44 #include "nsRegion.h"
45 #include "nsIFrame.h"
46 #include "Layers.h"
48 class nsDisplayListBuilder;
49 class nsDisplayList;
50 class nsDisplayItem;
51 class gfxContext;
52 class nsRootPresContext;
54 namespace mozilla {
56 enum LayerState {
57 LAYER_NONE,
58 LAYER_INACTIVE,
59 LAYER_ACTIVE
62 /**
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
80 * changes.
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 {
93 public:
94 typedef layers::ContainerLayer ContainerLayer;
95 typedef layers::Layer Layer;
96 typedef layers::ThebesLayer ThebesLayer;
97 typedef layers::LayerManager LayerManager;
99 FrameLayerBuilder() :
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
143 * region.
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
160 * region.
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
185 * the next paint.
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);
205 #ifdef DEBUG
207 * Dumps this FrameLayerBuilder's retained layer manager's retained
208 * layer tree to stderr.
210 void DumpRetainedLayerTree();
211 #endif
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.
229 struct Clip;
230 void AddThebesDisplayItem(ThebesLayer* aLayer,
231 nsDisplayItem* aItem,
232 const Clip& aClip,
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,
252 void* aClosure)
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
278 * document.
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.
297 struct Clip {
298 struct RoundedRect {
299 nsRect mRect;
300 // Indices into mRadii are the NS_CORNER_* constants in nsStyleConsts.h
301 nscoord mRadii[8];
303 bool operator==(const RoundedRect& aOther) const {
304 if (mRect != aOther.mRect) {
305 return false;
308 NS_FOR_CSS_HALF_CORNERS(corner) {
309 if (mRadii[corner] != aOther.mRadii[corner]) {
310 return false;
313 return true;
315 bool operator!=(const RoundedRect& aOther) const {
316 return !(*this == aOther);
319 nsRect mClipRect;
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
334 // not succeed.
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);
359 protected:
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 {
366 public:
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> {
393 public:
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
415 * ThebesLayer.
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;
425 Clip mClip;
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> {
434 public:
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,
451 void* aUserArg);
452 static PLDHashOperator StoreNewDisplayItemData(DisplayItemDataEntry* aEntry,
453 void* aUserArg);
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
464 * across paints.
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
487 * the current paint.
489 PRPackedBool mDetectedDOMModification;
491 * Indicates that the entire layer tree should be rerendered
492 * during this paint.
494 PRPackedBool mInvalidateAllLayers;
499 #endif /* FRAMELAYERBUILDER_H_ */