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