Bug 615870. Part 2: Track per-display-root-frame 'update layer tree' state bit. r=tnikkel a=b-f
authorRobert O'Callahan <robert@ocallahan.org>
Fri, 10 Dec 2010 21:32:52 +0200
changeset 59684 a07894326d5d034ebdd0245642056ea32cda9638
parent 59683 0a7d57ee6a0a896be712b9caed03f9ec28f30ead
child 59685 ce78f28be4c96d3c77313af1d00f59ad48e12e0e
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewerstnikkel, b-f
bugs615870
milestone2.0b9pre
Bug 615870. Part 2: Track per-display-root-frame 'update layer tree' state bit. r=tnikkel a=b-f
layout/base/nsPresShell.cpp
layout/generic/nsFrame.cpp
layout/generic/nsIFrame.h
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -6072,21 +6072,32 @@ PresShell::Paint(nsIView*           aDis
 
   AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Paint);
 
   NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell");
   NS_ASSERTION(aDisplayRoot, "null view");
   NS_ASSERTION(aViewToPaint, "null view");
   NS_ASSERTION(aWidgetToPaint, "Can't paint without a widget");
 
-  nscolor bgcolor = ComputeBackstopColor(aDisplayRoot);
-
   nsIFrame* frame = aPaintDefaultBackground
       ? nsnull : static_cast<nsIFrame*>(aDisplayRoot->GetClientData());
 
