This source file includes following definitions.
- MaxNumberOfBackingStores
 
- MaxBackingStoreMemory
 
- ExpireBackingStoreAt
 
- ExpireLastBackingStore
 
- CreateCacheSpace
 
- CreateBackingStore
 
- ComputeTotalArea
 
- GetBackingStore
 
- PrepareBackingStore
 
- Lookup
 
- RemoveBackingStore
 
- MemorySize
 
#include "content/browser/renderer_host/backing_store_manager.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/containers/mru_cache.h"
#include "base/sys_info.h"
#include "content/browser/renderer_host/backing_store.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/public/common/content_switches.h"
namespace content {
namespace {
typedef base::OwningMRUCache<RenderWidgetHost*, BackingStore*>
    BackingStoreCache;
BackingStoreCache* large_cache = NULL;
BackingStoreCache* small_cache = NULL;
const size_t kSmallThreshold = 4 * 32 * 1920;
const size_t kMemoryMultiplier = 4 * 1920 * 1200;  
static size_t MaxNumberOfBackingStores() {
  static bool unlimited = false;
  const CommandLine& command = *CommandLine::ForCurrentProcess();
  unlimited = command.HasSwitch(switches::kDisableBackingStoreLimit);
  if (unlimited) {
    
    
    
    return 100;
  } else {
    return std::min(5, 2 + (base::SysInfo::AmountOfPhysicalMemoryMB() / 256));
  }
}
static size_t MaxBackingStoreMemory() {
  
  return MaxNumberOfBackingStores() * kMemoryMultiplier;
}
void ExpireBackingStoreAt(BackingStoreCache* cache,
                          BackingStoreCache::iterator backing_store) {
  cache->Erase(backing_store);
}
size_t ExpireLastBackingStore(BackingStoreCache* cache) {
  if (cache->size() < 1)
    return 0;
  
  
  BackingStoreCache::iterator entry = --cache->rbegin().base();
  size_t entry_size = entry->second->MemorySize();
  ExpireBackingStoreAt(cache, entry);
  return entry_size;
}
void CreateCacheSpace(size_t size) {
  
  
  
  while (size > 0 && (large_cache->size() > 1 || small_cache->size() > 1)) {
    BackingStoreCache* cache =
        (large_cache->size() > 1) ? large_cache : small_cache;
    while (size > 0 && cache->size() > 1) {
      size_t entry_size = ExpireLastBackingStore(cache);
      if (size > entry_size)
        size -= entry_size;
      else
        size = 0;
    }
  }
  DCHECK(size == 0);
}
BackingStore* CreateBackingStore(RenderWidgetHost* host,
                                 const gfx::Size& backing_store_size) {
  
  BackingStoreManager::RemoveBackingStore(host);
  if (!large_cache) {
    large_cache = new BackingStoreCache(BackingStoreCache::NO_AUTO_EVICT);
    small_cache = new BackingStoreCache(BackingStoreCache::NO_AUTO_EVICT);
  }
  
  size_t new_mem = backing_store_size.GetArea() * 4;
  size_t current_mem = BackingStoreManager::MemorySize();
  size_t max_mem = MaxBackingStoreMemory();
  DCHECK(new_mem < max_mem);
  if (current_mem + new_mem > max_mem) {
    
    
    
    
    
    CreateCacheSpace((current_mem + new_mem) - max_mem);
  }
  DCHECK((BackingStoreManager::MemorySize() + new_mem) <= max_mem);
  BackingStoreCache* cache;
  if (new_mem > kSmallThreshold) {
    
    
    
    
    if (large_cache->size() >= MaxNumberOfBackingStores())
      ExpireLastBackingStore(large_cache);
    cache = large_cache;
  } else {
    cache = small_cache;
  }
  BackingStore* backing_store = RenderWidgetHostImpl::From(
      host)->AllocBackingStore(backing_store_size);
  if (backing_store)
    cache->Put(host, backing_store);
  return backing_store;
}
int ComputeTotalArea(const std::vector<gfx::Rect>& rects) {
  
  
#ifndef NDEBUG
  for (size_t i = 0; i < rects.size(); ++i) {
    for (size_t j = 0; j < rects.size(); ++j) {
      if (i != j)
        DCHECK(!rects[i].Intersects(rects[j]));
    }
  }
#endif
  int area = 0;
  for (size_t i = 0; i < rects.size(); ++i)
    area += rects[i].size().GetArea();
  return area;
}
}  
BackingStore* BackingStoreManager::GetBackingStore(
    RenderWidgetHost* host,
    const gfx::Size& desired_size) {
  BackingStore* backing_store = Lookup(host);
  if (backing_store) {
    
    
    if (backing_store->size() == desired_size)
      return backing_store;
    backing_store = NULL;
  }
  return backing_store;
}
void BackingStoreManager::PrepareBackingStore(
    RenderWidgetHost* host,
    const gfx::Size& backing_store_size,
    TransportDIB::Id bitmap,
    const gfx::Rect& bitmap_rect,
    const std::vector<gfx::Rect>& copy_rects,
    float scale_factor,
    const base::Closure& completion_callback,
    bool* needs_full_paint,
    bool* scheduled_completion_callback) {
  BackingStore* backing_store = GetBackingStore(host, backing_store_size);
  if (!backing_store) {
    
    
    if (bitmap_rect.size() != backing_store_size ||
        bitmap_rect.x() != 0 || bitmap_rect.y() != 0 ||
        ComputeTotalArea(copy_rects) != backing_store_size.GetArea() ||
        !(backing_store = CreateBackingStore(host, backing_store_size))) {
      DCHECK(needs_full_paint != NULL);
      *needs_full_paint = true;
      *scheduled_completion_callback = false;
      
      
      return;
    }
  }
  backing_store->PaintToBackingStore(host->GetProcess(), bitmap,
                                     bitmap_rect, copy_rects, scale_factor,
                                     completion_callback,
                                     scheduled_completion_callback);
}
BackingStore* BackingStoreManager::Lookup(RenderWidgetHost* host) {
  if (large_cache) {
    BackingStoreCache::iterator it = large_cache->Get(host);
    if (it != large_cache->end())
      return it->second;
    
    it = small_cache->Get(host);
    if (it != small_cache->end())
      return it->second;
  }
  return NULL;
}
void BackingStoreManager::RemoveBackingStore(RenderWidgetHost* host) {
  if (!large_cache)
    return;
  BackingStoreCache* cache = large_cache;
  BackingStoreCache::iterator it = cache->Peek(host);
  if (it == cache->end()) {
    cache = small_cache;
    it = cache->Peek(host);
    if (it == cache->end())
      return;
  }
  cache->Erase(it);
}
size_t BackingStoreManager::MemorySize() {
  if (!large_cache)
    return 0;
  size_t mem = 0;
  BackingStoreCache::iterator it;
  for (it = large_cache->begin(); it != large_cache->end(); ++it)
    mem += it->second->MemorySize();
  for (it = small_cache->begin(); it != small_cache->end(); ++it)
    mem += it->second->MemorySize();
  return mem;
}
}