Bug 610727 - Mark canvas layers inactive when relevant. r=roc a=blocking-fennec
authorAlon Zakai <azakai@mozilla.com>
Fri, 04 Feb 2011 10:11:24 -0800
changeset 61944 dc85ecc5f1dcfdbad46f44867749a63a197443fd
parent 61943 88f322876de1368d0d0acaf301815b575b95beb5
child 61945 5a4ab9b3fd2ffac5712a894aa22b4ebae4eb5f05
push id1
push userroot
push dateTue, 10 Dec 2013 15:46:25 +0000
reviewersroc, blocking-fennec
bugs610727
milestone2.0b12pre
Bug 610727 - Mark canvas layers inactive when relevant. r=roc a=blocking-fennec
content/canvas/src/WebGLContext.cpp
content/canvas/src/nsCanvasRenderingContext2D.cpp
gfx/layers/Layers.h
gfx/layers/basic/BasicLayers.cpp
gfx/layers/basic/BasicLayers.h
layout/generic/nsHTMLCanvasFrame.cpp
layout/generic/nsHTMLCanvasFrame.h
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -617,16 +617,17 @@ WebGLContext::GetCanvasLayer(CanvasLayer
                              LayerManager *aManager)
 {
     if (!mResetLayer && aOldLayer &&
         aOldLayer->HasUserData(&gWebGLLayerUserData)) {
         NS_ADDREF(aOldLayer);
         if (mInvalidated) {
             aOldLayer->Updated(nsIntRect(0, 0, mWidth, mHeight));
             mInvalidated = PR_FALSE;
+            HTMLCanvasElement()->GetPrimaryCanvasFrame()->MarkLayersActive();
         }
         return aOldLayer;
     }
 
     nsRefPtr<CanvasLayer> canvasLayer = aManager->CreateCanvasLayer();
     if (!canvasLayer) {
         NS_WARNING("CreateCanvasLayer returned null!");
         return nsnull;
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -4061,16 +4061,17 @@ nsCanvasRenderingContext2D::GetCanvasLay
     if (!mResetLayer && aOldLayer &&
         aOldLayer->HasUserData(&g2DContextLayerUserData)) {
         NS_ADDREF(aOldLayer);
         if (mIsEntireFrameInvalid || mInvalidateCount > 0) {
             // XXX Need to just update the changed area here; we should keep track
             // of the rectangle based on Redraw args.
             aOldLayer->Updated(nsIntRect(0, 0, mWidth, mHeight));
             MarkContextClean();
+            HTMLCanvasElement()->GetPrimaryCanvasFrame()->MarkLayersActive();
         }
 
         return aOldLayer;
     }
 
     nsRefPtr<CanvasLayer> canvasLayer = aManager->CreateCanvasLayer();
     if (!canvasLayer) {
         NS_WARNING("CreateCanvasLayer returned null!");
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
@@ -469,16 +469,21 @@ public:
    * Log information about just this layer manager itself to the NSPR
    * log (if enabled for "Layers").
    */
   void LogSelf(const char* aPrefix="");
 
   static bool IsLogEnabled();
   static PRLogModuleInfo* GetLog() { return sLog; }
 
+  PRBool IsCompositingCheap(LayerManager::LayersBackend aBackend)
+  { return LAYERS_BASIC != aBackend; }
+
+  virtual PRBool IsCompositingCheap() { return PR_TRUE; }
+
 protected:
   nsRefPtr<Layer> mRoot;
   LayerUserDataSet mUserData;
   PRPackedBool mDestroyed;
   PRPackedBool mSnapEffectiveTransforms;
 
   // Print interesting information about this into aTo.  Internally
   // used to implement Dump*() and Log*().
--- a/gfx/layers/basic/BasicLayers.cpp
+++ b/gfx/layers/basic/BasicLayers.cpp
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
@@ -2773,12 +2773,20 @@ BasicShadowLayerManager::Hold(Layer* aLa
                     "top-level tree, no shadow tree to remote to");
 
   ShadowableLayer* shadowable = ToShadowable(aLayer);
   NS_ABORT_IF_FALSE(shadowable, "trying to remote an unshadowable layer");
 
   mKeepAlive.AppendElement(aLayer);
   return shadowable;
 }
+
+PRBool
+BasicShadowLayerManager::IsCompositingCheap()
+{
+  // Whether compositing is cheap depends on the parent backend.
+  return mShadowManager &&
+         LayerManager::IsCompositingCheap(GetParentBackendType());
+}
 #endif  // MOZ_IPC
 
 }
 }
