Home | History | Annotate | Download | only in pepper
      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/common/view_messages.h"
     13 #include "content/renderer/pepper/common.h"
     14 #include "content/renderer/render_thread_impl.h"
     15 #include "ppapi/c/pp_errors.h"
     16 #include "ppapi/c/pp_instance.h"
     17 #include "ppapi/c/pp_resource.h"
     18 #include "ppapi/c/ppb_image_data.h"
     19 #include "ppapi/thunk/thunk.h"
     20 #include "skia/ext/platform_canvas.h"
     21 #include "third_party/skia/include/core/SkColorPriv.h"
     22 #include "ui/surface/transport_dib.h"
     23 
     24 using ppapi::thunk::PPB_ImageData_API;
     25 
     26 namespace content {
     27 
     28 PPB_ImageData_Impl::PPB_ImageData_Impl(PP_Instance instance,
     29                                        PPB_ImageData_Shared::ImageDataType type)
     30     : Resource(ppapi::OBJECT_IS_IMPL, instance),
     31       format_(PP_IMAGEDATAFORMAT_BGRA_PREMUL),
     32       width_(0),
     33       height_(0) {
     34   switch (type) {
     35     case PPB_ImageData_Shared::PLATFORM:
     36       backend_.reset(new ImageDataPlatformBackend);
     37       return;
     38     case PPB_ImageData_Shared::SIMPLE:
     39       backend_.reset(new ImageDataSimpleBackend);
     40       return;
     41     // No default: so that we get a compiler warning if any types are added.
     42   }
     43   NOTREACHED();
     44 }
     45 
     46 PPB_ImageData_Impl::~PPB_ImageData_Impl() {
     47 }
     48 
     49 bool PPB_ImageData_Impl::Init(PP_ImageDataFormat format,
     50                               int width, int height,
     51                               bool init_to_zero) {
     52   // TODO(brettw) this should be called only on the main thread!
     53   if (!IsImageDataFormatSupported(format))
     54     return false;  // Only support this one format for now.
     55   if (width <= 0 || height <= 0)
     56     return false;
     57   if (static_cast<int64>(width) * static_cast<int64>(height) >=
     58       std::numeric_limits<int32>::max() / 4)
     59     return false;  // Prevent overflow of signed 32-bit ints.
     60 
     61   format_ = format;
     62   width_ = width;
     63   height_ = height;
     64   return backend_->Init(this, format, width, height, init_to_zero);
     65 }
     66 
     67 // static
     68 PP_Resource PPB_ImageData_Impl::Create(PP_Instance instance,
     69                                        PPB_ImageData_Shared::ImageDataType type,
     70                                        PP_ImageDataFormat format,
     71                                        const PP_Size& size,
     72                                        PP_Bool init_to_zero) {
     73   scoped_refptr<PPB_ImageData_Impl>
     74       data(new PPB_ImageData_Impl(instance, type));
     75   if (!data->Init(format, size.width, size.height, !!init_to_zero))
     76     return 0;
     77   return data->GetReference();
     78 }
     79 
     80 PPB_ImageData_API* PPB_ImageData_Impl::AsPPB_ImageData_API() {
     81   return this;
     82 }
     83 
     84 bool PPB_ImageData_Impl::IsMapped() const {
     85   return backend_->IsMapped();
     86 }
     87 
     88 TransportDIB* PPB_ImageData_Impl::GetTransportDIB() const {
     89   return backend_->GetTransportDIB();
     90 }
     91 
     92 PP_Bool PPB_ImageData_Impl::Describe(PP_ImageDataDesc* desc) {
     93   desc->format = format_;
     94   desc->size.width = width_;
     95   desc->size.height = height_;
     96   desc->stride = width_ * 4;
     97   return PP_TRUE;
     98 }
     99 
    100 void* PPB_ImageData_Impl::Map() {
    101   return backend_->Map();
    102 }
    103 
    104 void PPB_ImageData_Impl::Unmap() {
    105   backend_->Unmap();
    106 }
    107 
    108 int32_t PPB_ImageData_Impl::GetSharedMemory(int* handle, uint32_t* byte_count) {
    109   return backend_->GetSharedMemory(handle, byte_count);
    110 }
    111 
    112 skia::PlatformCanvas* PPB_ImageData_Impl::GetPlatformCanvas() {
    113   return backend_->GetPlatformCanvas();
    114 }
    115 
    116 SkCanvas* PPB_ImageData_Impl::GetCanvas() {
    117   return backend_->GetCanvas();
    118 }
    119 
    120 void PPB_ImageData_Impl::SetIsCandidateForReuse() {
    121   // Nothing to do since we don't support image data re-use in-process.
    122 }
    123 
    124 const SkBitmap* PPB_ImageData_Impl::GetMappedBitmap() const {
    125   return backend_->GetMappedBitmap();
    126 }
    127 
    128 // ImageDataPlatformBackend ----------------------------------------------------
    129 
    130 ImageDataPlatformBackend::ImageDataPlatformBackend()
    131     : width_(0),
    132       height_(0) {
    133 }
    134 
    135 // On POSIX, we have to tell the browser to free the transport DIB.
    136 ImageDataPlatformBackend::~ImageDataPlatformBackend() {
    137 #if defined(OS_POSIX) && !defined(TOOLKIT_GTK) && !defined(OS_ANDROID)
    138   if (dib_) {
    139     RenderThreadImpl::current()->Send(
    140         new ViewHostMsg_FreeTransportDIB(dib_->id()));
    141   }
    142 #endif
    143 }
    144 
    145 bool ImageDataPlatformBackend::Init(PPB_ImageData_Impl* impl,
    146                                     PP_ImageDataFormat format,
    147                                     int width, int height,
    148                                     bool init_to_zero) {
    149   // TODO(brettw) use init_to_zero when we implement caching.
    150   width_ = width;
    151   height_ = height;
    152   uint32 buffer_size = width_ * height_ * 4;
    153 
    154   // Allocate the transport DIB and the PlatformCanvas pointing to it.
    155 #if defined(OS_POSIX) && !defined(TOOLKIT_GTK) && !defined(OS_ANDROID)
    156   // On the Mac, shared memory has to be created in the browser in order to
    157   // work in the sandbox.  Do this by sending a message to the browser
    158   // requesting a TransportDIB (see also
    159   // chrome/renderer/webplugin_delegate_proxy.cc, method
    160   // WebPluginDelegateProxy::CreateBitmap() for similar code). The TransportDIB
    161   // is cached in the browser, and is freed (in typical cases) by the
    162   // TransportDIB's destructor.
    163   TransportDIB::Handle dib_handle;
    164   IPC::Message* msg = new ViewHostMsg_AllocTransportDIB(buffer_size,
    165                                                         true,
    166                                                         &dib_handle);
    167   if (!RenderThreadImpl::current()->Send(msg))
    168     return false;
    169   if (!TransportDIB::is_valid_handle(dib_handle))
    170     return false;
    171 
    172   TransportDIB* dib = TransportDIB::CreateWithHandle(dib_handle);
    173 #else
    174   static int next_dib_id = 0;
    175   TransportDIB* dib = TransportDIB::Create(buffer_size, next_dib_id++);
    176   if (!dib)
    177     return false;
    178 #endif
    179   dib_.reset(dib);
    180   return true;
    181 }
    182 
    183 bool ImageDataPlatformBackend::IsMapped() const {
    184   return !!mapped_canvas_.get();
    185 }
    186 
    187 TransportDIB* ImageDataPlatformBackend::GetTransportDIB() const {
    188   return dib_.get();
    189 }
    190 
    191 void* ImageDataPlatformBackend::Map() {
    192   if (!mapped_canvas_) {
    193     mapped_canvas_.reset(dib_->GetPlatformCanvas(width_, height_));
    194     if (!mapped_canvas_)
    195       return NULL;
    196   }
    197   const SkBitmap& bitmap =
    198       skia::GetTopDevice(*mapped_canvas_)->accessBitmap(true);
    199 
    200   // Our platform bitmaps are set to opaque by default, which we don't want.
    201   const_cast<SkBitmap&>(bitmap).setIsOpaque(false);
    202 
    203   bitmap.lockPixels();
    204   return bitmap.getAddr32(0, 0);
    205 }
    206 
    207 void ImageDataPlatformBackend::Unmap() {
    208   // This is currently unimplemented, which is OK. The data will just always
    209   // be around once it's mapped. Chrome's TransportDIB isn't currently
    210   // unmappable without freeing it, but this may be something we want to support
    211   // in the future to save some memory.
    212 }
    213 
    214 int32_t ImageDataPlatformBackend::GetSharedMemory(int* handle,
    215                                                   uint32_t* byte_count) {
    216   *byte_count = dib_->size();
    217 #if defined(OS_WIN)
    218   *handle = reinterpret_cast<intptr_t>(dib_->handle());
    219 #elif defined(TOOLKIT_GTK)
    220   *handle = static_cast<intptr_t>(dib_->handle());
    221 #else
    222   *handle = static_cast<intptr_t>(dib_->handle().fd);
    223 #endif
    224 
    225   return PP_OK;
    226 }
    227 
    228 skia::PlatformCanvas* ImageDataPlatformBackend::GetPlatformCanvas() {
    229   return mapped_canvas_.get();
    230 }
    231 
    232 SkCanvas* ImageDataPlatformBackend::GetCanvas() {
    233   return mapped_canvas_.get();
    234 }
    235 
    236 const SkBitmap* ImageDataPlatformBackend::GetMappedBitmap() const {
    237   if (!mapped_canvas_)
    238     return NULL;
    239   return &skia::GetTopDevice(*mapped_canvas_)->accessBitmap(false);
    240 }
    241 
    242 // ImageDataSimpleBackend ------------------------------------------------------
    243 
    244 ImageDataSimpleBackend::ImageDataSimpleBackend()
    245     : map_count_(0) {
    246 }
    247 
    248 ImageDataSimpleBackend::~ImageDataSimpleBackend() {
    249 }
    250 
    251 bool ImageDataSimpleBackend::Init(PPB_ImageData_Impl* impl,
    252                                   PP_ImageDataFormat format,
    253                                   int width, int height,
    254                                   bool init_to_zero) {
    255   skia_bitmap_.setConfig(SkBitmap::kARGB_8888_Config,
    256                          impl->width(), impl->height());
    257   shared_memory_.reset(RenderThread::Get()->HostAllocateSharedMemoryBuffer(
    258       skia_bitmap_.getSize()).release());
    259   return !!shared_memory_.get();
    260 }
    261 
    262 bool ImageDataSimpleBackend::IsMapped() const {
    263   return map_count_ > 0;
    264 }
    265 
    266 TransportDIB* ImageDataSimpleBackend::GetTransportDIB() const {
    267   return NULL;
    268 }
    269 
    270 void* ImageDataSimpleBackend::Map() {
    271   DCHECK(shared_memory_.get());
    272   if (map_count_++ == 0) {
    273     shared_memory_->Map(skia_bitmap_.getSize());
    274     skia_bitmap_.setPixels(shared_memory_->memory());
    275     // Our platform bitmaps are set to opaque by default, which we don't want.
    276     skia_bitmap_.setIsOpaque(false);
    277     skia_canvas_.reset(new SkCanvas(skia_bitmap_));
    278     return skia_bitmap_.getAddr32(0, 0);
    279   }
    280   return shared_memory_->memory();
    281 }
    282 
    283 void ImageDataSimpleBackend::Unmap() {
    284   if (--map_count_ == 0)
    285     shared_memory_->Unmap();
    286 }
    287 
    288 int32_t ImageDataSimpleBackend::GetSharedMemory(int* handle,
    289                                                 uint32_t* byte_count) {
    290   *byte_count = skia_bitmap_.getSize();
    291 #if defined(OS_POSIX)
    292   *handle = shared_memory_->handle().fd;
    293 #elif defined(OS_WIN)
    294   *handle = reinterpret_cast<int>(shared_memory_->handle());
    295 #else
    296 #error "Platform not supported."
    297 #endif
    298   return PP_OK;
    299 }
    300 
    301 skia::PlatformCanvas* ImageDataSimpleBackend::GetPlatformCanvas() {
    302   return NULL;
    303 }
    304 
    305 SkCanvas* ImageDataSimpleBackend::GetCanvas() {
    306   if (!IsMapped())
    307     return NULL;
    308   return skia_canvas_.get();
    309 }
    310 
    311 const SkBitmap* ImageDataSimpleBackend::GetMappedBitmap() const {
    312   if (!IsMapped())
    313     return NULL;
    314   return &skia_bitmap_;
    315 }
    316 
    317 }  // namespace content
    318