1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/common/host_shared_bitmap_manager.h"
6
7#include "base/lazy_instance.h"
8#include "base/memory/ref_counted.h"
9#include "content/common/view_messages.h"
10#include "ui/gfx/size.h"
11
12namespace content {
13
14class BitmapData : public base::RefCountedThreadSafe<BitmapData> {
15 public:
16  BitmapData(base::ProcessHandle process_handle,
17             base::SharedMemoryHandle memory_handle,
18             size_t buffer_size)
19      : process_handle(process_handle),
20        memory_handle(memory_handle),
21        buffer_size(buffer_size) {}
22  base::ProcessHandle process_handle;
23  base::SharedMemoryHandle memory_handle;
24  scoped_ptr<base::SharedMemory> memory;
25  scoped_ptr<uint8[]> pixels;
26  size_t buffer_size;
27
28 private:
29  friend class base::RefCountedThreadSafe<BitmapData>;
30  ~BitmapData() {}
31  DISALLOW_COPY_AND_ASSIGN(BitmapData);
32};
33
34// Holds a reference on the memory to keep it alive.
35void FreeSharedMemory(scoped_refptr<BitmapData> data,
36                      cc::SharedBitmap* bitmap) {}
37
38base::LazyInstance<HostSharedBitmapManager> g_shared_memory_manager =
39    LAZY_INSTANCE_INITIALIZER;
40
41HostSharedBitmapManager::HostSharedBitmapManager() {}
42HostSharedBitmapManager::~HostSharedBitmapManager() {}
43
44HostSharedBitmapManager* HostSharedBitmapManager::current() {
45  return g_shared_memory_manager.Pointer();
46}
47
48scoped_ptr<cc::SharedBitmap> HostSharedBitmapManager::AllocateSharedBitmap(
49    const gfx::Size& size) {
50  base::AutoLock lock(lock_);
51  size_t bitmap_size;
52  if (!cc::SharedBitmap::SizeInBytes(size, &bitmap_size))
53    return scoped_ptr<cc::SharedBitmap>();
54
55  scoped_refptr<BitmapData> data(
56      new BitmapData(base::GetCurrentProcessHandle(),
57                     base::SharedMemory::NULLHandle(),
58                     bitmap_size));
59  // Bitmaps allocated in host don't need to be shared to other processes, so
60  // allocate them with new instead.
61  data->pixels = scoped_ptr<uint8[]>(new uint8[bitmap_size]);
62
63  cc::SharedBitmapId id = cc::SharedBitmap::GenerateId();
64  handle_map_[id] = data;
65  return make_scoped_ptr(new cc::SharedBitmap(
66      data->pixels.get(),
67      id,
68      base::Bind(&HostSharedBitmapManager::FreeSharedMemoryFromMap,
69                 base::Unretained(this))));
70}
71
72scoped_ptr<cc::SharedBitmap> HostSharedBitmapManager::GetSharedBitmapFromId(
73    const gfx::Size& size,
74    const cc::SharedBitmapId& id) {
75  base::AutoLock lock(lock_);
76  BitmapMap::iterator it = handle_map_.find(id);
77  if (it == handle_map_.end())
78    return scoped_ptr<cc::SharedBitmap>();
79
80  BitmapData* data = it->second.get();
81
82  size_t bitmap_size;
83  if (!cc::SharedBitmap::SizeInBytes(size, &bitmap_size) ||
84      bitmap_size > data->buffer_size)
85    return scoped_ptr<cc::SharedBitmap>();
86
87  if (data->pixels) {
88    return make_scoped_ptr(new cc::SharedBitmap(
89        data->pixels.get(), id, base::Bind(&FreeSharedMemory, it->second)));
90  }
91  if (!data->memory->memory()) {
92    TRACE_EVENT0("renderer_host",
93                 "HostSharedBitmapManager::GetSharedBitmapFromId");
94    if (!data->memory->Map(data->buffer_size)) {
95      return scoped_ptr<cc::SharedBitmap>();
96    }
97  }
98
99  scoped_ptr<cc::SharedBitmap> bitmap(new cc::SharedBitmap(
100      data->memory.get(), id, base::Bind(&FreeSharedMemory, it->second)));
101
102  return bitmap.Pass();
103}
104
105scoped_ptr<cc::SharedBitmap> HostSharedBitmapManager::GetBitmapForSharedMemory(
106    base::SharedMemory*) {
107  return scoped_ptr<cc::SharedBitmap>();
108}
109
110void HostSharedBitmapManager::ChildAllocatedSharedBitmap(
111    size_t buffer_size,
112    const base::SharedMemoryHandle& handle,
113    base::ProcessHandle process_handle,
114    const cc::SharedBitmapId& id) {
115  base::AutoLock lock(lock_);
116  if (handle_map_.find(id) != handle_map_.end())
117    return;
118  scoped_refptr<BitmapData> data(
119      new BitmapData(process_handle, handle, buffer_size));
120
121  handle_map_[id] = data;
122  process_map_[process_handle].insert(id);
123#if defined(OS_WIN)
124  data->memory = make_scoped_ptr(
125      new base::SharedMemory(data->memory_handle, false, data->process_handle));
126#else
127  data->memory =
128      make_scoped_ptr(new base::SharedMemory(data->memory_handle, false));
129#endif
130}
131
132void HostSharedBitmapManager::AllocateSharedBitmapForChild(
133    base::ProcessHandle process_handle,
134    size_t buffer_size,
135    const cc::SharedBitmapId& id,
136    base::SharedMemoryHandle* shared_memory_handle) {
137  base::AutoLock lock(lock_);
138  if (handle_map_.find(id) != handle_map_.end()) {
139    *shared_memory_handle = base::SharedMemory::NULLHandle();
140    return;
141  }
142  scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory);
143  if (!shared_memory->CreateAndMapAnonymous(buffer_size)) {
144    LOG(ERROR) << "Cannot create shared memory buffer";
145    *shared_memory_handle = base::SharedMemory::NULLHandle();
146    return;
147  }
148
149  scoped_refptr<BitmapData> data(
150      new BitmapData(process_handle, shared_memory->handle(), buffer_size));
151  data->memory = shared_memory.Pass();
152
153  handle_map_[id] = data;
154  process_map_[process_handle].insert(id);
155  if (!data->memory->ShareToProcess(process_handle, shared_memory_handle)) {
156    LOG(ERROR) << "Cannot share shared memory buffer";
157    *shared_memory_handle = base::SharedMemory::NULLHandle();
158    return;
159  }
160}
161
162void HostSharedBitmapManager::ChildDeletedSharedBitmap(
163    const cc::SharedBitmapId& id) {
164  base::AutoLock lock(lock_);
165  BitmapMap::iterator it = handle_map_.find(id);
166  if (it == handle_map_.end())
167    return;
168  base::hash_set<cc::SharedBitmapId>& res =
169      process_map_[it->second->process_handle];
170  res.erase(id);
171  handle_map_.erase(it);
172}
173
174void HostSharedBitmapManager::ProcessRemoved(
175    base::ProcessHandle process_handle) {
176  base::AutoLock lock(lock_);
177  ProcessMap::iterator proc_it = process_map_.find(process_handle);
178  if (proc_it == process_map_.end())
179    return;
180  base::hash_set<cc::SharedBitmapId>& res = proc_it->second;
181
182  for (base::hash_set<cc::SharedBitmapId>::iterator it = res.begin();
183       it != res.end();
184       ++it) {
185    handle_map_.erase(*it);
186  }
187  process_map_.erase(proc_it);
188}
189
190size_t HostSharedBitmapManager::AllocatedBitmapCount() const {
191  base::AutoLock lock(lock_);
192  return handle_map_.size();
193}
194
195void HostSharedBitmapManager::FreeSharedMemoryFromMap(
196    cc::SharedBitmap* bitmap) {
197  base::AutoLock lock(lock_);
198  handle_map_.erase(bitmap->id());
199}
200
201}  // namespace content
202