--- a/gfx/layers/basic/BasicLayers.h
+++ b/gfx/layers/basic/BasicLayers.h
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
@@ -179,16 +179,18 @@ public:
   virtual const char* Name() const { return "Basic"; }
 #endif // MOZ_LAYERS_HAVE_LOG
 
   // Clear the cached contents of this layer.
   void ClearCachedResources();
 
   void SetTransactionIncomplete() { mTransactionIncomplete = true; }
 
+  virtual PRBool IsCompositingCheap() { return PR_FALSE; }
+
 protected:
 #ifdef DEBUG
   enum TransactionPhase {
     PHASE_NONE, PHASE_CONSTRUCTION, PHASE_DRAWING, PHASE_FORWARD
   };
   TransactionPhase mPhase;
 #endif
 
@@ -264,16 +266,18 @@ public:
 
   PLayersChild* GetShadowManager() const { return mShadowManager; }
 
   void SetShadowManager(PLayersChild* aShadowManager)
   {
     mShadowManager = aShadowManager;
   }
 
+  virtual PRBool IsCompositingCheap();
+
 private:
   /**
    * Forward transaction results to the parent context.
    */
   void ForwardTransaction();
 
   LayerRefArray mKeepAlive;
 };
--- a/layout/generic/nsHTMLCanvasFrame.cpp
+++ b/layout/generic/nsHTMLCanvasFrame.cpp
@@ -100,31 +100,48 @@ public:
                                              LayerManager* aManager)
   {
     return static_cast<nsHTMLCanvasFrame*>(mFrame)->
       BuildLayer(aBuilder, aManager, this);
   }
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager)
   {
-    // XXX we should have some kind of activity timeout here so that
-    // inactive canvases can be composited into the background
-    return mozilla::LAYER_ACTIVE;
+    // If compositing is cheap, just do that
+    if (aManager->IsCompositingCheap())
+      return mozilla::LAYER_ACTIVE;
+
+    return mFrame->AreLayersMarkedActive() ? LAYER_ACTIVE : LAYER_INACTIVE;
   }
 };
 
 
 nsIFrame*
 NS_NewHTMLCanvasFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsHTMLCanvasFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsHTMLCanvasFrame)
 
+NS_IMETHODIMP
+nsHTMLCanvasFrame::Init(nsIContent* aContent,
+                        nsIFrame*   aParent,
+                        nsIFrame*   aPrevInFlow)
+{
+  nsresult rv = nsSplittableFrame::Init(aContent, aParent, aPrevInFlow);
+
+  // We can fill in the canvas before the canvas frame is created, in
+  // which case we never get around to marking the layer active. Therefore,
+  // we mark it active here when we create the frame.
+  MarkLayersActive();
+
+  return rv;
+}
+
 nsHTMLCanvasFrame::~nsHTMLCanvasFrame()
 {
 }
 
 nsIntSize
 nsHTMLCanvasFrame::GetCanvasSize()
 {
   nsIntSize size(0,0);
--- a/layout/generic/nsHTMLCanvasFrame.h
+++ b/layout/generic/nsHTMLCanvasFrame.h
@@ -57,16 +57,20 @@ class nsHTMLCanvasFrame : public nsSplit
 public:
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::LayerManager LayerManager;
 
   NS_DECL_FRAMEARENA_HELPERS
 
   nsHTMLCanvasFrame(nsStyleContext* aContext) : nsSplittableFrame(aContext) {}
 
+  NS_IMETHOD Init(nsIContent* aContent,
+                  nsIFrame*   aParent,
+                  nsIFrame*   aPrevInFlow);
+
   NS_IMETHOD BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                               const nsRect&           aDirtyRect,
                               const nsDisplayListSet& aLists);
 
   already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                      LayerManager* aManager,
                                      nsDisplayItem* aItem);