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"
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
;
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.
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
),
47 case PPB_ImageData_Shared::PLATFORM
:
48 backend_
.reset(new ImageDataPlatformBackend(IsBrowserAllocated()));
50 case PPB_ImageData_Shared::SIMPLE
:
51 backend_
.reset(new ImageDataSimpleBackend
);
53 // No default: so that we get a compiler warning if any types are added.
58 PPB_ImageData_Impl::PPB_ImageData_Impl(PP_Instance instance
, ForTest
)
59 : Resource(ppapi::OBJECT_IS_IMPL
, instance
),
60 format_(PP_IMAGEDATAFORMAT_BGRA_PREMUL
),
63 backend_
.reset(new ImageDataPlatformBackend(false));
66 PPB_ImageData_Impl::~PPB_ImageData_Impl() {}
68 bool PPB_ImageData_Impl::Init(PP_ImageDataFormat format
,
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)
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.
84 return backend_
->Init(this, format
, width
, height
, init_to_zero
);
88 PP_Resource
PPB_ImageData_Impl::Create(PP_Instance instance
,
89 PPB_ImageData_Shared::ImageDataType type
,
90 PP_ImageDataFormat format
,
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
))
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;
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)
148 RenderThreadImpl::current()->Send(
149 new ViewHostMsg_FreeTransportDIB(dib_
->id()));
155 bool ImageDataPlatformBackend::Init(PPB_ImageData_Impl
* impl
,
156 PP_ImageDataFormat format
,
160 // TODO(brettw) use init_to_zero when we implement caching.
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
;
176 new ViewHostMsg_AllocTransportDIB(buffer_size
, true, &dib_handle
);
177 if (!RenderThreadImpl::current()->Send(msg
))
179 if (!TransportDIB::is_valid_handle(dib_handle
))
182 dib
= TransportDIB::CreateWithHandle(dib_handle
);
185 static int next_dib_id
= 0;
186 dib
= TransportDIB::Create(buffer_size
, next_dib_id
++);
195 bool ImageDataPlatformBackend::IsMapped() const {
196 return !!mapped_canvas_
.get();
199 TransportDIB
* ImageDataPlatformBackend::GetTransportDIB() const {
203 void* ImageDataPlatformBackend::Map() {
204 if (!mapped_canvas_
) {
205 mapped_canvas_
.reset(dib_
->GetPlatformCanvas(width_
, height_
));
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
);
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();
230 *handle
= reinterpret_cast<intptr_t>(dib_
->handle());
232 *handle
= static_cast<intptr_t>(dib_
->handle().fd
);
238 skia::PlatformCanvas
* ImageDataPlatformBackend::GetPlatformCanvas() {
239 return mapped_canvas_
.get();
242 SkCanvas
* ImageDataPlatformBackend::GetCanvas() { return mapped_canvas_
.get(); }
244 const SkBitmap
* ImageDataPlatformBackend::GetMappedBitmap() const {
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
,
261 skia_bitmap_
.setInfo(
262 SkImageInfo::MakeN32Premul(impl
->width(), impl
->height()));
263 shared_memory_
.reset(
265 ->HostAllocateSharedMemoryBuffer(skia_bitmap_
.getSize())
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());
300 #error "Platform not supported."
305 skia::PlatformCanvas
* ImageDataSimpleBackend::GetPlatformCanvas() {
309 SkCanvas
* ImageDataSimpleBackend::GetCanvas() {
312 return skia_canvas_
.get();
315 const SkBitmap
* ImageDataSimpleBackend::GetMappedBitmap() const {
318 return &skia_bitmap_
;
321 } // namespace content