Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 // is as usable. | |
|
yzshen1
2012/08/21 22:07:24
is -> it.
| |
| 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 at least two frames for this time interfacl to | |
|
yzshen1
2012/08/21 22:07:24
interfacl -> interval
at at -> at
| |
| 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 base::WeakPtrFactory<ImageDataCache> weak_factory_; | |
|
yzshen1
2012/08/21 22:07:24
Why does it need to be a weak ptr factory?
brettw
2012/08/21 23:24:58
I added a comment
| |
| 228 | |
| 229 typedef std::map<PP_Instance, ImageDataInstanceCache> CacheMap; | |
| 230 CacheMap cache_; | |
| 231 | |
| 232 DISALLOW_COPY_AND_ASSIGN(ImageDataCache); | |
| 233 }; | |
| 234 | |
| 235 // static | |
| 236 ImageDataCache* ImageDataCache::GetInstance() { | |
| 237 return Singleton<ImageDataCache, | |
| 238 LeakySingletonTraits<ImageDataCache> >::get(); | |
| 239 } | |
| 240 | |
| 241 scoped_refptr<ImageData> ImageDataCache::Get(PP_Instance instance, | |
| 242 int width, int height, | |
| 243 PP_ImageDataFormat format) { | |
| 244 CacheMap::iterator found = cache_.find(instance); | |
| 245 if (found == cache_.end()) | |
| 246 return scoped_refptr<ImageData>(); | |
| 247 return found->second.Get(width, height, format); | |
| 248 } | |
| 249 | |
| 250 void ImageDataCache::Add(ImageData* image_data) { | |
| 251 cache_[image_data->pp_instance()].Add(image_data); | |
| 252 | |
| 253 // Schedule a timer to invalidate this entry. | |
| 254 MessageLoop::current()->PostDelayedTask( | |
| 255 FROM_HERE, | |
| 256 base::Bind(&ImageDataCache::OnTimer, | |
| 257 weak_factory_.GetWeakPtr(), | |
| 258 image_data->pp_instance()), | |
| 259 base::TimeDelta::FromSeconds(kMaxAgeSeconds)); | |
| 260 } | |
| 261 | |
| 262 void ImageDataCache::ImageDataUsable(ImageData* image_data) { | |
| 263 CacheMap::iterator found = cache_.find(image_data->pp_instance()); | |
| 264 if (found != cache_.end()) | |
| 265 found->second.ImageDataUsable(image_data); | |
| 266 } | |
| 267 | |
| 268 void ImageDataCache::OnTimer(PP_Instance instance) { | |
| 269 CacheMap::iterator found = cache_.find(instance); | |
| 270 if (found == cache_.end()) | |
| 271 return; | |
| 272 if (!found->second.ExpireEntries()) { | |
| 273 // There are no more entries for this instance, remove it from the cache. | |
| 274 cache_.erase(found); | |
| 275 } | |
| 276 } | |
| 277 | |
| 278 } // namespace | |
| 279 | |
| 280 // ImageData ------------------------------------------------------------------- | |
| 281 | |
| 33 #if !defined(OS_NACL) | 282 #if !defined(OS_NACL) |
| 34 ImageData::ImageData(const HostResource& resource, | 283 ImageData::ImageData(const HostResource& resource, |
| 35 const PP_ImageDataDesc& desc, | 284 const PP_ImageDataDesc& desc, |
| 36 ImageHandle handle) | 285 ImageHandle handle) |
| 37 : Resource(OBJECT_IS_PROXY, resource), | 286 : Resource(OBJECT_IS_PROXY, resource), |
| 38 desc_(desc) { | 287 desc_(desc) { |
| 39 #if defined(OS_WIN) | 288 #if defined(OS_WIN) |
| 40 transport_dib_.reset(TransportDIB::CreateWithHandle(handle)); | 289 transport_dib_.reset(TransportDIB::CreateWithHandle(handle)); |
| 41 #else | 290 #else |
| 42 transport_dib_.reset(TransportDIB::Map(handle)); | 291 transport_dib_.reset(TransportDIB::Map(handle)); |
| 43 #endif // defined(OS_WIN) | 292 #endif // defined(OS_WIN) |
| 44 } | 293 } |
| 45 #else // !defined(OS_NACL) | 294 #else // !defined(OS_NACL) |
| 46 | 295 |
| 47 ImageData::ImageData(const HostResource& resource, | 296 ImageData::ImageData(const HostResource& resource, |
| 48 const PP_ImageDataDesc& desc, | 297 const PP_ImageDataDesc& desc, |
| 49 const base::SharedMemoryHandle& handle) | 298 const base::SharedMemoryHandle& handle) |
| 50 : Resource(OBJECT_IS_PROXY, resource), | 299 : Resource(OBJECT_IS_PROXY, resource), |
| 51 desc_(desc), | 300 desc_(desc), |
| 52 shm_(handle, false /* read_only */), | 301 shm_(handle, false /* read_only */), |
| 53 size_(desc.size.width * desc.size.height * 4), | 302 size_(desc.size.width * desc.size.height * 4), |
| 54 map_count_(0) { | 303 map_count_(0) { |
| 55 } | 304 } |
| 56 #endif // !defined(OS_NACL) | 305 #endif // !defined(OS_NACL) |
| 57 | 306 |
| 58 ImageData::~ImageData() { | 307 ImageData::~ImageData() { |
| 59 } | 308 } |
| 60 | 309 |
| 61 thunk::PPB_ImageData_API* ImageData::AsPPB_ImageData_API() { | 310 PPB_ImageData_API* ImageData::AsPPB_ImageData_API() { |
| 62 return this; | 311 return this; |
| 63 } | 312 } |
| 64 | 313 |
| 314 void ImageData::LastPluginRefWasDeleted() { | |
| 315 // The plugin no longer needs this ImageData, add it to our cache. | |
| 316 ImageDataCache::GetInstance()->Add(this); | |
| 317 } | |
| 318 | |
| 65 PP_Bool ImageData::Describe(PP_ImageDataDesc* desc) { | 319 PP_Bool ImageData::Describe(PP_ImageDataDesc* desc) { |
| 66 memcpy(desc, &desc_, sizeof(PP_ImageDataDesc)); | 320 memcpy(desc, &desc_, sizeof(PP_ImageDataDesc)); |
| 67 return PP_TRUE; | 321 return PP_TRUE; |
| 68 } | 322 } |
| 69 | 323 |
| 70 void* ImageData::Map() { | 324 void* ImageData::Map() { |
| 71 #if defined(OS_NACL) | 325 #if defined(OS_NACL) |
| 72 if (map_count_++ == 0) | 326 if (map_count_++ == 0) |
| 73 shm_.Map(size_); | 327 shm_.Map(size_); |
| 74 return shm_.memory(); | 328 return shm_.memory(); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 114 } | 368 } |
| 115 | 369 |
| 116 SkCanvas* ImageData::GetCanvas() { | 370 SkCanvas* ImageData::GetCanvas() { |
| 117 #if defined(OS_NACL) | 371 #if defined(OS_NACL) |
| 118 return NULL; // No canvas in NaCl. | 372 return NULL; // No canvas in NaCl. |
| 119 #else | 373 #else |
| 120 return mapped_canvas_.get(); | 374 return mapped_canvas_.get(); |
| 121 #endif | 375 #endif |
| 122 } | 376 } |
| 123 | 377 |
| 378 void ImageData::ZeroContents() { | |
| 379 void* data = Map(); | |
| 380 memset(data, 0, desc_.stride * desc_.size.height); | |
| 381 Unmap(); | |
| 382 } | |
| 383 | |
| 124 #if !defined(OS_NACL) | 384 #if !defined(OS_NACL) |
| 125 // static | 385 // static |
| 126 ImageHandle ImageData::NullHandle() { | 386 ImageHandle ImageData::NullHandle() { |
| 127 #if defined(OS_WIN) | 387 #if defined(OS_WIN) |
| 128 return NULL; | 388 return NULL; |
| 129 #elif defined(OS_MACOSX) || defined(OS_ANDROID) | 389 #elif defined(OS_MACOSX) || defined(OS_ANDROID) |
| 130 return ImageHandle(); | 390 return ImageHandle(); |
| 131 #else | 391 #else |
| 132 return 0; | 392 return 0; |
| 133 #endif | 393 #endif |
| 134 } | 394 } |
| 135 | 395 |
| 136 ImageHandle ImageData::HandleFromInt(int32_t i) { | 396 ImageHandle ImageData::HandleFromInt(int32_t i) { |
| 137 #if defined(OS_WIN) | 397 #if defined(OS_WIN) |
| 138 return reinterpret_cast<ImageHandle>(i); | 398 return reinterpret_cast<ImageHandle>(i); |
| 139 #elif defined(OS_MACOSX) || defined(OS_ANDROID) | 399 #elif defined(OS_MACOSX) || defined(OS_ANDROID) |
| 140 return ImageHandle(i, false); | 400 return ImageHandle(i, false); |
| 141 #else | 401 #else |
| 142 return static_cast<ImageHandle>(i); | 402 return static_cast<ImageHandle>(i); |
| 143 #endif | 403 #endif |
| 144 } | 404 } |
| 145 #endif // !defined(OS_NACL) | 405 #endif // !defined(OS_NACL) |
| 146 | 406 |
| 407 // PPB_ImageData_Proxy --------------------------------------------------------- | |
| 408 | |
| 147 PPB_ImageData_Proxy::PPB_ImageData_Proxy(Dispatcher* dispatcher) | 409 PPB_ImageData_Proxy::PPB_ImageData_Proxy(Dispatcher* dispatcher) |
| 148 : InterfaceProxy(dispatcher) { | 410 : InterfaceProxy(dispatcher) { |
| 149 } | 411 } |
| 150 | 412 |
| 151 PPB_ImageData_Proxy::~PPB_ImageData_Proxy() { | 413 PPB_ImageData_Proxy::~PPB_ImageData_Proxy() { |
| 152 } | 414 } |
| 153 | 415 |
| 154 // static | 416 // static |
| 155 PP_Resource PPB_ImageData_Proxy::CreateProxyResource(PP_Instance instance, | 417 PP_Resource PPB_ImageData_Proxy::CreateProxyResource(PP_Instance instance, |
| 156 PP_ImageDataFormat format, | 418 PP_ImageDataFormat format, |
| 157 const PP_Size& size, | 419 const PP_Size& size, |
| 158 PP_Bool init_to_zero) { | 420 PP_Bool init_to_zero) { |
| 159 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); | 421 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); |
| 160 if (!dispatcher) | 422 if (!dispatcher) |
| 161 return 0; | 423 return 0; |
| 162 | 424 |
| 425 // Check the cache. | |
| 426 scoped_refptr<ImageData> cached_image_data = | |
| 427 ImageDataCache::GetInstance()->Get(instance, size.width, size.height, | |
| 428 format); | |
| 429 if (cached_image_data.get()) { | |
| 430 // We have one we can re-use rather than allocating a new one. Only zero | |
| 431 // out if requested. | |
| 432 if (PP_ToBool(init_to_zero)) | |
| 433 cached_image_data->ZeroContents(); | |
| 434 return cached_image_data->GetReference(); | |
| 435 } | |
| 436 | |
| 163 HostResource result; | 437 HostResource result; |
| 164 std::string image_data_desc; | 438 std::string image_data_desc; |
| 165 #if defined(OS_NACL) | 439 #if defined(OS_NACL) |
| 166 base::SharedMemoryHandle image_handle = base::SharedMemory::NULLHandle(); | 440 base::SharedMemoryHandle image_handle = base::SharedMemory::NULLHandle(); |
| 167 dispatcher->Send(new PpapiHostMsg_PPBImageData_CreateNaCl( | 441 dispatcher->Send(new PpapiHostMsg_PPBImageData_CreateNaCl( |
| 168 kApiID, instance, format, size, init_to_zero, | 442 kApiID, instance, format, size, init_to_zero, |
| 169 &result, &image_data_desc, &image_handle)); | 443 &result, &image_data_desc, &image_handle)); |
| 170 #else | 444 #else |
| 171 ImageHandle image_handle = ImageData::NullHandle(); | 445 ImageHandle image_handle = ImageData::NullHandle(); |
| 172 dispatcher->Send(new PpapiHostMsg_PPBImageData_Create( | 446 dispatcher->Send(new PpapiHostMsg_PPBImageData_Create( |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 183 | 457 |
| 184 return (new ImageData(result, desc, image_handle))->GetReference(); | 458 return (new ImageData(result, desc, image_handle))->GetReference(); |
| 185 } | 459 } |
| 186 | 460 |
| 187 bool PPB_ImageData_Proxy::OnMessageReceived(const IPC::Message& msg) { | 461 bool PPB_ImageData_Proxy::OnMessageReceived(const IPC::Message& msg) { |
| 188 bool handled = true; | 462 bool handled = true; |
| 189 IPC_BEGIN_MESSAGE_MAP(PPB_ImageData_Proxy, msg) | 463 IPC_BEGIN_MESSAGE_MAP(PPB_ImageData_Proxy, msg) |
| 190 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBImageData_Create, OnHostMsgCreate) | 464 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBImageData_Create, OnHostMsgCreate) |
| 191 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBImageData_CreateNaCl, | 465 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBImageData_CreateNaCl, |
| 192 OnHostMsgCreateNaCl) | 466 OnHostMsgCreateNaCl) |
| 467 | |
| 468 IPC_MESSAGE_HANDLER(PpapiPluginMsg_PPBImageData_NotifyUnusedImageData, | |
| 469 OnPluginMsgNotifyUnusedImageData) | |
| 470 | |
| 193 IPC_MESSAGE_UNHANDLED(handled = false) | 471 IPC_MESSAGE_UNHANDLED(handled = false) |
| 194 IPC_END_MESSAGE_MAP() | 472 IPC_END_MESSAGE_MAP() |
| 195 return handled; | 473 return handled; |
| 196 } | 474 } |
| 197 | 475 |
| 198 void PPB_ImageData_Proxy::OnHostMsgCreate(PP_Instance instance, | 476 void PPB_ImageData_Proxy::OnHostMsgCreate(PP_Instance instance, |
| 199 int32_t format, | 477 int32_t format, |
| 200 const PP_Size& size, | 478 const PP_Size& size, |
| 201 PP_Bool init_to_zero, | 479 PP_Bool init_to_zero, |
| 202 HostResource* result, | 480 HostResource* result, |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 213 if (enter.failed()) | 491 if (enter.failed()) |
| 214 return; | 492 return; |
| 215 | 493 |
| 216 PP_Resource resource = enter.functions()->CreateImageData( | 494 PP_Resource resource = enter.functions()->CreateImageData( |
| 217 instance, static_cast<PP_ImageDataFormat>(format), size, init_to_zero); | 495 instance, static_cast<PP_ImageDataFormat>(format), size, init_to_zero); |
| 218 if (!resource) | 496 if (!resource) |
| 219 return; | 497 return; |
| 220 result->SetHostResource(instance, resource); | 498 result->SetHostResource(instance, resource); |
| 221 | 499 |
| 222 // Get the description, it's just serialized as a string. | 500 // Get the description, it's just serialized as a string. |
| 223 thunk::EnterResourceNoLock<thunk::PPB_ImageData_API> enter_resource( | 501 thunk::EnterResourceNoLock<PPB_ImageData_API> enter_resource(resource, false); |
| 224 resource, false); | |
| 225 PP_ImageDataDesc desc; | 502 PP_ImageDataDesc desc; |
| 226 if (enter_resource.object()->Describe(&desc) == PP_TRUE) { | 503 if (enter_resource.object()->Describe(&desc) == PP_TRUE) { |
| 227 image_data_desc->resize(sizeof(PP_ImageDataDesc)); | 504 image_data_desc->resize(sizeof(PP_ImageDataDesc)); |
| 228 memcpy(&(*image_data_desc)[0], &desc, sizeof(PP_ImageDataDesc)); | 505 memcpy(&(*image_data_desc)[0], &desc, sizeof(PP_ImageDataDesc)); |
| 229 } | 506 } |
| 230 | 507 |
| 231 // Get the shared memory handle. | 508 // Get the shared memory handle. |
| 232 uint32_t byte_count = 0; | 509 uint32_t byte_count = 0; |
| 233 int32_t handle = 0; | 510 int32_t handle = 0; |
| 234 if (enter_resource.object()->GetSharedMemory(&handle, &byte_count) == PP_OK) { | 511 if (enter_resource.object()->GetSharedMemory(&handle, &byte_count) == PP_OK) { |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 264 if (enter.failed()) | 541 if (enter.failed()) |
| 265 return; | 542 return; |
| 266 | 543 |
| 267 PP_Resource resource = enter.functions()->CreateImageDataNaCl( | 544 PP_Resource resource = enter.functions()->CreateImageDataNaCl( |
| 268 instance, static_cast<PP_ImageDataFormat>(format), size, init_to_zero); | 545 instance, static_cast<PP_ImageDataFormat>(format), size, init_to_zero); |
| 269 if (!resource) | 546 if (!resource) |
| 270 return; | 547 return; |
| 271 result->SetHostResource(instance, resource); | 548 result->SetHostResource(instance, resource); |
| 272 | 549 |
| 273 // Get the description, it's just serialized as a string. | 550 // Get the description, it's just serialized as a string. |
| 274 thunk::EnterResourceNoLock<thunk::PPB_ImageData_API> enter_resource( | 551 thunk::EnterResourceNoLock<PPB_ImageData_API> enter_resource(resource, false); |
| 275 resource, false); | |
| 276 if (enter_resource.failed()) | 552 if (enter_resource.failed()) |
| 277 return; | 553 return; |
| 278 PP_ImageDataDesc desc; | 554 PP_ImageDataDesc desc; |
| 279 if (enter_resource.object()->Describe(&desc) == PP_TRUE) { | 555 if (enter_resource.object()->Describe(&desc) == PP_TRUE) { |
| 280 image_data_desc->resize(sizeof(PP_ImageDataDesc)); | 556 image_data_desc->resize(sizeof(PP_ImageDataDesc)); |
| 281 memcpy(&(*image_data_desc)[0], &desc, sizeof(PP_ImageDataDesc)); | 557 memcpy(&(*image_data_desc)[0], &desc, sizeof(PP_ImageDataDesc)); |
| 282 } | 558 } |
| 283 int local_fd; | 559 int local_fd; |
| 284 uint32_t byte_count; | 560 uint32_t byte_count; |
| 285 if (enter_resource.object()->GetSharedMemory(&local_fd, &byte_count) != PP_OK) | 561 if (enter_resource.object()->GetSharedMemory(&local_fd, &byte_count) != PP_OK) |
| 286 return; | 562 return; |
| 287 | 563 |
| 288 // TODO(dmichael): Change trusted interface to return a PP_FileHandle, those | 564 // TODO(dmichael): Change trusted interface to return a PP_FileHandle, those |
| 289 // casts are ugly. | 565 // casts are ugly. |
| 290 base::PlatformFile platform_file = | 566 base::PlatformFile platform_file = |
| 291 #if defined(OS_WIN) | 567 #if defined(OS_WIN) |
| 292 reinterpret_cast<HANDLE>(static_cast<intptr_t>(local_fd)); | 568 reinterpret_cast<HANDLE>(static_cast<intptr_t>(local_fd)); |
| 293 #elif defined(OS_POSIX) | 569 #elif defined(OS_POSIX) |
| 294 local_fd; | 570 local_fd; |
| 295 #else | 571 #else |
| 296 #error Not implemented. | 572 #error Not implemented. |
| 297 #endif // defined(OS_WIN) | 573 #endif // defined(OS_WIN) |
| 298 *result_image_handle = | 574 *result_image_handle = |
| 299 dispatcher->ShareHandleWithRemote(platform_file, false); | 575 dispatcher->ShareHandleWithRemote(platform_file, false); |
| 300 #endif // defined(OS_NACL) | 576 #endif // defined(OS_NACL) |
| 301 } | 577 } |
| 302 | 578 |
| 579 void PPB_ImageData_Proxy::OnPluginMsgNotifyUnusedImageData( | |
| 580 const HostResource& old_image_data) { | |
| 581 PluginGlobals* plugin_globals = PluginGlobals::Get(); | |
| 582 if (!plugin_globals) | |
| 583 return; // This may happen if the plugin is malixiously sending this | |
|
yzshen1
2012/08/21 22:07:24
malixiously -> maliciously
| |
| 584 // message to the renderer. | |
| 585 | |
| 586 EnterPluginFromHostResource<PPB_ImageData_API> enter(old_image_data); | |
| 587 if (enter.succeeded()) { | |
| 588 ImageData* image_data = static_cast<ImageData*>(enter.object()); | |
| 589 ImageDataCache::GetInstance()->ImageDataUsable(image_data); | |
| 590 } | |
| 591 | |
| 592 // The renderer sent us a reference with the message. If the image data was | |
| 593 // still cached in our process, the proxy still holds a reference so we can | |
| 594 // remove the one the renderer just sent is. If the proxy no longer holds a | |
| 595 // reference, we released everything and we should also release the one the | |
| 596 // renderer just sent us. | |
| 597 dispatcher()->Send(new PpapiHostMsg_PPBCore_ReleaseResource( | |
| 598 API_ID_PPB_CORE, old_image_data)); | |
| 599 } | |
| 600 | |
| 303 } // namespace proxy | 601 } // namespace proxy |
| 304 } // namespace ppapi | 602 } // namespace ppapi |
| OLD | NEW |