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 void RunV8GC(PP_Instance instance) { 131 // TODO(raymes): Implement this if we need it. 132 NOTIMPLEMENTED(); 133 } 134 135 const PPB_Testing_Private testing_interface = { 136 &ReadImageData, 137 &RunMessageLoop, 138 &QuitMessageLoop, 139 &GetLiveObjectsForInstance, 140 &IsOutOfProcess, 141 &SimulateInputEvent, 142 &GetDocumentURL, 143 &GetLiveVars, 144 &SetMinimumArrayBufferSizeForShmem, 145 &RunV8GC 146 }; 147 148 } // namespace 149 150 PPB_Testing_Proxy::PPB_Testing_Proxy(Dispatcher* dispatcher) 151 : InterfaceProxy(dispatcher), 152 ppb_testing_impl_(NULL) { 153 if (!dispatcher->IsPlugin()) { 154 ppb_testing_impl_ = static_cast<const PPB_Testing_Private*>( 155 dispatcher->local_get_interface()(PPB_TESTING_PRIVATE_INTERFACE)); 156 } 157 } 158 159 PPB_Testing_Proxy::~PPB_Testing_Proxy() { 160 } 161 162 // static 163 const PPB_Testing_Private* PPB_Testing_Proxy::GetProxyInterface() { 164 return &testing_interface; 165 } 166 167 bool PPB_Testing_Proxy::OnMessageReceived(const IPC::Message& msg) { 168 if (!dispatcher()->permissions().HasPermission(PERMISSION_TESTING)) 169 return false; 170 171 bool handled = true; 172 IPC_BEGIN_MESSAGE_MAP(PPB_Testing_Proxy, msg) 173 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBTesting_ReadImageData, 174 OnMsgReadImageData) 175 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBTesting_GetLiveObjectsForInstance, 176 OnMsgGetLiveObjectsForInstance) 177 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBTesting_SimulateInputEvent, 178 OnMsgSimulateInputEvent) 179 IPC_MESSAGE_HANDLER( 180 PpapiHostMsg_PPBTesting_SetMinimumArrayBufferSizeForShmem, 181 OnMsgSetMinimumArrayBufferSizeForShmem) 182 IPC_MESSAGE_UNHANDLED(handled = false) 183 IPC_END_MESSAGE_MAP() 184 return handled; 185 } 186 187 void PPB_Testing_Proxy::OnMsgReadImageData( 188 const HostResource& device_context_2d, 189 const HostResource& image, 190 const PP_Point& top_left, 191 PP_Bool* result) { 192 *result = ppb_testing_impl_->ReadImageData( 193 device_context_2d.host_resource(), image.host_resource(), &top_left); 194 } 195 196 void PPB_Testing_Proxy::OnMsgRunMessageLoop(PP_Instance instance) { 197 ppb_testing_impl_->RunMessageLoop(instance); 198 } 199 200 void PPB_Testing_Proxy::OnMsgQuitMessageLoop(PP_Instance instance) { 201 ppb_testing_impl_->QuitMessageLoop(instance); 202 } 203 204 void PPB_Testing_Proxy::OnMsgGetLiveObjectsForInstance(PP_Instance instance, 205 uint32_t* result) { 206 *result = ppb_testing_impl_->GetLiveObjectsForInstance(instance); 207 } 208 209 void PPB_Testing_Proxy::OnMsgSimulateInputEvent( 210 PP_Instance instance, 211 const InputEventData& input_event) { 212 scoped_refptr<PPB_InputEvent_Shared> input_event_impl( 213 new PPB_InputEvent_Shared(OBJECT_IS_PROXY, instance, input_event)); 214 ppb_testing_impl_->SimulateInputEvent(instance, 215 input_event_impl->pp_resource()); 216 } 217 218 void PPB_Testing_Proxy::OnMsgSetMinimumArrayBufferSizeForShmem( 219 uint32_t threshold) { 220 RawVarDataGraph::SetMinimumArrayBufferSizeForShmemForTest(threshold); 221 } 222 223 } // namespace proxy 224 } // namespace ppapi 225