// Copyright (c) 2012 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/graphics_2d_resource.h"
#include "ppapi/c/pp_bool.h"
#include "ppapi/c/pp_point.h"
#include "ppapi/c/pp_rect.h"
#include "ppapi/c/pp_resource.h"
#include "ppapi/c/pp_size.h"
#include "ppapi/c/ppb_graphics_2d.h"
#include "ppapi/proxy/dispatch_reply_message.h"
#include "ppapi/proxy/plugin_dispatcher.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/shared_impl/ppapi_globals.h"
#include "ppapi/shared_impl/resource_tracker.h"
#include "ppapi/shared_impl/tracked_callback.h"
#include "ppapi/thunk/enter.h"
#include "ppapi/thunk/ppb_image_data_api.h"
namespace ppapi {
namespace proxy {
Graphics2DResource::Graphics2DResource(Connection connection,
PP_Instance instance,
const PP_Size& size,
PP_Bool is_always_opaque)
: PluginResource(connection, instance),
size_(size),
is_always_opaque_(is_always_opaque),
scale_(1.0f) {
// These checks are copied from PPB_ImageData_Impl::Init to make tests passed.
// Let's remove/refactor this when start to refactor ImageData.
bool bad_args = size.width <= 0 || size.height <= 0 ||
static_cast<int64>(size.width) * static_cast<int64>(size.height) >=
std::numeric_limits<int32>::max() / 4;
if (!bad_args && !sent_create_to_renderer()) {
SendCreate(RENDERER,
PpapiHostMsg_Graphics2D_Create(size, is_always_opaque));
}
}
Graphics2DResource::~Graphics2DResource() {
}
PP_Bool Graphics2DResource::Describe(PP_Size* size, PP_Bool* is_always_opaque) {
*size = size_;
*is_always_opaque = is_always_opaque_;
return PP_TRUE;
}
thunk::PPB_Graphics2D_API* Graphics2DResource::AsPPB_Graphics2D_API() {
return this;
}
void Graphics2DResource::PaintImageData(PP_Resource image_data,
const PP_Point* top_left,
const PP_Rect* src_rect) {
Resource* image_object =
PpapiGlobals::Get()->GetResourceTracker()->GetResource(image_data);
if (!image_object || pp_instance() != image_object->pp_instance()) {
Log(PP_LOGLEVEL_ERROR,
"Graphics2DResource.PaintImageData: Bad image resource.");
return;
}
PP_Rect dummy;
memset(&dummy, 0, sizeof(PP_Rect));
Post(RENDERER, PpapiHostMsg_Graphics2D_PaintImageData(
image_object->host_resource(), *top_left,
!!src_rect, src_rect ? *src_rect : dummy));
}
void Graphics2DResource::Scroll(const PP_Rect* clip_rect,
const PP_Point* amount) {
PP_Rect dummy;
memset(&dummy, 0, sizeof(PP_Rect));
Post(RENDERER, PpapiHostMsg_Graphics2D_Scroll(
!!clip_rect, clip_rect ? *clip_rect : dummy, *amount));
}
void Graphics2DResource::ReplaceContents(PP_Resource image_data) {
thunk::EnterResourceNoLock<thunk::PPB_ImageData_API> enter_image(
image_data, true);
if (enter_image.failed())
return;
// Check that the PP_Instance matches.
Resource* image_object =
PpapiGlobals::Get()->GetResourceTracker()->GetResource(image_data);
if (!image_object || pp_instance() != image_object->pp_instance()) {
Log(PP_LOGLEVEL_ERROR,
"Graphics2DResource.PaintImageData: Bad image resource.");
return;
}
enter_image.object()->SetIsCandidateForReuse();
Post(RENDERER, PpapiHostMsg_Graphics2D_ReplaceContents(
image_object->host_resource()));
}
PP_Bool Graphics2DResource::SetScale(float scale) {
if (scale <= 0.0f)
return PP_FALSE;
Post(RENDERER, PpapiHostMsg_Graphics2D_Dev_SetScale(scale));
scale_ = scale;
return PP_TRUE;
}
float Graphics2DResource::GetScale() {
return scale_;
}
void Graphics2DResource::SetOffset(const PP_Point* offset) {
Post(RENDERER, PpapiHostMsg_Graphics2D_SetOffset(*offset));
}
void Graphics2DResource::SetResizeMode(
PP_Graphics2D_Dev_ResizeMode resize_mode) {
Post(RENDERER, PpapiHostMsg_Graphics2D_SetResizeMode(resize_mode));
}
int32_t Graphics2DResource::Flush(scoped_refptr<TrackedCallback> callback) {
// If host is not even created, return failure immediately. This can happen
// when failed to initialize (in constructor).
if (!sent_create_to_renderer())
return PP_ERROR_FAILED;
if (TrackedCallback::IsPending(current_flush_callback_))
return PP_ERROR_INPROGRESS; // Can't have >1 flush pending.
current_flush_callback_ = callback;
// Send the current view data with the Flush() message. This allows the
// renderer to know what the plugin's view of the renderer is at the time
// Flush was called.
PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(
pp_instance());
ppapi::ViewData view_data;
if (dispatcher) {
InstanceData* data = dispatcher->GetInstanceData(pp_instance());
if (data)
view_data = data->view;
}
Call<PpapiPluginMsg_Graphics2D_FlushAck>(
RENDERER,
PpapiHostMsg_Graphics2D_Flush(view_data),
base::Bind(&Graphics2DResource::OnPluginMsgFlushACK, this));
return PP_OK_COMPLETIONPENDING;
}
bool Graphics2DResource::ReadImageData(PP_Resource image,
const PP_Point* top_left) {
if (!top_left)
return false;
int32_t result = SyncCall<PpapiPluginMsg_Graphics2D_ReadImageDataAck>(
RENDERER,
PpapiHostMsg_Graphics2D_ReadImageData(image, *top_left));
return result == PP_OK;
}
void Graphics2DResource::OnPluginMsgFlushACK(
const ResourceMessageReplyParams& params) {
current_flush_callback_->Run(params.result());
}
} // namespace proxy
} // namespace ppapi