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