Index: Source/platform/graphics/Canvas2DLayerManager.cpp |
diff --git a/Source/platform/graphics/Canvas2DLayerManager.cpp b/Source/platform/graphics/Canvas2DLayerManager.cpp |
index 5d21312a0fe0d650bd4a30b23b0142bb8c5852b3..f020cafe4c7c7ec974bb37856781b890ea65d66a 100644 |
--- a/Source/platform/graphics/Canvas2DLayerManager.cpp |
+++ b/Source/platform/graphics/Canvas2DLayerManager.cpp |
@@ -31,11 +31,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
using blink::WebThread; |
namespace { |
+ |
enum { |
DefaultMaxBytesAllocated = 64*1024*1024, |
DefaultTargetBytesAllocated = 16*1024*1024, |
}; |
-} |
+ |
+} // unnamed namespace |
namespace WebCore { |
@@ -81,8 +83,17 @@ void Canvas2DLayerManager::didProcessTask() |
ASSERT(m_taskObserverActive); |
blink::Platform::current()->currentThread()->removeTaskObserver(this); |
m_taskObserverActive = false; |
- for (Canvas2DLayerBridge* layer = m_layerList.head(); layer; layer = layer->next()) |
- layer->limitPendingFrames(); |
+ Canvas2DLayerBridge* layer = m_layerList.head(); |
+ while (layer) { |
+ Canvas2DLayerBridge* currentLayer = layer; |
+ layer = layer->next(); |
+ if (currentLayer->hidden()) { |
+ currentLayer->freeTransientResources(); |
+ ASSERT(!isInList(currentLayer)); |
+ } else { |
+ currentLayer->limitPendingFrames(); |
+ } |
+ } |
} |
void Canvas2DLayerManager::layerDidDraw(Canvas2DLayerBridge* layer) |
@@ -102,6 +113,13 @@ void Canvas2DLayerManager::layerDidDraw(Canvas2DLayerBridge* layer) |
} |
} |
+void Canvas2DLayerManager::setLayerHasFreeableResources(Canvas2DLayerBridge* layer) |
+{ |
+ if (!isInList(layer)) { |
+ addLayerToList(layer); |
+ } |
+} |
+ |
void Canvas2DLayerManager::addLayerToList(Canvas2DLayerBridge* layer) |
{ |
ASSERT(!isInList(layer)); |
@@ -111,11 +129,14 @@ void Canvas2DLayerManager::addLayerToList(Canvas2DLayerBridge* layer) |
void Canvas2DLayerManager::layerAllocatedStorageChanged(Canvas2DLayerBridge* layer, intptr_t deltaBytes) |
{ |
- if (!isInList(layer)) |
+ if (!isInList(layer)) { |
+ ASSERT(layer->hasTransientResources()); |
addLayerToList(layer); |
- else { |
+ } else { |
ASSERT((intptr_t)m_bytesAllocated + deltaBytes >= 0); |
m_bytesAllocated = (intptr_t)m_bytesAllocated + deltaBytes; |
+ if (!layer->hasTransientResources()) |
+ removeLayerFromList(layer); |
} |
if (deltaBytes > 0) |
freeMemoryIfNecessary(); |
@@ -129,21 +150,41 @@ void Canvas2DLayerManager::layerToBeDestroyed(Canvas2DLayerBridge* layer) |
void Canvas2DLayerManager::freeMemoryIfNecessary() |
{ |
- if (m_bytesAllocated > m_maxBytesAllocated) { |
+ if (m_bytesAllocated >= m_maxBytesAllocated) { |
// Pass 1: Free memory from caches |
Canvas2DLayerBridge* layer = m_layerList.tail(); // LRU |
- while (m_bytesAllocated > m_targetBytesAllocated && layer) { |
- layer->freeMemoryIfPossible(m_bytesAllocated - m_targetBytesAllocated); |
+ while (layer && m_bytesAllocated > m_targetBytesAllocated) { |
+ Canvas2DLayerBridge* currentLayer = layer; |
layer = layer->prev(); |
+ currentLayer->freeMemoryIfPossible(m_bytesAllocated - m_targetBytesAllocated); |
+ ASSERT(isInList(currentLayer) == currentLayer->hasTransientResources()); |
} |
// Pass 2: Flush canvases |
- Canvas2DLayerBridge* leastRecentlyUsedLayer = m_layerList.tail(); |
- while (m_bytesAllocated > m_targetBytesAllocated && leastRecentlyUsedLayer) { |
- leastRecentlyUsedLayer->flush(); |
- leastRecentlyUsedLayer->freeMemoryIfPossible(~0); |
- removeLayerFromList(leastRecentlyUsedLayer); |
- leastRecentlyUsedLayer = m_layerList.tail(); |
+ layer = m_layerList.tail(); |
+ while (m_bytesAllocated > m_targetBytesAllocated && layer) { |
+ Canvas2DLayerBridge* currentLayer = layer; |
+ layer = layer->prev(); |
+ currentLayer->flush(); |
+ currentLayer->freeMemoryIfPossible(m_bytesAllocated - m_targetBytesAllocated); |
+ ASSERT(isInList(currentLayer) == currentLayer->hasTransientResources()); |
+ } |
+ } |
+} |
+ |
+void Canvas2DLayerManager::didHidePage() |
+{ |
+ // A page that lives in this process just became hidden. |
+ // Instead of traversing the page's DOMs to find its canvases, |
+ // we traverse all live canvases to find those that are now hidden, |
+ // which should almost always be more efficient than traversing DOMs. |
+ Canvas2DLayerBridge* layer = m_layerList.head(); |
+ while (layer) { |
+ Canvas2DLayerBridge* currentLayer = layer; |
+ layer = layer->next(); |
+ if (currentLayer->hidden()) { |
eseidel
2013/12/19 02:56:32
I'm surprised youw ant to check this "hidden" meth
|
+ currentLayer->freeTransientResources(); |
+ ASSERT(!isInList(currentLayer)); |
} |
} |
} |
@@ -157,7 +198,7 @@ void Canvas2DLayerManager::removeLayerFromList(Canvas2DLayerBridge* layer) |
layer->setPrev(0); |
} |
-bool Canvas2DLayerManager::isInList(Canvas2DLayerBridge* layer) |
+bool Canvas2DLayerManager::isInList(Canvas2DLayerBridge* layer) const |
{ |
return layer->prev() || m_layerList.head() == layer; |
} |