blob: 18b4614433bd4788f616c60e756d2d0f328bff8f [file] [log] [blame]
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ppapi/proxy/ppb_image_data_proxy.h"
#include <string.h> // For memcpy
#include <vector>
#include "base/logging.h"
#include "build/build_config.h"
#include "ppapi/c/pp_completion_callback.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/pp_resource.h"
#include "ppapi/c/trusted/ppb_image_data_trusted.h"
#include "ppapi/proxy/host_resource.h"
#include "ppapi/proxy/plugin_dispatcher.h"
#include "ppapi/proxy/plugin_resource.h"
#include "ppapi/proxy/plugin_resource_tracker.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/shared_impl/image_data_impl.h"
#if defined(OS_LINUX)
#include <sys/shm.h>
#elif defined(OS_MACOSX)
#include <sys/stat.h>
#include <sys/mman.h>
#endif
namespace pp {
namespace proxy {
class ImageData : public PluginResource,
public pp::shared_impl::ImageDataImpl {
public:
ImageData(const HostResource& resource,
const PP_ImageDataDesc& desc,
ImageHandle handle);
virtual ~ImageData();
// Resource overrides.
virtual ImageData* AsImageData();
void* Map();
void Unmap();
const PP_ImageDataDesc& desc() const { return desc_; }
static const ImageHandle NullHandle;
static ImageHandle HandleFromInt(int32_t i);
private:
PP_ImageDataDesc desc_;
ImageHandle handle_;
void* mapped_data_;
DISALLOW_COPY_AND_ASSIGN(ImageData);
};
ImageData::ImageData(const HostResource& resource,
const PP_ImageDataDesc& desc,
ImageHandle handle)
: PluginResource(resource),
desc_(desc),
handle_(handle),
mapped_data_(NULL) {
}
ImageData::~ImageData() {
Unmap();
}
ImageData* ImageData::AsImageData() {
return this;
}
void* ImageData::Map() {
#if defined(OS_WIN)
NOTIMPLEMENTED();
return NULL;
#elif defined(OS_MACOSX)
struct stat st;
if (fstat(handle_.fd, &st) != 0)
return NULL;
void* memory = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE,
MAP_SHARED, handle_.fd, 0);
if (memory == MAP_FAILED)
return NULL;
mapped_data_ = memory;
return mapped_data_;
#else
int shmkey = handle_;
void* address = shmat(shmkey, NULL, 0);
// Mark for deletion in case we crash so the kernel will clean it up.
shmctl(shmkey, IPC_RMID, 0);
if (address == (void*)-1)
return NULL;
mapped_data_ = address;
return address;
#endif
}
void ImageData::Unmap() {
#if defined(OS_WIN)
NOTIMPLEMENTED();
#elif defined(OS_MACOSX)
if (mapped_data_) {
struct stat st;
if (fstat(handle_.fd, &st) == 0)
munmap(mapped_data_, st.st_size);
}
#else
if (mapped_data_)
shmdt(mapped_data_);
#endif
mapped_data_ = NULL;
}
#if defined(OS_WIN)
const ImageHandle ImageData::NullHandle = NULL;
#elif defined(OS_MACOSX)
const ImageHandle ImageData::NullHandle = ImageHandle();
#else
const ImageHandle ImageData::NullHandle = 0;
#endif
ImageHandle ImageData::HandleFromInt(int32_t i) {
#if defined(OS_WIN)
return reinterpret_cast<ImageHandle>(i);
#elif defined(OS_MACOSX)
return ImageHandle(i, false);
#else
return static_cast<ImageHandle>(i);
#endif
}
namespace {
PP_ImageDataFormat GetNativeImageDataFormat() {
return ImageData::GetNativeImageDataFormat();
}
PP_Bool IsImageDataFormatSupported(PP_ImageDataFormat format) {
return BoolToPPBool(ImageData::IsImageDataFormatSupported(format));
}
PP_Resource Create(PP_Instance instance,
PP_ImageDataFormat format,
const PP_Size* size,
PP_Bool init_to_zero) {
PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
if (!dispatcher)
return PP_ERROR_BADARGUMENT;
HostResource result;
std::string image_data_desc;
ImageHandle image_handle = ImageData::NullHandle;
dispatcher->Send(new PpapiHostMsg_PPBImageData_Create(
INTERFACE_ID_PPB_IMAGE_DATA, instance, format, *size, init_to_zero,
&result, &image_data_desc, &image_handle));
if (result.is_null() || image_data_desc.size() != sizeof(PP_ImageDataDesc))
return 0;
// We serialize the PP_ImageDataDesc just by copying to a string.
PP_ImageDataDesc desc;
memcpy(&desc, image_data_desc.data(), sizeof(PP_ImageDataDesc));
linked_ptr<ImageData> object(new ImageData(result, desc, image_handle));
return PluginResourceTracker::GetInstance()->AddResource(object);
}
PP_Bool IsImageData(PP_Resource resource) {
ImageData* object = PluginResource::GetAs<ImageData>(resource);
return BoolToPPBool(!!object);
}
PP_Bool Describe(PP_Resource resource, PP_ImageDataDesc* desc) {
ImageData* object = PluginResource::GetAs<ImageData>(resource);
if (!object)
return PP_FALSE;
memcpy(desc, &object->desc(), sizeof(PP_ImageDataDesc));
return PP_TRUE;
}
void* Map(PP_Resource resource) {
ImageData* object = PluginResource::GetAs<ImageData>(resource);
if (!object)
return NULL;
return object->Map();
}
void Unmap(PP_Resource resource) {
ImageData* object = PluginResource::GetAs<ImageData>(resource);
if (object)
object->Unmap();
}
const PPB_ImageData ppb_imagedata = {
&GetNativeImageDataFormat,
&IsImageDataFormatSupported,
&Create,
&IsImageData,
&Describe,
&Map,
&Unmap,
};
} // namespace
PPB_ImageData_Proxy::PPB_ImageData_Proxy(Dispatcher* dispatcher,
const void* target_interface)
: InterfaceProxy(dispatcher, target_interface) {
}
PPB_ImageData_Proxy::~PPB_ImageData_Proxy() {
}
const void* PPB_ImageData_Proxy::GetSourceInterface() const {
return &ppb_imagedata;
}
InterfaceID PPB_ImageData_Proxy::GetInterfaceId() const {
return INTERFACE_ID_PPB_IMAGE_DATA;
}
bool PPB_ImageData_Proxy::OnMessageReceived(const IPC::Message& msg) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(PPB_ImageData_Proxy, msg)
IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBImageData_Create, OnMsgCreate)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
// FIXME(brettw) handle bad messages!
return handled;
}
void PPB_ImageData_Proxy::OnMsgCreate(PP_Instance instance,
int32_t format,
const PP_Size& size,
PP_Bool init_to_zero,
HostResource* result,
std::string* image_data_desc,
ImageHandle* result_image_handle) {
PP_Resource resource = ppb_image_data_target()->Create(
instance, static_cast<PP_ImageDataFormat>(format), &size, init_to_zero);
*result_image_handle = ImageData::NullHandle;
if (resource) {
// The ImageDesc is just serialized as a string.
PP_ImageDataDesc desc;
if (ppb_image_data_target()->Describe(resource, &desc)) {
image_data_desc->resize(sizeof(PP_ImageDataDesc));
memcpy(&(*image_data_desc)[0], &desc, sizeof(PP_ImageDataDesc));
}
// Get the shared memory handle.
const PPB_ImageDataTrusted* trusted =
reinterpret_cast<const PPB_ImageDataTrusted*>(
dispatcher()->GetLocalInterface(PPB_IMAGEDATA_TRUSTED_INTERFACE));
uint32_t byte_count = 0;
if (trusted) {
int32_t handle;
if (trusted->GetSharedMemory(resource, &handle, &byte_count) == PP_OK)
*result_image_handle = ImageData::HandleFromInt(handle);
}
result->SetHostResource(instance, resource);
}
}
} // namespace proxy
} // namespace pp