ppp_instance_proxy.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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. 4 5#include "ppapi/proxy/ppp_instance_proxy.h" 6 7#include <algorithm> 8 9#include "base/bind.h" 10#include "ppapi/c/pp_var.h" 11#include "ppapi/c/ppb_core.h" 12#include "ppapi/c/ppb_fullscreen.h" 13#include "ppapi/c/ppp_instance.h" 14#include "ppapi/c/private/ppb_flash_fullscreen.h" 15#include "ppapi/proxy/host_dispatcher.h" 16#include "ppapi/proxy/plugin_dispatcher.h" 17#include "ppapi/proxy/plugin_resource_tracker.h" 18#include "ppapi/proxy/ppapi_messages.h" 19#include "ppapi/proxy/ppb_url_loader_proxy.h" 20#include "ppapi/shared_impl/ppapi_globals.h" 21#include "ppapi/shared_impl/ppb_view_shared.h" 22#include "ppapi/shared_impl/scoped_pp_resource.h" 23#include "ppapi/thunk/enter.h" 24#include "ppapi/thunk/ppb_view_api.h" 25 26namespace ppapi { 27namespace proxy { 28 29namespace { 30 31PP_Bool IsFlashFullscreen(PP_Instance instance, 32 HostDispatcher* dispatcher) { 33 const PPB_FlashFullscreen* flash_fullscreen_interface = 34 static_cast<const PPB_FlashFullscreen*>( 35 dispatcher->local_get_interface()(PPB_FLASHFULLSCREEN_INTERFACE)); 36 DCHECK(flash_fullscreen_interface); 37 return flash_fullscreen_interface->IsFullscreen(instance); 38} 39 40PP_Bool DidCreate(PP_Instance instance, 41 uint32_t argc, 42 const char* argn[], 43 const char* argv[]) { 44 std::vector<std::string> argn_vect; 45 std::vector<std::string> argv_vect; 46 for (uint32_t i = 0; i < argc; i++) { 47 argn_vect.push_back(std::string(argn[i])); 48 argv_vect.push_back(std::string(argv[i])); 49 } 50 51 PP_Bool result = PP_FALSE; 52 HostDispatcher::GetForInstance(instance)->Send( 53 new PpapiMsg_PPPInstance_DidCreate(API_ID_PPP_INSTANCE, instance, 54 argn_vect, argv_vect, &result)); 55 return result; 56} 57 58void DidDestroy(PP_Instance instance) { 59 HostDispatcher::GetForInstance(instance)->Send( 60 new PpapiMsg_PPPInstance_DidDestroy(API_ID_PPP_INSTANCE, instance)); 61} 62 63void DidChangeView(PP_Instance instance, PP_Resource view_resource) { 64 HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); 65 66 thunk::EnterResourceNoLock<thunk::PPB_View_API> enter(view_resource, false); 67 if (enter.failed()) { 68 NOTREACHED(); 69 return; 70 } 71 72 dispatcher->Send(new PpapiMsg_PPPInstance_DidChangeView( 73 API_ID_PPP_INSTANCE, instance, enter.object()->GetData(), 74 IsFlashFullscreen(instance, dispatcher))); 75} 76 77void DidChangeFocus(PP_Instance instance, PP_Bool has_focus) { 78 HostDispatcher::GetForInstance(instance)->Send( 79 new PpapiMsg_PPPInstance_DidChangeFocus(API_ID_PPP_INSTANCE, 80 instance, has_focus)); 81} 82 83PP_Bool HandleDocumentLoad(PP_Instance instance, 84 PP_Resource url_loader) { 85 PP_Bool result = PP_FALSE; 86 HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); 87 88 // Set up the URLLoader for proxying. 89 90 PPB_URLLoader_Proxy* url_loader_proxy = static_cast<PPB_URLLoader_Proxy*>( 91 dispatcher->GetInterfaceProxy(API_ID_PPB_URL_LOADER)); 92 url_loader_proxy->PrepareURLLoaderForSendingToPlugin(url_loader); 93 94 // PluginResourceTracker in the plugin process assumes that resources that it 95 // tracks have been addrefed on behalf of the plugin at the renderer side. So 96 // we explicitly do it for |url_loader| here. 97 // 98 // Please also see comments in PPP_Instance_Proxy::OnMsgHandleDocumentLoad() 99 // about releasing of this extra reference. 100 const PPB_Core* core = reinterpret_cast<const PPB_Core*>( 101 dispatcher->local_get_interface()(PPB_CORE_INTERFACE)); 102 if (!core) { 103 NOTREACHED(); 104 return PP_FALSE; 105 } 106 core->AddRefResource(url_loader); 107 108 HostResource serialized_loader; 109 serialized_loader.SetHostResource(instance, url_loader); 110 dispatcher->Send(new PpapiMsg_PPPInstance_HandleDocumentLoad( 111 API_ID_PPP_INSTANCE, instance, serialized_loader, &result)); 112 return result; 113} 114 115static const PPP_Instance_1_1 instance_interface = { 116 &DidCreate, 117 &DidDestroy, 118 &DidChangeView, 119 &DidChangeFocus, 120 &HandleDocumentLoad 121}; 122 123} // namespace 124 125PPP_Instance_Proxy::PPP_Instance_Proxy(Dispatcher* dispatcher) 126 : InterfaceProxy(dispatcher) { 127 if (dispatcher->IsPlugin()) { 128 // The PPP_Instance proxy works by always proxying the 1.1 version of the 129 // interface, and then detecting in the plugin process which one to use. 130 // PPP_Instance_Combined handles dispatching to whatever interface is 131 // supported. 132 // 133 // This means that if the plugin supports either 1.0 or 1.1 version of 134 // the interface, we want to say it supports the 1.1 version since we'll 135 // convert it here. This magic conversion code is hardcoded into 136 // PluginDispatcher::OnMsgSupportsInterface. 137 combined_interface_.reset(PPP_Instance_Combined::Create( 138 base::Bind(dispatcher->local_get_interface()))); 139 } 140} 141 142PPP_Instance_Proxy::~PPP_Instance_Proxy() { 143} 144 145// static 146const PPP_Instance* PPP_Instance_Proxy::GetInstanceInterface() { 147 return &instance_interface; 148} 149 150bool PPP_Instance_Proxy::OnMessageReceived(const IPC::Message& msg) { 151 bool handled = true; 152 IPC_BEGIN_MESSAGE_MAP(PPP_Instance_Proxy, msg) 153 IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidCreate, 154 OnPluginMsgDidCreate) 155 IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidDestroy, 156 OnPluginMsgDidDestroy) 157 IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidChangeView, 158 OnPluginMsgDidChangeView) 159 IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidChangeFocus, 160 OnPluginMsgDidChangeFocus) 161 IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_HandleDocumentLoad, 162 OnPluginMsgHandleDocumentLoad) 163 IPC_MESSAGE_UNHANDLED(handled = false) 164 IPC_END_MESSAGE_MAP() 165 return handled; 166} 167 168void PPP_Instance_Proxy::OnPluginMsgDidCreate( 169 PP_Instance instance, 170 const std::vector<std::string>& argn, 171 const std::vector<std::string>& argv, 172 PP_Bool* result) { 173 *result = PP_FALSE; 174 if (argn.size() != argv.size()) 175 return; 176 177 // Set up the routing associating this new instance with the dispatcher we 178 // just got the message from. This must be done before calling into the 179 // plugin so it can in turn call PPAPI functions. 180 PluginDispatcher* plugin_dispatcher = 181 static_cast<PluginDispatcher*>(dispatcher()); 182 plugin_dispatcher->DidCreateInstance(instance); 183 PpapiGlobals::Get()->GetResourceTracker()->DidCreateInstance(instance); 184 185 // Make sure the arrays always have at least one element so we can take the 186 // address below. 187 std::vector<const char*> argn_array( 188 std::max(static_cast<size_t>(1), argn.size())); 189 std::vector<const char*> argv_array( 190 std::max(static_cast<size_t>(1), argn.size())); 191 for (size_t i = 0; i < argn.size(); i++) { 192 argn_array[i] = argn[i].c_str(); 193 argv_array[i] = argv[i].c_str(); 194 } 195 196 DCHECK(combined_interface_.get()); 197 *result = combined_interface_->DidCreate(instance, 198 static_cast<uint32_t>(argn.size()), 199 &argn_array[0], &argv_array[0]); 200} 201 202void PPP_Instance_Proxy::OnPluginMsgDidDestroy(PP_Instance instance) { 203 combined_interface_->DidDestroy(instance); 204 205 PpapiGlobals* globals = PpapiGlobals::Get(); 206 globals->GetResourceTracker()->DidDeleteInstance(instance); 207 globals->GetVarTracker()->DidDeleteInstance(instance); 208 209 static_cast<PluginDispatcher*>(dispatcher())->DidDestroyInstance(instance); 210} 211 212void PPP_Instance_Proxy::OnPluginMsgDidChangeView( 213 PP_Instance instance, 214 const ViewData& new_data, 215 PP_Bool flash_fullscreen) { 216 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); 217 if (!dispatcher) 218 return; 219 InstanceData* data = dispatcher->GetInstanceData(instance); 220 if (!data) 221 return; 222 223 data->view = new_data; 224 data->flash_fullscreen = flash_fullscreen; 225 226 ScopedPPResource resource( 227 ScopedPPResource::PassRef(), 228 (new PPB_View_Shared(OBJECT_IS_PROXY, 229 instance, new_data))->GetReference()); 230 231 combined_interface_->DidChangeView(instance, resource, 232 &new_data.rect, 233 &new_data.clip_rect); 234} 235 236void PPP_Instance_Proxy::OnPluginMsgDidChangeFocus(PP_Instance instance, 237 PP_Bool has_focus) { 238 combined_interface_->DidChangeFocus(instance, has_focus); 239} 240 241void PPP_Instance_Proxy::OnPluginMsgHandleDocumentLoad( 242 PP_Instance instance, 243 const HostResource& url_loader, 244 PP_Bool* result) { 245 PP_Resource plugin_loader = 246 PPB_URLLoader_Proxy::TrackPluginResource(url_loader); 247 *result = combined_interface_->HandleDocumentLoad(instance, plugin_loader); 248 249 // This balances the one reference that TrackPluginResource() initialized it 250 // with. The plugin will normally take an additional reference which will keep 251 // the resource alive in the plugin (and the one reference in the renderer 252 // representing all plugin references). 253 // Once all references at the plugin side are released, the renderer side will 254 // be notified and release the reference added in HandleDocumentLoad() above. 255 PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(plugin_loader); 256} 257 258} // namespace proxy 259} // namespace ppapi 260