+  LayerManager* layerManager = aWidgetToPaint->GetLayerManager();
+  NS_ASSERTION(layerManager, "Must be in paint event");
+
+  if (frame) {
+    if (!(frame->GetStateBits() & NS_FRAME_UPDATE_LAYER_TREE)) {
+      if (layerManager->DoEmptyTransaction())
+        return NS_OK;
+    }
+    frame->RemoveStateBits(NS_FRAME_UPDATE_LAYER_TREE);
+  }
+
+  nscolor bgcolor = ComputeBackstopColor(aDisplayRoot);
+
   if (frame && aViewToPaint == aDisplayRoot) {
     // Defer invalidates that are triggered during painting, and discard
     // invalidates of areas that are already being repainted.
     // The layer system can trigger invalidates during painting
     // (see FrameLayerBuilder).
     frame->BeginDeferringInvalidatesForDisplayRoot(aDirtyRegion);
 
     // We can paint directly into the widget using its layer manager.
@@ -6101,19 +6112,16 @@ PresShell::Paint(nsIView*           aDis
   }
 
   if (frame) {
     // Defer invalidates that are triggered during painting, and discard
     // invalidates of areas that are already being repainted.
     frame->BeginDeferringInvalidatesForDisplayRoot(aDirtyRegion);
   }
 
-  LayerManager* layerManager = aWidgetToPaint->GetLayerManager();
-  NS_ASSERTION(layerManager, "Must be in paint event");
-
   layerManager->BeginTransaction();
   nsRefPtr<ThebesLayer> root = layerManager->CreateThebesLayer();
   if (root) {
     root->SetVisibleRegion(aIntDirtyRegion);
     layerManager->SetRoot(root);
   }
   if (!frame) {
     bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -3945,17 +3945,23 @@ nsIFrame::InvalidateLayer(const nsRect& 
 {
   NS_ASSERTION(aDisplayItemKey > 0, "Need a key");
 
   if (!FrameLayerBuilder::HasDedicatedLayer(this, aDisplayItemKey)) {
     Invalidate(aDamageRect);
     return;
   }
 
-  InvalidateWithFlags(aDamageRect, INVALIDATE_NO_THEBES_LAYERS);
+  PRUint32 flags = INVALIDATE_NO_THEBES_LAYERS;
+  if (aDisplayItemKey == nsDisplayItem::TYPE_VIDEO ||
+      aDisplayItemKey == nsDisplayItem::TYPE_PLUGIN) {
+    flags = INVALIDATE_NO_UPDATE_LAYER_TREE;
+  }
+
+  InvalidateWithFlags(aDamageRect, flags);
 }
 
 class LayerActivity {
 public:
   LayerActivity(nsIFrame* aFrame) : mFrame(aFrame) {}
   ~LayerActivity();
   nsExpirationState* GetExpirationState() { return &mState; }
 
@@ -4251,16 +4257,20 @@ nsIFrame::InvalidateRoot(const nsRect& a
       nsRegion r;
       r.Sub(rect, *excludeRegion);
       if (r.IsEmpty())
         return;
       rect = r.GetBounds();
     }
   }
 
+  if (!(aFlags & INVALIDATE_NO_UPDATE_LAYER_TREE)) {
+    AddStateBits(NS_FRAME_UPDATE_LAYER_TREE);
+  }
+
   nsIView* view = GetView();
   NS_ASSERTION(view, "This can only be called on frames with views");
   view->GetViewManager()->UpdateViewNoSuppression(view, rect, flags);
 }
 
 void
 nsIFrame::BeginDeferringInvalidatesForDisplayRoot(const nsRegion& aExcludeRegion)
 {
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -268,16 +268,22 @@ typedef PRUint64 nsFrameState;
 
 // Frame or one of its (cross-doc) descendants may have the
 // NS_FRAME_HAS_CONTAINER_LAYER bit.
 #define NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT     NS_FRAME_STATE_BIT(34)
 
 // Frame's overflow area was clipped by the 'clip' property.
 #define NS_FRAME_HAS_CLIP                           NS_FRAME_STATE_BIT(35)
 
+// Frame is a display root and the retained layer tree needs to be updated
+// at the next paint via display list construction.
+// Only meaningful for display roots, so we don't really need a global state
+// bit; we could free up this bit with a little extra complexity.
+#define NS_FRAME_UPDATE_LAYER_TREE                  NS_FRAME_STATE_BIT(36)
+
 // The lower 20 bits and upper 32 bits of the frame state are reserved
 // by this API.
 #define NS_FRAME_RESERVED                           ~NS_FRAME_IMPL_RESERVED
 
 // Box layout bits
 #define NS_STATE_IS_HORIZONTAL                      NS_FRAME_STATE_BIT(22)
 #define NS_STATE_IS_DIRECTION_NORMAL                NS_FRAME_STATE_BIT(31)
 
@@ -2046,27 +2052,32 @@ public:
    * then invalidation in the current paint region is simply discarded.
    * Use this flag if areas that are being painted do not need
    * to be invalidated. By default, when this flag is not specified,
    * areas that are invalidated while currently being painted will be repainted
    * again.
    * This flag is useful when, during painting, FrameLayerBuilder discovers that
    * a region of the window needs to be drawn differently, and that region
    * may or may not be contained in the currently painted region.
+   * @param aFlags INVALIDATE_NO_UPDATE_LAYER_TREE: display lists and the
+   * layer tree do not need to be updated. This can be used when the layer
+   * tree has already been updated outside a transaction, e.g. via
+   * ImageContainer::SetCurrentImage.
    */
   enum {
     INVALIDATE_IMMEDIATE = 0x01,
     INVALIDATE_CROSS_DOC = 0x02,
     INVALIDATE_REASON_SCROLL_BLIT = 0x04,
     INVALIDATE_REASON_SCROLL_REPAINT = 0x08,
     INVALIDATE_REASON_MASK = INVALIDATE_REASON_SCROLL_BLIT |
                              INVALIDATE_REASON_SCROLL_REPAINT,
     INVALIDATE_NO_THEBES_LAYERS = 0x10,
     INVALIDATE_ONLY_THEBES_LAYERS = 0x20,
-    INVALIDATE_EXCLUDE_CURRENT_PAINT = 0x40
+    INVALIDATE_EXCLUDE_CURRENT_PAINT = 0x40,
+    INVALIDATE_NO_UPDATE_LAYER_TREE = 0x80
   };
   virtual void InvalidateInternal(const nsRect& aDamageRect,
                                   nscoord aOffsetX, nscoord aOffsetY,
                                   nsIFrame* aForChild, PRUint32 aFlags);
 
   /**
    * Helper function that funnels an InvalidateInternal request up to the
    * parent.  This function is used so that if MOZ_SVG is not defined, we still