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/ppb_testing_proxy.h" 6 7 #include "base/message_loop/message_loop.h" 8 #include "ppapi/c/private/ppb_testing_private.h" 9 #include "ppapi/proxy/enter_proxy.h" 10 #include "ppapi/proxy/plugin_dispatcher.h" 11 #include "ppapi/proxy/ppapi_messages.h" 12 #include "ppapi/shared_impl/ppapi_globals.h" 13 #include "ppapi/shared_impl/proxy_lock.h" 14 #include "ppapi/shared_impl/resource.h" 15 #include "ppapi/shared_impl/resource_tracker.h" 16 #include "ppapi/thunk/enter.h" 17 #include "ppapi/thunk/ppb_graphics_2d_api.h" 18 #include "ppapi/thunk/ppb_input_event_api.h" 19 20 using ppapi::thunk::EnterInstance; 21 using ppapi::thunk::EnterResource; 22 using ppapi::thunk::EnterResourceNoLock; 23 using ppapi::thunk::PPB_Graphics2D_API; 24 using ppapi::thunk::PPB_InputEvent_API; 25 26 namespace ppapi { 27 namespace proxy { 28 29 namespace { 30 31 PP_Bool ReadImageData(PP_Resource graphics_2d, 32 PP_Resource image, 33 const PP_Point* top_left) { 34 ProxyAutoLock lock; 35 Resource* image_object = 36 PpapiGlobals::Get()->GetResourceTracker()->GetResource(image); 37 if (!image_object) 38 return PP_FALSE; 39 Resource* graphics_2d_object = 40 PpapiGlobals::Get()->GetResourceTracker()->GetResource(graphics_2d); 41 if (!graphics_2d_object || 42 image_object->pp_instance() != graphics_2d_object->pp_instance()) 43 return PP_FALSE; 44 45 EnterResourceNoLock<PPB_Graphics2D_API> enter(graphics_2d, true); 46 if (enter.failed()) 47 return PP_FALSE; 48 const HostResource& host_image = image_object->host_resource(); 49 return enter.object()->ReadImageData(host_image.host_resource(), top_left) ? 50 PP_TRUE : PP_FALSE; 51 } 52 53 void RunMessageLoop(PP_Instance instance) { 54 base::MessageLoop::ScopedNestableTaskAllower allow( 55 base::MessageLoop::current()); 56 CHECK(PpapiGlobals::Get()->GetMainThreadMessageLoop()-> 57 BelongsToCurrentThread()); 58 base::MessageLoop::current()->Run(); 59 } 60 61 void QuitMessageLoop(PP_Instance instance) { 62 CHECK(PpapiGlobals::Get()->GetMainThreadMessageLoop()-> 63 BelongsToCurrentThread()); 64 base::MessageLoop::current()->QuitNow(); 65 } 66 67 uint32_t GetLiveObjectsForInstance(PP_Instance instance_id) { 68 ProxyAutoLock lock; 69 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance_id); 70 if (!dispatcher) 71 return static_cast<uint32_t>(-1); 72 73 uint32_t result = 0; 74 dispatcher->Send(new PpapiHostMsg_PPBTesting_GetLiveObjectsForInstance( 75 API_ID_PPB_TESTING, instance_id, &result)); 76 return result; 77 } 78 79 PP_Bool IsOutOfProcess() { 80 return PP_TRUE; 81 } 82 83 void SimulateInputEvent(PP_Instance instance_id, PP_Resource input_event) { 84 ProxyAutoLock lock; 85 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance_id); 86 if (!dispatcher) 87 return; 88 EnterResourceNoLock<PPB_InputEvent_API> enter(input_event, false); 89 if (enter.failed()) 90 return; 91 92 const InputEventData& input_event_data = enter.object()->GetInputEventData(); 93 dispatcher->Send(new PpapiHostMsg_PPBTesting_SimulateInputEvent( 94 API_ID_PPB_TESTING, instance_id, input_event_data)); 95 } 96 97 PP_Var GetDocumentURL(PP_Instance instance, PP_URLComponents_Dev* components) { 98 EnterInstance enter(instance); 99 if (enter.failed()) 100 return PP_MakeUndefined(); 101 return enter.functions()->GetDocumentURL(instance, components); 102 } 103 104 // TODO(dmichael): Ideally we could get a way to check the number of vars in the 105 // host-side tracker when running out-of-process, to make sure the proxy does 106 // not leak host-side vars. 107 uint32_t GetLiveVars(PP_Var live_vars[], uint32_t array_size) { 108 ProxyAutoLock lock; 109 std::vector<PP_Var> vars = 110 PpapiGlobals::Get()->GetVarTracker()->GetLiveVars(); 111 for (size_t i = 0u; 112 i < std::min(static_cast<size_t>(array_size), vars.size()); 113 ++i) 114 live_vars[i] = vars[i]; 115 return vars.size(); 116 } 117 118 void SetMinimumArrayBufferSizeForShmem(PP_Instance instance, 119 uint32_t threshold) { 120 ProxyAutoLock lock; 121 RawVarDataGraph::SetMinimumArrayBufferSizeForShmemForTest(threshold); 122 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); 123 if (!dispatcher) 124 return; 125 dispatcher->Send( 126 new PpapiHostMsg_PPBTesting_SetMinimumArrayBufferSizeForShmem( 127 API_ID_PPB_TESTING, threshold)); 128 } 129 130 const PPB_Testing_Private testing_interface = { 131 &ReadImageData, 132 &RunMessageLoop, 133 &QuitMessageLoop, 134 &GetLiveObjectsForInstance, 135 &IsOutOfProcess, 136 &SimulateInputEvent, 137 &GetDocumentURL, 138 &GetLiveVars, 139 &SetMinimumArrayBufferSizeForShmem 140 }; 141 142 } // namespace 143 144 PPB_Testing_Proxy::PPB_Testing_Proxy(Dispatcher* dispatcher) 145 : InterfaceProxy(dispatcher), 146 ppb_testing_impl_(NULL) { 147 if (!dispatcher->IsPlugin()) { 148 ppb_testing_impl_ = static_cast<const PPB_Testing_Private*>( 149 dispatcher->local_get_interface()(PPB_TESTING_PRIVATE_INTERFACE)); 150 } 151 } 152 153 PPB_Testing_Proxy::~PPB_Testing_Proxy() { 154 } 155 156 // static 157 const PPB_Testing_Private* PPB_Testing_Proxy::GetProxyInterface() { 158 return &testing_interface; 159 } 160 161 bool PPB_Testing_Proxy::OnMessageReceived(const IPC::Message& msg) { 162 if (!dispatcher()->permissions().HasPermission(PERMISSION_TESTING)) 163 return false; 164 165 bool handled = true; 166 IPC_BEGIN_MESSAGE_MAP(PPB_Testing_Proxy, msg) 167 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBTesting_ReadImageData, 168 OnMsgReadImageData) 169 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBTesting_GetLiveObjectsForInstance, 170 OnMsgGetLiveObjectsForInstance) 171 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBTesting_SimulateInputEvent, 172 OnMsgSimulateInputEvent) 173 IPC_MESSAGE_HANDLER( 174 PpapiHostMsg_PPBTesting_SetMinimumArrayBufferSizeForShmem, 175 OnMsgSetMinimumArrayBufferSizeForShmem) 176 IPC_MESSAGE_UNHANDLED(handled = false) 177 IPC_END_MESSAGE_MAP() 178 return handled; 179 } 180 181 void PPB_Testing_Proxy::OnMsgReadImageData( 182 const HostResource& device_context_2d, 183 const HostResource& image, 184 const PP_Point& top_left, 185 PP_Bool* result) { 186 *result = ppb_testing_impl_->ReadImageData( 187 device_context_2d.host_resource(), image.host_resource(), &top_left); 188 } 189 190 void PPB_Testing_Proxy::OnMsgRunMessageLoop(PP_Instance instance) { 191 ppb_testing_impl_->RunMessageLoop(instance); 192 } 193 194 void PPB_Testing_Proxy::OnMsgQuitMessageLoop(PP_Instance instance) { 195 ppb_testing_impl_->QuitMessageLoop(instance); 196 } 197 198 void PPB_Testing_Proxy::OnMsgGetLiveObjectsForInstance(PP_Instance instance, 199 uint32_t* result) { 200 *result = ppb_testing_impl_->GetLiveObjectsForInstance(instance); 201 } 202 203 void PPB_Testing_Proxy::OnMsgSimulateInputEvent( 204 PP_Instance instance, 205 const InputEventData& input_event) { 206 scoped_refptr<PPB_InputEvent_Shared> input_event_impl( 207 new PPB_InputEvent_Shared(OBJECT_IS_PROXY, instance, input_event)); 208 ppb_testing_impl_->SimulateInputEvent(instance, 209 input_event_impl->pp_resource()); 210 } 211 212 void PPB_Testing_Proxy::OnMsgSetMinimumArrayBufferSizeForShmem( 213 uint32_t threshold) { 214 RawVarDataGraph::SetMinimumArrayBufferSizeForShmemForTest(threshold); 215 } 216 217 } // namespace proxy 218 } // namespace ppapi 219