Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(138)

Side by Side Diff: ppapi/proxy/ppb_image_data_proxy.cc

Issue 10823378: Cache image data objects. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ppapi/proxy/ppb_image_data_proxy.h" 5 #include "ppapi/proxy/ppb_image_data_proxy.h"
6 6
7 #include <string.h> // For memcpy 7 #include <string.h> // For memcpy
8 8
9 #include <map>
9 #include <vector> 10 #include <vector>
10 11
11 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/memory/singleton.h"
14 #include "base/memory/weak_ptr.h"
12 #include "build/build_config.h" 15 #include "build/build_config.h"
13 #include "ppapi/c/pp_completion_callback.h" 16 #include "ppapi/c/pp_completion_callback.h"
14 #include "ppapi/c/pp_errors.h" 17 #include "ppapi/c/pp_errors.h"
15 #include "ppapi/c/pp_resource.h" 18 #include "ppapi/c/pp_resource.h"
19 #include "ppapi/proxy/enter_proxy.h"
16 #include "ppapi/proxy/host_dispatcher.h" 20 #include "ppapi/proxy/host_dispatcher.h"
17 #include "ppapi/proxy/plugin_dispatcher.h" 21 #include "ppapi/proxy/plugin_dispatcher.h"
22 #include "ppapi/proxy/plugin_globals.h"
18 #include "ppapi/proxy/plugin_resource_tracker.h" 23 #include "ppapi/proxy/plugin_resource_tracker.h"
19 #include "ppapi/proxy/ppapi_messages.h" 24 #include "ppapi/proxy/ppapi_messages.h"
20 #include "ppapi/shared_impl/host_resource.h" 25 #include "ppapi/shared_impl/host_resource.h"
21 #include "ppapi/shared_impl/resource.h" 26 #include "ppapi/shared_impl/resource.h"
22 #include "ppapi/thunk/enter.h" 27 #include "ppapi/thunk/enter.h"
23 #include "ppapi/thunk/thunk.h" 28 #include "ppapi/thunk/thunk.h"
24 29
25 #if !defined(OS_NACL) 30 #if !defined(OS_NACL)
26 #include "skia/ext/platform_canvas.h" 31 #include "skia/ext/platform_canvas.h"
27 #include "ui/surface/transport_dib.h" 32 #include "ui/surface/transport_dib.h"
28 #endif 33 #endif
29 34
35 using ppapi::thunk::PPB_ImageData_API;
36
30 namespace ppapi { 37 namespace ppapi {
31 namespace proxy { 38 namespace proxy {
32 39
40 namespace {
41
42 // How ImageData re-use works
43 // --------------------------
44 //
45 // When a plugin does ReplaceContents, it transfers the ImageData to the system
46 // for use as the backing store for the instance. When animating plugins (like
47 // video) re-creating image datas for each frame and mapping the memory has a
48 // high overhead. So we try to re-use these when possible.
49 //
50 // 1. Plugin does ReplaceContents and Flush and the proxy queues up an
51 // asynchronous request to the renderer.
52 // 2. Plugin frees its ImageData reference. If it doesn't do this we can't
53 // re-use it.
54 // 3. When the last plugin ref of an ImageData is released, we don't actually
55 // delete it. Instead we put it on a queue where we hold onto it in the
56 // plugin process for a short period of time.
57 // 4. When the Flush for the Graphics2D.ReplaceContents is executed, the proxy
58 // will request the old ImageData. This is the one that's being replaced by
59 // the new contents so is being abandoned, and without our caching system it
60 // would get deleted at this point.
61 // 5. The proxy in the renderer will send NotifyUnusedImageData back to the
62 // plugin process. We check if the given resource is in the queue and mark
63 // it as usable.
64 // 6. When the plugin requests a new image data, we check our queue and if there
65 // is a usable ImageData of the right size and format, we'll return it
66 // instead of making a new one. Since when you're doing full frame
67 // animations, generally the size doesn't change so cache hits should be
68 // high.
69 //
70 // Some notes:
71 //
72 // - We only re-use image datas when the plugin does ReplaceContents on them.
73 // Theoretically we could re-use them in other cases but the lifetime
74 // becomes more difficult to manage. The plugin could have used an ImageData
75 // in an arbitrary number of queued up PaintImageData calls which we would
76 // have to check. By doing ReplaceContents, the plugin is promising that it's
77 // done with the image, so this is a good signal.
78 //
79 // - If a flush takes a long time or there are many released image datas
80 // accumulating in our queue such that some are deleted, we will have
81 // released our reference by the time the renderer notifies us of an unused
82 // image data. In this case we just give up.
83 //
84 // - We maintain a per-instance cache. Some pages have many instances of
85 // Flash, for example, each of a different size. If they're all animating we
86 // want each to get its own image data re-use.
87 //
88 // - We generate new resource IDs when re-use happens to try to avoid weird
89 // problems if the plugin messes up its refcounting.
90
91 // Keep a cache entry for this many seconds before expiring it. We get an entry
92 // back from the renderer after an ImageData is swapped out, so it means the
93 // plugin has to be painting at least two frames for this time interfacl to
yzshen1 2012/08/21 23:42:44 interfacl -> interval. :)
94 // get caching.
95 static const int kMaxAgeSeconds = 2;
96
97 // ImageDataCacheEntry ---------------------------------------------------------
98
99 struct ImageDataCacheEntry {
100 ImageDataCacheEntry() : added_time(), usable(false), image() {}
101 ImageDataCacheEntry(ImageData* i)
102 : added_time(base::TimeTicks::Now()),
103 usable(false),
104 image(i) {
105 }
106
107 base::TimeTicks added_time;
108
109 // Set to true when the renderer tells us that it's OK to re-use this iamge.
110 bool usable;
111
112 scoped_refptr<ImageData> image;
113 };
114
115 // ImageDataInstanceCache ------------------------------------------------------
116
117 // Per-instance cache of image datas.
118 class ImageDataInstanceCache {
119 public:
120 ImageDataInstanceCache() : next_insertion_point_(0) {}
121
122 // These functions have the same spec as the ones in ImageDataCache.
123 scoped_refptr<ImageData> Get(int width, int height,
124 PP_ImageDataFormat format);
125 void Add(ImageData* image_data);
126 void ImageDataUsable(ImageData* image_data);
127
128 // Expires old entries. Returns true if there are still entries in the list,
129 // false if this instance cache is now empty.
130 bool ExpireEntries();
131
132 private:
133 // We'll store this many ImageDatas per instance.
134 const static int kCacheSize = 2;
135
136 ImageDataCacheEntry images_[kCacheSize];
137
138 // Index into cache where the next item will go.
139 int next_insertion_point_;
140 };
141
142 scoped_refptr<ImageData> ImageDataInstanceCache::Get(
143 int width, int height,
144 PP_ImageDataFormat format) {
145 // Just do a brute-force search since the cache is so small.
146 for (int i = 0; i < kCacheSize; i++) {
147 if (!images_[i].usable)
148 continue;
149 const PP_ImageDataDesc& desc = images_[i].image->desc();
150 if (desc.format == format &&
151 desc.size.width == width && desc.size.height == height) {
152 scoped_refptr<ImageData> ret(images_[i].image);
153 images_[i] = ImageDataCacheEntry();
154 return ret;
155 }
156 }
157 return scoped_refptr<ImageData>();
158 }
159
160 void ImageDataInstanceCache::Add(ImageData* image_data) {
161 images_[next_insertion_point_] = ImageDataCacheEntry(image_data);
162
163 // Go to the next location, wrapping around to get LRU.
164 next_insertion_point_++;
165 if (next_insertion_point_ >= kCacheSize)
166 next_insertion_point_ = 0;
167 }
168
169 void ImageDataInstanceCache::ImageDataUsable(ImageData* image_data) {
170 for (int i = 0; i < kCacheSize; i++) {
171 if (images_[i].image.get() == image_data) {
172 images_[i].usable = true;
173 return;
174 }
175 }
176 }
177
178 bool ImageDataInstanceCache::ExpireEntries() {
179 base::TimeTicks threshold_time =
180 base::TimeTicks::Now() - base::TimeDelta::FromSeconds(kMaxAgeSeconds);
181
182 bool has_entry = false;
183 for (int i = 0; i < kCacheSize; i++) {
184 if (images_[i].image.get()) {
185 // Entry present.
186 if (images_[i].added_time <= threshold_time) {
187 // Found an entry to expire.
188 images_[i] = ImageDataCacheEntry();
189 next_insertion_point_ = i;
190 } else {
191 // Found an entry that we're keeping.
192 has_entry = true;
193 }
194 }
195 }
196 return has_entry;
197 }
198
199 // ImageDataCache --------------------------------------------------------------
200
201 class ImageDataCache {
202 public:
203 ImageDataCache() : weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {}
204 ~ImageDataCache() {}
205
206 static ImageDataCache* GetInstance();
207
208 // Retrieves an image data from the cache of the specified size and format if
209 // one exists. If one doesn't exist, this will return a null refptr.
210 scoped_refptr<ImageData> Get(PP_Instance instance,
211 int width, int height,
212 PP_ImageDataFormat format);
213
214 // Adds the given image data to the cache. There should be no plugin
215 // references to it. This may delete an older item from the cache.
216 void Add(ImageData* image_data);
217
218 // Notification from the renderer that the given image data is usable.
219 void ImageDataUsable(ImageData* image_data);
220
221 private:
222 friend struct LeakySingletonTraits<ImageDataCache>;
223
224 // Timer callback to expire entries for the given instance.
225 void OnTimer(PP_Instance instance);
226
227 // This class does timer calls and we don't want to run these outside of the
228 // scope of the object. Technically, since this class is a leaked static,
229 // this will never happen and this factory is unnecessary. However, it's
230 // probably better not to make assumptions about the lifetime of this class.
231 base::WeakPtrFactory<ImageDataCache> weak_factory_;
232
233 typedef std::map<PP_Instance, ImageDataInstanceCache> CacheMap;
234 CacheMap cache_;
235
236 DISALLOW_COPY_AND_ASSIGN(ImageDataCache);
237 };
238
239 // static
240 ImageDataCache* ImageDataCache::GetInstance() {
241 return Singleton<ImageDataCache,
242 LeakySingletonTraits<ImageDataCache> >::get();
243 }
244
245 scoped_refptr<ImageData> ImageDataCache::Get(PP_Instance instance,
246 int width, int height,
247 PP_ImageDataFormat format) {
248 CacheMap::iterator found = cache_.find(instance);
249 if (found == cache_.end())
250 return scoped_refptr<ImageData>();
251 return found->second.Get(width, height, format);
252 }
253
254 void ImageDataCache::Add(ImageData* image_data) {
255 cache_[image_data->pp_instance()].Add(image_data);
256
257 // Schedule a timer to invalidate this entry.
258 MessageLoop::current()->PostDelayedTask(
259 FROM_HERE,
260 base::Bind(&ImageDataCache::OnTimer,
261 weak_factory_.GetWeakPtr(),
262 image_data->pp_instance()),
263 base::TimeDelta::FromSeconds(kMaxAgeSeconds));
264 }
265
266 void ImageDataCache::ImageDataUsable(ImageData* image_data) {
267 CacheMap::iterator found = cache_.find(image_data->pp_instance());
268 if (found != cache_.end())
269 found->second.ImageDataUsable(image_data);
270 }
271
272 void ImageDataCache::OnTimer(PP_Instance instance) {
273 CacheMap::iterator found = cache_.find(instance);
274 if (found == cache_.end())
275 return;
276 if (!found->second.ExpireEntries()) {
277 // There are no more entries for this instance, remove it from the cache.
278 cache_.erase(found);
279 }
280 }
281
282 } // namespace
283
284 // ImageData -------------------------------------------------------------------
285
33 #if !defined(OS_NACL) 286 #if !defined(OS_NACL)
34 ImageData::ImageData(const HostResource& resource, 287 ImageData::ImageData(const HostResource& resource,
35 const PP_ImageDataDesc& desc, 288 const PP_ImageDataDesc& desc,
36 ImageHandle handle) 289 ImageHandle handle)
37 : Resource(OBJECT_IS_PROXY, resource), 290 : Resource(OBJECT_IS_PROXY, resource),
38 desc_(desc) { 291 desc_(desc) {
39 #if defined(OS_WIN) 292 #if defined(OS_WIN)
40 transport_dib_.reset(TransportDIB::CreateWithHandle(handle)); 293 transport_dib_.reset(TransportDIB::CreateWithHandle(handle));
41 #else 294 #else
42 transport_dib_.reset(TransportDIB::Map(handle)); 295 transport_dib_.reset(TransportDIB::Map(handle));
43 #endif // defined(OS_WIN) 296 #endif // defined(OS_WIN)
44 } 297 }
45 #else // !defined(OS_NACL) 298 #else // !defined(OS_NACL)
46 299
47 ImageData::ImageData(const HostResource& resource, 300 ImageData::ImageData(const HostResource& resource,
48 const PP_ImageDataDesc& desc, 301 const PP_ImageDataDesc& desc,
49 const base::SharedMemoryHandle& handle) 302 const base::SharedMemoryHandle& handle)
50 : Resource(OBJECT_IS_PROXY, resource), 303 : Resource(OBJECT_IS_PROXY, resource),
51 desc_(desc), 304 desc_(desc),
52 shm_(handle, false /* read_only */), 305 shm_(handle, false /* read_only */),
53 size_(desc.size.width * desc.size.height * 4), 306 size_(desc.size.width * desc.size.height * 4),
54 map_count_(0) { 307 map_count_(0) {
55 } 308 }
56 #endif // !defined(OS_NACL) 309 #endif // !defined(OS_NACL)
57 310
58 ImageData::~ImageData() { 311 ImageData::~ImageData() {
59 } 312 }
60 313
61 thunk::PPB_ImageData_API* ImageData::AsPPB_ImageData_API() { 314 PPB_ImageData_API* ImageData::AsPPB_ImageData_API() {
62 return this; 315 return this;
63 } 316 }
64 317
318 void ImageData::LastPluginRefWasDeleted() {
319 // The plugin no longer needs this ImageData, add it to our cache.
320 ImageDataCache::GetInstance()->Add(this);
321 }
322
65 PP_Bool ImageData::Describe(PP_ImageDataDesc* desc) { 323 PP_Bool ImageData::Describe(PP_ImageDataDesc* desc) {
66 memcpy(desc, &desc_, sizeof(PP_ImageDataDesc)); 324 memcpy(desc, &desc_, sizeof(PP_ImageDataDesc));
67 return PP_TRUE; 325 return PP_TRUE;
68 } 326 }
69 327
70 void* ImageData::Map() { 328 void* ImageData::Map() {
71 #if defined(OS_NACL) 329 #if defined(OS_NACL)
72 if (map_count_++ == 0) 330 if (map_count_++ == 0)
73 shm_.Map(size_); 331 shm_.Map(size_);
74 return shm_.memory(); 332 return shm_.memory();
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
114 } 372 }
115 373
116 SkCanvas* ImageData::GetCanvas() { 374 SkCanvas* ImageData::GetCanvas() {
117 #if defined(OS_NACL) 375 #if defined(OS_NACL)
118 return NULL; // No canvas in NaCl. 376 return NULL; // No canvas in NaCl.
119 #else 377 #else
120 return mapped_canvas_.get(); 378 return mapped_canvas_.get();
121 #endif 379 #endif
122 } 380 }
123 381
382 void ImageData::ZeroContents() {
383 void* data = Map();
384 memset(data, 0, desc_.stride * desc_.size.height);
385 Unmap();
386 }
387
124 #if !defined(OS_NACL) 388 #if !defined(OS_NACL)
125 // static 389 // static
126 ImageHandle ImageData::NullHandle() { 390 ImageHandle ImageData::NullHandle() {
127 #if defined(OS_WIN) 391 #if defined(OS_WIN)
128 return NULL; 392 return NULL;
129 #elif defined(OS_MACOSX) || defined(OS_ANDROID) 393 #elif defined(OS_MACOSX) || defined(OS_ANDROID)
130 return ImageHandle(); 394 return ImageHandle();
131 #else 395 #else
132 return 0; 396 return 0;
133 #endif 397 #endif
134 } 398 }
135 399
136 ImageHandle ImageData::HandleFromInt(int32_t i) { 400 ImageHandle ImageData::HandleFromInt(int32_t i) {
137 #if defined(OS_WIN) 401 #if defined(OS_WIN)
138 return reinterpret_cast<ImageHandle>(i); 402 return reinterpret_cast<ImageHandle>(i);
139 #elif defined(OS_MACOSX) || defined(OS_ANDROID) 403 #elif defined(OS_MACOSX) || defined(OS_ANDROID)
140 return ImageHandle(i, false); 404 return ImageHandle(i, false);
141 #else 405 #else
142 return static_cast<ImageHandle>(i); 406 return static_cast<ImageHandle>(i);
143 #endif 407 #endif
144 } 408 }
145 #endif // !defined(OS_NACL) 409 #endif // !defined(OS_NACL)
146 410
411 // PPB_ImageData_Proxy ---------------------------------------------------------
412
147 PPB_ImageData_Proxy::PPB_ImageData_Proxy(Dispatcher* dispatcher) 413 PPB_ImageData_Proxy::PPB_ImageData_Proxy(Dispatcher* dispatcher)
148 : InterfaceProxy(dispatcher) { 414 : InterfaceProxy(dispatcher) {
149 } 415 }
150 416
151 PPB_ImageData_Proxy::~PPB_ImageData_Proxy() { 417 PPB_ImageData_Proxy::~PPB_ImageData_Proxy() {
152 } 418 }
153 419
154 // static 420 // static
155 PP_Resource PPB_ImageData_Proxy::CreateProxyResource(PP_Instance instance, 421 PP_Resource PPB_ImageData_Proxy::CreateProxyResource(PP_Instance instance,
156 PP_ImageDataFormat format, 422 PP_ImageDataFormat format,
157 const PP_Size& size, 423 const PP_Size& size,
158 PP_Bool init_to_zero) { 424 PP_Bool init_to_zero) {
159 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); 425 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
160 if (!dispatcher) 426 if (!dispatcher)
161 return 0; 427 return 0;
162 428
429 // Check the cache.
430 scoped_refptr<ImageData> cached_image_data =
431 ImageDataCache::GetInstance()->Get(instance, size.width, size.height,
432 format);
433 if (cached_image_data.get()) {
434 // We have one we can re-use rather than allocating a new one. Only zero
435 // out if requested.
436 if (PP_ToBool(init_to_zero))
437 cached_image_data->ZeroContents();
438 return cached_image_data->GetReference();
439 }
440
163 HostResource result; 441 HostResource result;
164 std::string image_data_desc; 442 std::string image_data_desc;
165 #if defined(OS_NACL) 443 #if defined(OS_NACL)
166 base::SharedMemoryHandle image_handle = base::SharedMemory::NULLHandle(); 444 base::SharedMemoryHandle image_handle = base::SharedMemory::NULLHandle();
167 dispatcher->Send(new PpapiHostMsg_PPBImageData_CreateNaCl( 445 dispatcher->Send(new PpapiHostMsg_PPBImageData_CreateNaCl(
168 kApiID, instance, format, size, init_to_zero, 446 kApiID, instance, format, size, init_to_zero,
169 &result, &image_data_desc, &image_handle)); 447 &result, &image_data_desc, &image_handle));
170 #else 448 #else
171 ImageHandle image_handle = ImageData::NullHandle(); 449 ImageHandle image_handle = ImageData::NullHandle();
172 dispatcher->Send(new PpapiHostMsg_PPBImageData_Create( 450 dispatcher->Send(new PpapiHostMsg_PPBImageData_Create(
(...skipping 10 matching lines...) Expand all
183 461
184 return (new ImageData(result, desc, image_handle))->GetReference(); 462 return (new ImageData(result, desc, image_handle))->GetReference();
185 } 463 }
186 464
187 bool PPB_ImageData_Proxy::OnMessageReceived(const IPC::Message& msg) { 465 bool PPB_ImageData_Proxy::OnMessageReceived(const IPC::Message& msg) {
188 bool handled = true; 466 bool handled = true;
189 IPC_BEGIN_MESSAGE_MAP(PPB_ImageData_Proxy, msg) 467 IPC_BEGIN_MESSAGE_MAP(PPB_ImageData_Proxy, msg)
190 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBImageData_Create, OnHostMsgCreate) 468 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBImageData_Create, OnHostMsgCreate)
191 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBImageData_CreateNaCl, 469 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBImageData_CreateNaCl,
192 OnHostMsgCreateNaCl) 470 OnHostMsgCreateNaCl)
471
472 IPC_MESSAGE_HANDLER(PpapiMsg_PPBImageData_NotifyUnusedImageData,
473 OnPluginMsgNotifyUnusedImageData)
474
193 IPC_MESSAGE_UNHANDLED(handled = false) 475 IPC_MESSAGE_UNHANDLED(handled = false)
194 IPC_END_MESSAGE_MAP() 476 IPC_END_MESSAGE_MAP()
195 return handled; 477 return handled;
196 } 478 }
197 479
198 void PPB_ImageData_Proxy::OnHostMsgCreate(PP_Instance instance, 480 void PPB_ImageData_Proxy::OnHostMsgCreate(PP_Instance instance,
199 int32_t format, 481 int32_t format,
200 const PP_Size& size, 482 const PP_Size& size,
201 PP_Bool init_to_zero, 483 PP_Bool init_to_zero,
202 HostResource* result, 484 HostResource* result,
(...skipping 10 matching lines...) Expand all
213 if (enter.failed()) 495 if (enter.failed())
214 return; 496 return;
215 497
216 PP_Resource resource = enter.functions()->CreateImageData( 498 PP_Resource resource = enter.functions()->CreateImageData(
217 instance, static_cast<PP_ImageDataFormat>(format), size, init_to_zero); 499 instance, static_cast<PP_ImageDataFormat>(format), size, init_to_zero);
218 if (!resource) 500 if (!resource)
219 return; 501 return;
220 result->SetHostResource(instance, resource); 502 result->SetHostResource(instance, resource);
221 503
222 // Get the description, it's just serialized as a string. 504 // Get the description, it's just serialized as a string.
223 thunk::EnterResourceNoLock<thunk::PPB_ImageData_API> enter_resource( 505 thunk::EnterResourceNoLock<PPB_ImageData_API> enter_resource(resource, false);
224 resource, false);
225 PP_ImageDataDesc desc; 506 PP_ImageDataDesc desc;
226 if (enter_resource.object()->Describe(&desc) == PP_TRUE) { 507 if (enter_resource.object()->Describe(&desc) == PP_TRUE) {
227 image_data_desc->resize(sizeof(PP_ImageDataDesc)); 508 image_data_desc->resize(sizeof(PP_ImageDataDesc));
228 memcpy(&(*image_data_desc)[0], &desc, sizeof(PP_ImageDataDesc)); 509 memcpy(&(*image_data_desc)[0], &desc, sizeof(PP_ImageDataDesc));
229 } 510 }
230 511
231 // Get the shared memory handle. 512 // Get the shared memory handle.
232 uint32_t byte_count = 0; 513 uint32_t byte_count = 0;
233 int32_t handle = 0; 514 int32_t handle = 0;
234 if (enter_resource.object()->GetSharedMemory(&handle, &byte_count) == PP_OK) { 515 if (enter_resource.object()->GetSharedMemory(&handle, &byte_count) == PP_OK) {
(...skipping 29 matching lines...) Expand all
264 if (enter.failed()) 545 if (enter.failed())
265 return; 546 return;
266 547
267 PP_Resource resource = enter.functions()->CreateImageDataNaCl( 548 PP_Resource resource = enter.functions()->CreateImageDataNaCl(
268 instance, static_cast<PP_ImageDataFormat>(format), size, init_to_zero); 549 instance, static_cast<PP_ImageDataFormat>(format), size, init_to_zero);
269 if (!resource) 550 if (!resource)
270 return; 551 return;
271 result->SetHostResource(instance, resource); 552 result->SetHostResource(instance, resource);
272 553
273 // Get the description, it's just serialized as a string. 554 // Get the description, it's just serialized as a string.
274 thunk::EnterResourceNoLock<thunk::PPB_ImageData_API> enter_resource( 555 thunk::EnterResourceNoLock<PPB_ImageData_API> enter_resource(resource, false);
275 resource, false);
276 if (enter_resource.failed()) 556 if (enter_resource.failed())
277 return; 557 return;
278 PP_ImageDataDesc desc; 558 PP_ImageDataDesc desc;
279 if (enter_resource.object()->Describe(&desc) == PP_TRUE) { 559 if (enter_resource.object()->Describe(&desc) == PP_TRUE) {
280 image_data_desc->resize(sizeof(PP_ImageDataDesc)); 560 image_data_desc->resize(sizeof(PP_ImageDataDesc));
281 memcpy(&(*image_data_desc)[0], &desc, sizeof(PP_ImageDataDesc)); 561 memcpy(&(*image_data_desc)[0], &desc, sizeof(PP_ImageDataDesc));
282 } 562 }
283 int local_fd; 563 int local_fd;
284 uint32_t byte_count; 564 uint32_t byte_count;
285 if (enter_resource.object()->GetSharedMemory(&local_fd, &byte_count) != PP_OK) 565 if (enter_resource.object()->GetSharedMemory(&local_fd, &byte_count) != PP_OK)
286 return; 566 return;
287 567
288 // TODO(dmichael): Change trusted interface to return a PP_FileHandle, those 568 // TODO(dmichael): Change trusted interface to return a PP_FileHandle, those
289 // casts are ugly. 569 // casts are ugly.
290 base::PlatformFile platform_file = 570 base::PlatformFile platform_file =
291 #if defined(OS_WIN) 571 #if defined(OS_WIN)
292 reinterpret_cast<HANDLE>(static_cast<intptr_t>(local_fd)); 572 reinterpret_cast<HANDLE>(static_cast<intptr_t>(local_fd));
293 #elif defined(OS_POSIX) 573 #elif defined(OS_POSIX)
294 local_fd; 574 local_fd;
295 #else 575 #else
296 #error Not implemented. 576 #error Not implemented.
297 #endif // defined(OS_WIN) 577 #endif // defined(OS_WIN)
298 *result_image_handle = 578 *result_image_handle =
299 dispatcher->ShareHandleWithRemote(platform_file, false); 579 dispatcher->ShareHandleWithRemote(platform_file, false);
300 #endif // defined(OS_NACL) 580 #endif // defined(OS_NACL)
301 } 581 }
302 582
583 void PPB_ImageData_Proxy::OnPluginMsgNotifyUnusedImageData(
584 const HostResource& old_image_data) {
585 PluginGlobals* plugin_globals = PluginGlobals::Get();
586 if (!plugin_globals)
587 return; // This may happen if the plugin is maliciously sending this
588 // message to the renderer.
589
590 EnterPluginFromHostResource<PPB_ImageData_API> enter(old_image_data);
591 if (enter.succeeded()) {
592 ImageData* image_data = static_cast<ImageData*>(enter.object());
593 ImageDataCache::GetInstance()->ImageDataUsable(image_data);
594 }
595
596 // The renderer sent us a reference with the message. If the image data was
597 // still cached in our process, the proxy still holds a reference so we can
598 // remove the one the renderer just sent is. If the proxy no longer holds a
599 // reference, we released everything and we should also release the one the
600 // renderer just sent us.
601 dispatcher()->Send(new PpapiHostMsg_PPBCore_ReleaseResource(
602 API_ID_PPB_CORE, old_image_data));
603 }
604
303 } // namespace proxy 605 } // namespace proxy
304 } // namespace ppapi 606 } // namespace ppapi
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698