Chromium Code Reviews| 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; |
| } |