ppb_image_data_impl.cc revision bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3
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 3// found in the LICENSE file. 4 5#include "content/renderer/pepper/ppb_image_data_impl.h" 6 7#include <algorithm> 8#include <limits> 9 10#include "base/logging.h" 11#include "base/memory/scoped_ptr.h" 12#include "content/renderer/pepper/common.h" 13#include "content/renderer/pepper/resource_helper.h" 14#include "skia/ext/platform_canvas.h" 15#include "ppapi/c/pp_instance.h" 16#include "ppapi/c/pp_resource.h" 17#include "ppapi/c/ppb_image_data.h" 18#include "ppapi/thunk/thunk.h" 19#include "third_party/skia/include/core/SkColorPriv.h" 20 21using ::ppapi::thunk::PPB_ImageData_API; 22 23namespace webkit { 24namespace ppapi { 25 26PPB_ImageData_Impl::PPB_ImageData_Impl(PP_Instance instance, 27 PPB_ImageData_Shared::ImageDataType type) 28 : Resource(::ppapi::OBJECT_IS_IMPL, instance), 29 format_(PP_IMAGEDATAFORMAT_BGRA_PREMUL), 30 width_(0), 31 height_(0) { 32 switch (type) { 33 case PPB_ImageData_Shared::PLATFORM: 34 backend_.reset(new ImageDataPlatformBackend); 35 return; 36 case PPB_ImageData_Shared::SIMPLE: 37 backend_.reset(new ImageDataSimpleBackend); 38 return; 39 // No default: so that we get a compiler warning if any types are added. 40 } 41 NOTREACHED(); 42} 43 44PPB_ImageData_Impl::~PPB_ImageData_Impl() { 45} 46 47bool PPB_ImageData_Impl::Init(PP_ImageDataFormat format, 48 int width, int height, 49 bool init_to_zero) { 50 // TODO(brettw) this should be called only on the main thread! 51 if (!IsImageDataFormatSupported(format)) 52 return false; // Only support this one format for now. 53 if (width <= 0 || height <= 0) 54 return false; 55 if (static_cast<int64>(width) * static_cast<int64>(height) >= 56 std::numeric_limits<int32>::max() / 4) 57 return false; // Prevent overflow of signed 32-bit ints. 58 59 format_ = format; 60 width_ = width; 61 height_ = height; 62 return backend_->Init(this, format, width, height, init_to_zero); 63} 64 65// static 66PP_Resource PPB_ImageData_Impl::Create(PP_Instance instance, 67 PPB_ImageData_Shared::ImageDataType type, 68 PP_ImageDataFormat format, 69 const PP_Size& size, 70 PP_Bool init_to_zero) { 71 scoped_refptr<PPB_ImageData_Impl> 72 data(new PPB_ImageData_Impl(instance, type)); 73 if (!data->Init(format, size.width, size.height, !!init_to_zero)) 74 return 0; 75 return data->GetReference(); 76} 77 78PPB_ImageData_API* PPB_ImageData_Impl::AsPPB_ImageData_API() { 79 return this; 80} 81 82bool PPB_ImageData_Impl::IsMapped() const { 83 return backend_->IsMapped(); 84} 85 86PluginDelegate::PlatformImage2D* PPB_ImageData_Impl::PlatformImage() const { 87 return backend_->PlatformImage(); 88} 89 90PP_Bool PPB_ImageData_Impl::Describe(PP_ImageDataDesc* desc) { 91 desc->format = format_; 92 desc->size.width = width_; 93 desc->size.height = height_; 94 desc->stride = width_ * 4; 95 return PP_TRUE; 96} 97 98void* PPB_ImageData_Impl::Map() { 99 return backend_->Map(); 100} 101 102void PPB_ImageData_Impl::Unmap() { 103 backend_->Unmap(); 104} 105 106int32_t PPB_ImageData_Impl::GetSharedMemory(int* handle, uint32_t* byte_count) { 107 return backend_->GetSharedMemory(handle, byte_count); 108} 109 110skia::PlatformCanvas* PPB_ImageData_Impl::GetPlatformCanvas() { 111 return backend_->GetPlatformCanvas(); 112} 113 114SkCanvas* PPB_ImageData_Impl::GetCanvas() { 115 return backend_->GetCanvas(); 116} 117 118void PPB_ImageData_Impl::SetIsCandidateForReuse() { 119 // Nothing to do since we don't support image data re-use in-process. 120} 121 122const SkBitmap* PPB_ImageData_Impl::GetMappedBitmap() const { 123 return backend_->GetMappedBitmap(); 124} 125 126// ImageDataPlatformBackend ---------------------------------------------------- 127 128ImageDataPlatformBackend::ImageDataPlatformBackend() { 129} 130 131ImageDataPlatformBackend::~ImageDataPlatformBackend() { 132} 133 134bool ImageDataPlatformBackend::Init(PPB_ImageData_Impl* impl, 135 PP_ImageDataFormat format, 136 int width, int height, 137 bool init_to_zero) { 138 PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(impl); 139 if (!plugin_delegate) 140 return false; 141 142 // TODO(brettw) use init_to_zero when we implement caching. 143 platform_image_.reset(plugin_delegate->CreateImage2D(width, height)); 144 return !!platform_image_.get(); 145} 146 147bool ImageDataPlatformBackend::IsMapped() const { 148 return !!mapped_canvas_.get(); 149} 150 151PluginDelegate::PlatformImage2D* 152ImageDataPlatformBackend::PlatformImage() const { 153 return platform_image_.get(); 154} 155 156void* ImageDataPlatformBackend::Map() { 157 if (!mapped_canvas_) { 158 mapped_canvas_.reset(platform_image_->Map()); 159 if (!mapped_canvas_) 160 return NULL; 161 } 162 const SkBitmap& bitmap = 163 skia::GetTopDevice(*mapped_canvas_)->accessBitmap(true); 164 165 // Our platform bitmaps are set to opaque by default, which we don't want. 166 const_cast<SkBitmap&>(bitmap).setIsOpaque(false); 167 168 bitmap.lockPixels(); 169 return bitmap.getAddr32(0, 0); 170} 171 172void ImageDataPlatformBackend::Unmap() { 173 // This is currently unimplemented, which is OK. The data will just always 174 // be around once it's mapped. Chrome's TransportDIB isn't currently 175 // unmappable without freeing it, but this may be something we want to support 176 // in the future to save some memory. 177} 178 179int32_t ImageDataPlatformBackend::GetSharedMemory(int* handle, 180 uint32_t* byte_count) { 181 *handle = platform_image_->GetSharedMemoryHandle(byte_count); 182 return PP_OK; 183} 184 185skia::PlatformCanvas* ImageDataPlatformBackend::GetPlatformCanvas() { 186 return mapped_canvas_.get(); 187} 188 189SkCanvas* ImageDataPlatformBackend::GetCanvas() { 190 return mapped_canvas_.get(); 191} 192 193const SkBitmap* ImageDataPlatformBackend::GetMappedBitmap() const { 194 if (!mapped_canvas_) 195 return NULL; 196 return &skia::GetTopDevice(*mapped_canvas_)->accessBitmap(false); 197} 198 199// ImageDataSimpleBackend ------------------------------------------------------ 200 201ImageDataSimpleBackend::ImageDataSimpleBackend() 202 : map_count_(0) { 203} 204 205ImageDataSimpleBackend::~ImageDataSimpleBackend() { 206} 207 208bool ImageDataSimpleBackend::Init(PPB_ImageData_Impl* impl, 209 PP_ImageDataFormat format, 210 int width, int height, 211 bool init_to_zero) { 212 skia_bitmap_.setConfig(SkBitmap::kARGB_8888_Config, 213 impl->width(), impl->height()); 214 PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(impl); 215 if (!plugin_delegate) 216 return false; 217 shared_memory_.reset( 218 plugin_delegate->CreateAnonymousSharedMemory(skia_bitmap_.getSize())); 219 return !!shared_memory_.get(); 220} 221 222bool ImageDataSimpleBackend::IsMapped() const { 223 return map_count_ > 0; 224} 225 226PluginDelegate::PlatformImage2D* ImageDataSimpleBackend::PlatformImage() const { 227 return NULL; 228} 229 230void* ImageDataSimpleBackend::Map() { 231 DCHECK(shared_memory_.get()); 232 if (map_count_++ == 0) { 233 shared_memory_->Map(skia_bitmap_.getSize()); 234 skia_bitmap_.setPixels(shared_memory_->memory()); 235 // Our platform bitmaps are set to opaque by default, which we don't want. 236 skia_bitmap_.setIsOpaque(false); 237 skia_canvas_.reset(new SkCanvas(skia_bitmap_)); 238 return skia_bitmap_.getAddr32(0, 0); 239 } 240 return shared_memory_->memory(); 241} 242 243void ImageDataSimpleBackend::Unmap() { 244 if (--map_count_ == 0) 245 shared_memory_->Unmap(); 246} 247 248int32_t ImageDataSimpleBackend::GetSharedMemory(int* handle, 249 uint32_t* byte_count) { 250 *byte_count = skia_bitmap_.getSize(); 251#if defined(OS_POSIX) 252 *handle = shared_memory_->handle().fd; 253#elif defined(OS_WIN) 254 *handle = reinterpret_cast<int>(shared_memory_->handle()); 255#else 256#error "Platform not supported." 257#endif 258 return PP_OK; 259} 260 261skia::PlatformCanvas* ImageDataSimpleBackend::GetPlatformCanvas() { 262 return NULL; 263} 264 265SkCanvas* ImageDataSimpleBackend::GetCanvas() { 266 if (!IsMapped()) 267 return NULL; 268 return skia_canvas_.get(); 269} 270 271const SkBitmap* ImageDataSimpleBackend::GetMappedBitmap() const { 272 if (!IsMapped()) 273 return NULL; 274 return &skia_bitmap_; 275} 276 277} // namespace ppapi 278} // namespace webkit 279