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