blob: 1faae86a1ada77aa5ee07cb0c3ed8241d0b47cc2 [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_flash_proxy.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/time.h"
#include "ppapi/c/dev/ppb_font_dev.h"
#include "ppapi/c/dev/ppb_var_deprecated.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/pp_resource.h"
#include "ppapi/c/private/ppb_flash.h"
#include "ppapi/proxy/host_dispatcher.h"
#include "ppapi/proxy/plugin_dispatcher.h"
#include "ppapi/proxy/plugin_resource_tracker.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/proxy/proxy_module.h"
#include "ppapi/proxy/serialized_var.h"
#include "ppapi/shared_impl/resource.h"
#include "ppapi/shared_impl/scoped_pp_resource.h"
#include "ppapi/shared_impl/var.h"
#include "ppapi/thunk/enter.h"
#include "ppapi/thunk/ppb_url_request_info_api.h"
#include "ppapi/thunk/resource_creation_api.h"
namespace ppapi {
namespace proxy {
namespace {
void SetInstanceAlwaysOnTop(PP_Instance pp_instance, PP_Bool on_top) {
PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(pp_instance);
if (dispatcher) {
dispatcher->Send(new PpapiHostMsg_PPBFlash_SetInstanceAlwaysOnTop(
INTERFACE_ID_PPB_FLASH, pp_instance, on_top));
}
}
PP_Bool DrawGlyphs(PP_Instance instance,
PP_Resource pp_image_data,
const PP_FontDescription_Dev* font_desc,
uint32_t color,
PP_Point position,
PP_Rect clip,
const float transformation[3][3],
uint32_t glyph_count,
const uint16_t glyph_indices[],
const PP_Point glyph_advances[]) {
Resource* image_data = PluginResourceTracker::GetInstance()->GetResource(
pp_image_data);
if (!image_data)
return PP_FALSE;
// The instance parameter isn't strictly necessary but we check that it
// matches anyway.
if (image_data->pp_instance() != instance)
return PP_FALSE;
PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(
image_data->pp_instance());
if (!dispatcher)
return PP_FALSE;
PPBFlash_DrawGlyphs_Params params;
params.image_data = image_data->host_resource();
params.font_desc.SetFromPPFontDescription(dispatcher, *font_desc, true);
params.color = color;
params.position = position;
params.clip = clip;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++)
params.transformation[i][j] = transformation[i][j];
}
params.glyph_indices.insert(params.glyph_indices.begin(),
&glyph_indices[0],
&glyph_indices[glyph_count]);
params.glyph_advances.insert(params.glyph_advances.begin(),
&glyph_advances[0],
&glyph_advances[glyph_count]);
PP_Bool result = PP_FALSE;
dispatcher->Send(new PpapiHostMsg_PPBFlash_DrawGlyphs(
INTERFACE_ID_PPB_FLASH, params, &result));
return result;
}
PP_Var GetProxyForURL(PP_Instance instance, const char* url) {
PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
if (!dispatcher)
return PP_MakeUndefined();
ReceiveSerializedVarReturnValue result;
dispatcher->Send(new PpapiHostMsg_PPBFlash_GetProxyForURL(
INTERFACE_ID_PPB_FLASH, instance, url, &result));
return result.Return(dispatcher);
}
int32_t Navigate(PP_Resource request_id,
const char* target,
bool from_user_action) {
thunk::EnterResource<thunk::PPB_URLRequestInfo_API> enter(request_id, true);
if (enter.failed())
return PP_ERROR_BADRESOURCE;
PP_Instance instance = enter.resource()->pp_instance();
PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
if (!dispatcher)
return PP_ERROR_FAILED;
int32_t result = PP_ERROR_FAILED;
dispatcher->Send(new PpapiHostMsg_PPBFlash_Navigate(
INTERFACE_ID_PPB_FLASH,
instance, enter.object()->GetData(), target, from_user_action,
&result));
return result;
}
void RunMessageLoop(PP_Instance instance) {
PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
if (!dispatcher)
return;
IPC::SyncMessage* msg = new PpapiHostMsg_PPBFlash_RunMessageLoop(
INTERFACE_ID_PPB_FLASH, instance);
msg->EnableMessagePumping();
dispatcher->Send(msg);
}
void QuitMessageLoop(PP_Instance instance) {
PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
if (!dispatcher)
return;
dispatcher->Send(new PpapiHostMsg_PPBFlash_QuitMessageLoop(
INTERFACE_ID_PPB_FLASH, instance));
}
double GetLocalTimeZoneOffset(PP_Instance instance, PP_Time t) {
PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
if (!dispatcher)
return 0.0;
// TODO(brettw) on Windows it should be possible to do the time calculation
// in-process since it doesn't need to read files on disk. This will improve
// performance.
//
// On Linux, it would be better to go directly to the browser process for
// this message rather than proxy it through some instance in a renderer.
double result = 0;
dispatcher->Send(new PpapiHostMsg_PPBFlash_GetLocalTimeZoneOffset(
INTERFACE_ID_PPB_FLASH, instance, t, &result));
return result;
}
PP_Var GetCommandLineArgs(PP_Module pp_module) {
std::string args = ProxyModule::GetInstance()->GetFlashCommandLineArgs();
return StringVar::StringToPPVar(pp_module, args);
}
const PPB_Flash flash_interface = {
&SetInstanceAlwaysOnTop,
&DrawGlyphs,
&GetProxyForURL,
&Navigate,
&RunMessageLoop,
&QuitMessageLoop,
&GetLocalTimeZoneOffset,
&GetCommandLineArgs
};
InterfaceProxy* CreateFlashProxy(Dispatcher* dispatcher) {
return new PPB_Flash_Proxy(dispatcher);
}
} // namespace
PPB_Flash_Proxy::PPB_Flash_Proxy(Dispatcher* dispatcher)
: InterfaceProxy(dispatcher),
ppb_flash_impl_(NULL) {
if (!dispatcher->IsPlugin())
ppb_flash_impl_ = static_cast<const PPB_Flash*>(
dispatcher->local_get_interface()(PPB_FLASH_INTERFACE));
}
PPB_Flash_Proxy::~PPB_Flash_Proxy() {
}
// static
const InterfaceProxy::Info* PPB_Flash_Proxy::GetInfo() {
static const Info info = {
&flash_interface,
PPB_FLASH_INTERFACE,
INTERFACE_ID_PPB_FLASH,
true,
&CreateFlashProxy,
};
return &info;
}
bool PPB_Flash_Proxy::OnMessageReceived(const IPC::Message& msg) {
// Prevent the dispatcher from going away during a call to Navigate.
// This must happen OUTSIDE of OnMsgNavigate since the handling code use
// the dispatcher upon return of the function (sending the reply message).
ScopedModuleReference death_grip(dispatcher());
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(PPB_Flash_Proxy, msg)
IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_SetInstanceAlwaysOnTop,
OnMsgSetInstanceAlwaysOnTop)
IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_DrawGlyphs,
OnMsgDrawGlyphs)
IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_GetProxyForURL,
OnMsgGetProxyForURL)
IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_Navigate, OnMsgNavigate)
IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_RunMessageLoop,
OnMsgRunMessageLoop)
IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_QuitMessageLoop,
OnMsgQuitMessageLoop)
IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_GetLocalTimeZoneOffset,
OnMsgGetLocalTimeZoneOffset)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
// TODO(brettw) handle bad messages!
return handled;
}
void PPB_Flash_Proxy::OnMsgSetInstanceAlwaysOnTop(
PP_Instance instance,
PP_Bool on_top) {
ppb_flash_impl_->SetInstanceAlwaysOnTop(instance, on_top);
}
void PPB_Flash_Proxy::OnMsgDrawGlyphs(const PPBFlash_DrawGlyphs_Params& params,
PP_Bool* result) {
*result = PP_FALSE;
PP_FontDescription_Dev font_desc;
params.font_desc.SetToPPFontDescription(dispatcher(), &font_desc, false);
if (params.glyph_indices.size() != params.glyph_advances.size() ||
params.glyph_indices.empty())
return;
*result = ppb_flash_impl_->DrawGlyphs(
0, // Unused instance param.
params.image_data.host_resource(), &font_desc,
params.color, params.position, params.clip,
const_cast<float(*)[3]>(params.transformation),
static_cast<uint32_t>(params.glyph_indices.size()),
const_cast<uint16_t*>(&params.glyph_indices[0]),
const_cast<PP_Point*>(&params.glyph_advances[0]));
}
void PPB_Flash_Proxy::OnMsgGetProxyForURL(PP_Instance instance,
const std::string& url,
SerializedVarReturnValue result) {
result.Return(dispatcher(), ppb_flash_impl_->GetProxyForURL(
instance, url.c_str()));
}
void PPB_Flash_Proxy::OnMsgNavigate(PP_Instance instance,
const PPB_URLRequestInfo_Data& data,
const std::string& target,
bool from_user_action,
int32_t* result) {
DCHECK(!dispatcher()->IsPlugin());
// Validate the PP_Instance since we'll be constructing resources on its
// behalf.
HostDispatcher* host_dispatcher = static_cast<HostDispatcher*>(dispatcher());
if (HostDispatcher::GetForInstance(instance) != host_dispatcher) {
NOTREACHED();
*result = PP_ERROR_BADARGUMENT;
return;
}
// We need to allow re-entrancy here, because this may call into Javascript
// (e.g. with a "javascript:" URL), or do things like navigate away from the
// page, either one of which will need to re-enter into the plugin.
// It is safe, because it is essentially equivalent to NPN_GetURL, where Flash
// would expect re-entrancy. When running in-process, it does re-enter here.
host_dispatcher->set_allow_plugin_reentrancy();
// Make a temporary request resource.
thunk::EnterFunctionNoLock<thunk::ResourceCreationAPI> enter(instance, true);
if (enter.failed()) {
*result = PP_ERROR_FAILED;
return;
}
ScopedPPResource request_resource(
ScopedPPResource::PassRef(),
enter.functions()->CreateURLRequestInfo(instance, data));
*result = ppb_flash_impl_->Navigate(request_resource,
target.c_str(),
from_user_action);
}
void PPB_Flash_Proxy::OnMsgRunMessageLoop(PP_Instance instance) {
ppb_flash_impl_->RunMessageLoop(instance);
}
void PPB_Flash_Proxy::OnMsgQuitMessageLoop(PP_Instance instance) {
ppb_flash_impl_->QuitMessageLoop(instance);
}
void PPB_Flash_Proxy::OnMsgGetLocalTimeZoneOffset(PP_Instance instance,
PP_Time t,
double* result) {
*result = ppb_flash_impl_->GetLocalTimeZoneOffset(instance, t);
}
} // namespace proxy
} // namespace ppapi