Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / renderer / pepper / ppb_image_data_impl.cc
blob28f23c99c7173f8a7740ed699190f06f942dda59
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.
5 #include "content/renderer/pepper/ppb_image_data_impl.h"
7 #include <algorithm>
8 #include <limits>
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "content/common/view_messages.h"
13 #include "content/renderer/render_thread_impl.h"
14 #include "ppapi/c/pp_errors.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 "skia/ext/platform_canvas.h"
20 #include "third_party/skia/include/core/SkColorPriv.h"
21 #include "ui/surface/transport_dib.h"
23 using ppapi::thunk::PPB_ImageData_API;
25 namespace content {
27 namespace {
28 // Returns true if the ImageData shared memory should be allocated in the
29 // browser process for the current platform.
30 bool IsBrowserAllocated() {
31 #if defined(OS_POSIX) && !defined(OS_ANDROID)
32 // On the Mac, shared memory has to be created in the browser in order to
33 // work in the sandbox.
34 return true;
35 #endif
36 return false;
38 } // namespace
40 PPB_ImageData_Impl::PPB_ImageData_Impl(PP_Instance instance,
41 PPB_ImageData_Shared::ImageDataType type)
42 : Resource(ppapi::OBJECT_IS_IMPL, instance),
43 format_(PP_IMAGEDATAFORMAT_BGRA_PREMUL),
44 width_(0),
45 height_(0) {
46 switch (type) {
47 case PPB_ImageData_Shared::PLATFORM:
48 backend_.reset(new ImageDataPlatformBackend(IsBrowserAllocated()));
49 return;
50 case PPB_ImageData_Shared::SIMPLE:
51 backend_.reset(new ImageDataSimpleBackend);
52 return;
53 // No default: so that we get a compiler warning if any types are added.
55 NOTREACHED();
58 PPB_ImageData_Impl::PPB_ImageData_Impl(PP_Instance instance, ForTest)
59 : Resource(ppapi::OBJECT_IS_IMPL, instance),
60 format_(PP_IMAGEDATAFORMAT_BGRA_PREMUL),
61 width_(0),
62 height_(0) {
63 backend_.reset(new ImageDataPlatformBackend(false));
66 PPB_ImageData_Impl::~PPB_ImageData_Impl() {}
68 bool PPB_ImageData_Impl::Init(PP_ImageDataFormat format,
69 int width,
70 int height,
71 bool init_to_zero) {
72 // TODO(brettw) this should be called only on the main thread!
73 if (!IsImageDataFormatSupported(format))
74 return false; // Only support this one format for now.
75 if (width <= 0 || height <= 0)
76 return false;
77 if (static_cast<int64>(width) * static_cast<int64>(height) >=
78 std::numeric_limits<int32>::max() / 4)
79 return false; // Prevent overflow of signed 32-bit ints.
81 format_ = format;
82 width_ = width;
83 height_ = height;
84 return backend_->Init(this, format, width, height, init_to_zero);
87 // static
88 PP_Resource PPB_ImageData_Impl::Create(PP_Instance instance,
89 PPB_ImageData_Shared::ImageDataType type,
90 PP_ImageDataFormat format,
91 const PP_Size& size,
92 PP_Bool init_to_zero) {
93 scoped_refptr<PPB_ImageData_Impl> data(
94 new PPB_ImageData_Impl(instance, type));
95 if (!data->Init(format, size.width, size.height, !!init_to_zero))
96 return 0;
97 return data->GetReference();
100 PPB_ImageData_API* PPB_ImageData_Impl::AsPPB_ImageData_API() { return this; }
102 bool PPB_ImageData_Impl::IsMapped() const { return backend_->IsMapped(); }
104 TransportDIB* PPB_ImageData_Impl::GetTransportDIB() const {
105 return backend_->GetTransportDIB();
108 PP_Bool PPB_ImageData_Impl::Describe(PP_ImageDataDesc* desc) {
109 desc->format = format_;
110 desc->size.width = width_;
111 desc->size.height = height_;
112 desc->stride = width_ * 4;
113 return PP_TRUE;
116 void* PPB_ImageData_Impl::Map() { return backend_->Map(); }
118 void PPB_ImageData_Impl::Unmap() { backend_->Unmap(); }
120 int32_t PPB_ImageData_Impl::GetSharedMemory(int* handle, uint32_t* byte_count) {
121 return backend_->GetSharedMemory(handle, byte_count);
124 skia::PlatformCanvas* PPB_ImageData_Impl::GetPlatformCanvas() {
125 return backend_->GetPlatformCanvas();
128 SkCanvas* PPB_ImageData_Impl::GetCanvas() { return backend_->GetCanvas(); }
130 void PPB_ImageData_Impl::SetIsCandidateForReuse() {
131 // Nothing to do since we don't support image data re-use in-process.
134 const SkBitmap* PPB_ImageData_Impl::GetMappedBitmap() const {
135 return backend_->GetMappedBitmap();
138 // ImageDataPlatformBackend ----------------------------------------------------
140 ImageDataPlatformBackend::ImageDataPlatformBackend(bool is_browser_allocated)
141 : width_(0), height_(0), is_browser_allocated_(is_browser_allocated) {}
143 // On POSIX, we have to tell the browser to free the transport DIB.
144 ImageDataPlatformBackend::~ImageDataPlatformBackend() {
145 if (is_browser_allocated_) {
146 #if defined(OS_POSIX)
147 if (dib_) {
148 RenderThreadImpl::current()->Send(
149 new ViewHostMsg_FreeTransportDIB(dib_->id()));
151 #endif
155 bool ImageDataPlatformBackend::Init(PPB_ImageData_Impl* impl,
156 PP_ImageDataFormat format,
157 int width,
158 int height,
159 bool init_to_zero) {
160 // TODO(brettw) use init_to_zero when we implement caching.
161 width_ = width;
162 height_ = height;
163 uint32 buffer_size = width_ * height_ * 4;
165 // Allocate the transport DIB and the PlatformCanvas pointing to it.
166 TransportDIB* dib = NULL;
167 if (is_browser_allocated_) {
168 #if defined(OS_POSIX)
169 // Allocate the image data by sending a message to the browser requesting a
170 // TransportDIB (see also chrome/renderer/webplugin_delegate_proxy.cc,
171 // method WebPluginDelegateProxy::CreateBitmap() for similar code). The
172 // TransportDIB is cached in the browser, and is freed (in typical cases) by
173 // the TransportDIB's destructor.
174 TransportDIB::Handle dib_handle;
175 IPC::Message* msg =
176 new ViewHostMsg_AllocTransportDIB(buffer_size, true, &dib_handle);
177 if (!RenderThreadImpl::current()->Send(msg))
178 return false;
179 if (!TransportDIB::is_valid_handle(dib_handle))
180 return false;
182 dib = TransportDIB::CreateWithHandle(dib_handle);
183 #endif
184 } else {
185 static int next_dib_id = 0;
186 dib = TransportDIB::Create(buffer_size, next_dib_id++);
187 if (!dib)
188 return false;
190 DCHECK(dib);
191 dib_.reset(dib);
192 return true;
195 bool ImageDataPlatformBackend::IsMapped() const {
196 return !!mapped_canvas_.get();
199 TransportDIB* ImageDataPlatformBackend::GetTransportDIB() const {
200 return dib_.get();
203 void* ImageDataPlatformBackend::Map() {
204 if (!mapped_canvas_) {
205 mapped_canvas_.reset(dib_->GetPlatformCanvas(width_, height_));
206 if (!mapped_canvas_)
207 return NULL;
209 const SkBitmap& bitmap =
210 skia::GetTopDevice(*mapped_canvas_)->accessBitmap(true);
212 // Our platform bitmaps are set to opaque by default, which we don't want.
213 const_cast<SkBitmap&>(bitmap).setAlphaType(kPremul_SkAlphaType);
215 bitmap.lockPixels();
216 return bitmap.getAddr32(0, 0);
219 void ImageDataPlatformBackend::Unmap() {
220 // This is currently unimplemented, which is OK. The data will just always
221 // be around once it's mapped. Chrome's TransportDIB isn't currently
222 // unmappable without freeing it, but this may be something we want to support
223 // in the future to save some memory.
226 int32_t ImageDataPlatformBackend::GetSharedMemory(int* handle,
227 uint32_t* byte_count) {
228 *byte_count = dib_->size();
229 #if defined(OS_WIN)
230 *handle = reinterpret_cast<intptr_t>(dib_->handle());
231 #else
232 *handle = static_cast<intptr_t>(dib_->handle().fd);
233 #endif
235 return PP_OK;
238 skia::PlatformCanvas* ImageDataPlatformBackend::GetPlatformCanvas() {
239 return mapped_canvas_.get();
242 SkCanvas* ImageDataPlatformBackend::GetCanvas() { return mapped_canvas_.get(); }
244 const SkBitmap* ImageDataPlatformBackend::GetMappedBitmap() const {
245 if (!mapped_canvas_)
246 return NULL;
247 return &skia::GetTopDevice(*mapped_canvas_)->accessBitmap(false);
250 // ImageDataSimpleBackend ------------------------------------------------------
252 ImageDataSimpleBackend::ImageDataSimpleBackend() : map_count_(0) {}
254 ImageDataSimpleBackend::~ImageDataSimpleBackend() {}
256 bool ImageDataSimpleBackend::Init(PPB_ImageData_Impl* impl,
257 PP_ImageDataFormat format,
258 int width,
259 int height,
260 bool init_to_zero) {
261 skia_bitmap_.setInfo(
262 SkImageInfo::MakeN32Premul(impl->width(), impl->height()));
263 shared_memory_.reset(
264 RenderThread::Get()
265 ->HostAllocateSharedMemoryBuffer(skia_bitmap_.getSize())
266 .release());
267 return !!shared_memory_.get();
270 bool ImageDataSimpleBackend::IsMapped() const { return map_count_ > 0; }
272 TransportDIB* ImageDataSimpleBackend::GetTransportDIB() const { return NULL; }
274 void* ImageDataSimpleBackend::Map() {
275 DCHECK(shared_memory_.get());
276 if (map_count_++ == 0) {
277 shared_memory_->Map(skia_bitmap_.getSize());
278 skia_bitmap_.setPixels(shared_memory_->memory());
279 // Our platform bitmaps are set to opaque by default, which we don't want.
280 skia_bitmap_.setAlphaType(kPremul_SkAlphaType);
281 skia_canvas_.reset(new SkCanvas(skia_bitmap_));
282 return skia_bitmap_.getAddr32(0, 0);
284 return shared_memory_->memory();
287 void ImageDataSimpleBackend::Unmap() {
288 if (--map_count_ == 0)
289 shared_memory_->Unmap();
292 int32_t ImageDataSimpleBackend::GetSharedMemory(int* handle,
293 uint32_t* byte_count) {
294 *byte_count = skia_bitmap_.getSize();
295 #if defined(OS_POSIX)
296 *handle = shared_memory_->handle().fd;
297 #elif defined(OS_WIN)
298 *handle = reinterpret_cast<int>(shared_memory_->handle());
299 #else
300 #error "Platform not supported."
301 #endif
302 return PP_OK;
305 skia::PlatformCanvas* ImageDataSimpleBackend::GetPlatformCanvas() {
306 return NULL;
309 SkCanvas* ImageDataSimpleBackend::GetCanvas() {
310 if (!IsMapped())
311 return NULL;
312 return skia_canvas_.get();
315 const SkBitmap* ImageDataSimpleBackend::GetMappedBitmap() const {
316 if (!IsMapped())
317 return NULL;
318 return &skia_bitmap_;
321 } // namespace content