OLD | NEW |
(Empty) | |
| 1 // Use of this source code is governed by a BSD-style license that can be |
| 2 // found in the LICENSE file. |
| 3 |
| 4 #include "content/renderer/browser_plugin/guest_to_embedder_channel.h" |
| 5 |
| 6 #include "base/process_util.h" |
| 7 #include "content/common/browser_plugin_messages.h" |
| 8 #include "content/common/child_process.h" |
| 9 #include "content/renderer/browser_plugin/browser_plugin_channel_manager.h" |
| 10 #include "content/renderer/browser_plugin/browser_plugin_var_serialization_rules
.h" |
| 11 #include "content/renderer/render_thread_impl.h" |
| 12 #include "content/renderer/render_view_impl.h" |
| 13 #include "ppapi/c/pp_bool.h" |
| 14 #include "ppapi/c/pp_graphics_3d.h" |
| 15 #include "ppapi/proxy/ppapi_command_buffer_proxy.h" |
| 16 #include "ppapi/proxy/ppapi_messages.h" |
| 17 #include "ppapi/shared_impl/api_id.h" |
| 18 #include "ppapi/shared_impl/ppapi_globals.h" |
| 19 #include "ppapi/shared_impl/var.h" |
| 20 #include "webkit/plugins/ppapi/event_conversion.h" |
| 21 |
| 22 namespace content { |
| 23 |
| 24 GuestToEmbedderChannel::GuestToEmbedderChannel( |
| 25 const std::string& embedder_channel_name) |
| 26 : Dispatcher(NULL), |
| 27 embedder_channel_name_(embedder_channel_name) { |
| 28 SetSerializationRules(new BrowserPluginVarSerializationRules()); |
| 29 } |
| 30 |
| 31 bool GuestToEmbedderChannel::OnMessageReceived(const IPC::Message& message) { |
| 32 bool handled = true; |
| 33 IPC_BEGIN_MESSAGE_MAP(GuestToEmbedderChannel, message) |
| 34 IPC_MESSAGE_HANDLER(PpapiMsg_SupportsInterface, OnSupportsInterface) |
| 35 IPC_MESSAGE_HANDLER(PpapiMsg_SetPreferences, OnSetPreferences) |
| 36 IPC_MESSAGE_HANDLER(PpapiMsg_ReserveInstanceId, OnReserveInstanceId) |
| 37 IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidCreate, |
| 38 OnDidCreate) |
| 39 IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidDestroy, |
| 40 OnDidDestroy) |
| 41 IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidChangeView, |
| 42 OnDidChangeView) |
| 43 IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidChangeFocus, |
| 44 OnDidChangeFocus) |
| 45 IPC_MESSAGE_HANDLER(PpapiMsg_PPPMessaging_HandleMessage, |
| 46 OnHandleMessage) |
| 47 IPC_MESSAGE_HANDLER(PpapiMsg_PPPInputEvent_HandleFilteredInputEvent, |
| 48 OnHandleFilteredInputEvent) |
| 49 IPC_MESSAGE_HANDLER(PpapiMsg_PPPGraphics3D_ContextLost, |
| 50 OnContextLost) |
| 51 // Have the super handle all other messages. |
| 52 IPC_MESSAGE_UNHANDLED(handled = false) |
| 53 IPC_END_MESSAGE_MAP() |
| 54 |
| 55 return handled; |
| 56 } |
| 57 |
| 58 bool GuestToEmbedderChannel::Send(IPC::Message* message) { |
| 59 // We always want guest->host messages to arrive in-order. If some sync |
| 60 // and some async messages are sent in response to a synchronous |
| 61 // host->guest call, the sync reply will be processed before the async |
| 62 // reply, and everything will be confused. |
| 63 // |
| 64 // Allowing all async messages to unblock the renderer means more reentrancy |
| 65 // there but gives correct ordering. |
| 66 message->set_unblock(true); |
| 67 return ProxyChannel::Send(message); |
| 68 } |
| 69 |
| 70 void GuestToEmbedderChannel::OnChannelError() { |
| 71 // We cannot destroy the GuestToEmbedderChannel here because a |
| 72 // PpapiCommandBufferProxy may still refer to this object. |
| 73 // However, we should not be using this channel again once we get a |
| 74 // channel error so we remove it from the channel manager. |
| 75 RenderThreadImpl::current()->browser_plugin_channel_manager()-> |
| 76 RemoveChannelByName(embedder_channel_name_); |
| 77 } |
| 78 |
| 79 bool GuestToEmbedderChannel::IsPlugin() const { |
| 80 return true; |
| 81 } |
| 82 |
| 83 WebGraphicsContext3DCommandBufferImpl* |
| 84 GuestToEmbedderChannel::CreateWebGraphicsContext3D( |
| 85 RenderViewImpl* render_view, |
| 86 const WebKit::WebGraphicsContext3D::Attributes& attributes, |
| 87 bool offscreen) { |
| 88 scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context( |
| 89 new WebGraphicsContext3DCommandBufferImpl( |
| 90 0, GURL(), NULL, |
| 91 render_view->AsWeakPtr())); |
| 92 |
| 93 // Special case: RenderView initialization has not yet completed. |
| 94 if (!render_view->guest_pp_instance()) |
| 95 return context.release(); |
| 96 |
| 97 if (CreateGraphicsContext(context.get(), |
| 98 attributes, |
| 99 offscreen, |
| 100 render_view)) |
| 101 return context.release(); |
| 102 |
| 103 return NULL; |
| 104 } |
| 105 |
| 106 void GuestToEmbedderChannel::IssueSwapBuffers( |
| 107 const ppapi::HostResource& resource) { |
| 108 Send(new PpapiHostMsg_PPBGraphics3D_SwapBuffers( |
| 109 ppapi::API_ID_PPB_GRAPHICS_3D, resource)); |
| 110 } |
| 111 |
| 112 bool GuestToEmbedderChannel::InitChannel( |
| 113 const IPC::ChannelHandle& channel_handle) { |
| 114 return ProxyChannel::InitWithChannel(&delegate_, channel_handle, false); |
| 115 } |
| 116 |
| 117 void GuestToEmbedderChannel::OnSupportsInterface( |
| 118 const std::string& interface_name, |
| 119 bool* result) { |
| 120 // TODO(fsamuel): This is a hack to avoid getting GetInstanceObject messages |
| 121 // and failing a CHECK. A more correct solution is to implement |
| 122 // VarSerializationRules for GuestToEmbedderChannel. |
| 123 *result = interface_name.find("PPP_Instance_Private") == std::string::npos; |
| 124 } |
| 125 |
| 126 void GuestToEmbedderChannel::OnSetPreferences(const ppapi::Preferences& prefs) { |
| 127 // TODO(fsamuel): Do we care about these preferences? |
| 128 // These look like some font stuff from WebPreferences. |
| 129 // Perhaps this should be plumbed into our associated RenderView? |
| 130 NOTIMPLEMENTED(); |
| 131 } |
| 132 |
| 133 void GuestToEmbedderChannel::OnReserveInstanceId(PP_Instance instance, |
| 134 bool* usable) { |
| 135 *usable = |
| 136 render_view_instances_.find(instance) == render_view_instances_.end(); |
| 137 } |
| 138 |
| 139 void GuestToEmbedderChannel::RequestInputEvents(PP_Instance instance) { |
| 140 // Request receipt of input events |
| 141 Send(new PpapiHostMsg_PPBInstance_RequestInputEvents( |
| 142 ppapi::API_ID_PPB_INSTANCE, instance, true, |
| 143 PP_INPUTEVENT_CLASS_MOUSE | |
| 144 PP_INPUTEVENT_CLASS_KEYBOARD | |
| 145 PP_INPUTEVENT_CLASS_WHEEL | |
| 146 PP_INPUTEVENT_CLASS_TOUCH)); |
| 147 } |
| 148 |
| 149 bool GuestToEmbedderChannel::CreateGraphicsContext( |
| 150 WebGraphicsContext3DCommandBufferImpl* context, |
| 151 const WebKit::WebGraphicsContext3D::Attributes& attributes, |
| 152 bool offscreen, |
| 153 RenderViewImpl* render_view) { |
| 154 std::vector<int32_t> attribs; |
| 155 attribs.push_back(PP_GRAPHICS3DATTRIB_NONE); |
| 156 |
| 157 ppapi::HostResource resource; |
| 158 DCHECK(render_view->guest_pp_instance()); |
| 159 // TODO(fsamuel): Support child contexts. |
| 160 bool success = Send(new PpapiHostMsg_PPBGraphics3D_Create( |
| 161 ppapi::API_ID_PPB_GRAPHICS_3D, |
| 162 render_view->guest_pp_instance(), |
| 163 attribs, |
| 164 &resource)); |
| 165 if (!success || resource.is_null()) |
| 166 return false; |
| 167 if (!offscreen) { |
| 168 PP_Bool result = PP_FALSE; |
| 169 Send(new PpapiHostMsg_PPBInstance_BindGraphics( |
| 170 ppapi::API_ID_PPB_INSTANCE, |
| 171 render_view->guest_pp_instance(), |
| 172 resource, |
| 173 &result)); |
| 174 if (result != PP_TRUE) |
| 175 return false; |
| 176 } |
| 177 |
| 178 CommandBufferProxy* command_buffer = |
| 179 new ppapi::proxy::PpapiCommandBufferProxy(resource, this); |
| 180 command_buffer->Initialize(); |
| 181 context->InitializeWithCommandBuffer( |
| 182 command_buffer, |
| 183 attributes, |
| 184 false /* bind generates resources */); |
| 185 render_view->set_guest_graphics_resource(resource); |
| 186 return true; |
| 187 } |
| 188 |
| 189 void GuestToEmbedderChannel::AddGuest( |
| 190 PP_Instance instance, |
| 191 RenderViewImpl* render_view) { |
| 192 DCHECK(instance); |
| 193 DCHECK(render_view_instances_.find(instance) == render_view_instances_.end()); |
| 194 render_view_instances_[instance] = render_view->AsWeakPtr(); |
| 195 } |
| 196 |
| 197 |
| 198 void GuestToEmbedderChannel::RemoveGuest(PP_Instance instance) { |
| 199 DCHECK(render_view_instances_.find(instance) != render_view_instances_.end()); |
| 200 render_view_instances_.erase(instance); |
| 201 } |
| 202 |
| 203 void GuestToEmbedderChannel::OnDidCreate(PP_Instance instance, |
| 204 const std::vector<std::string>& argn, |
| 205 const std::vector<std::string>& argv, |
| 206 PP_Bool* result) { |
| 207 *result = PP_TRUE; |
| 208 } |
| 209 |
| 210 void GuestToEmbedderChannel::OnDidDestroy(PP_Instance instance) { |
| 211 RemoveGuest(instance); |
| 212 } |
| 213 |
| 214 void GuestToEmbedderChannel::OnDidChangeView( |
| 215 PP_Instance instance, |
| 216 const ppapi::ViewData& new_data, |
| 217 PP_Bool flash_fullscreen) { |
| 218 // We can't do anything with this message if we don't have a render view |
| 219 // yet. If we do have a RenderView then we need to tell the associated |
| 220 // WebContentsObserver to resize. |
| 221 if (render_view_instances_.find(instance) != render_view_instances_.end()) { |
| 222 RenderViewImpl* render_view = render_view_instances_[instance]; |
| 223 render_view->Send( |
| 224 new BrowserPluginHostMsg_ResizeGuest( |
| 225 render_view->GetRoutingID(), |
| 226 new_data.rect.size.width, |
| 227 new_data.rect.size.height)); |
| 228 } |
| 229 } |
| 230 |
| 231 void GuestToEmbedderChannel::OnDidChangeFocus(PP_Instance instance, |
| 232 PP_Bool has_focus) { |
| 233 NOTIMPLEMENTED(); |
| 234 } |
| 235 |
| 236 void GuestToEmbedderChannel::OnHandleMessage( |
| 237 PP_Instance instance, |
| 238 ppapi::proxy::SerializedVarReceiveInput message_data) { |
| 239 InstanceMap::iterator it = render_view_instances_.find(instance); |
| 240 if (it == render_view_instances_.end()) |
| 241 return; |
| 242 |
| 243 PP_Var received_var(message_data.Get(this)); |
| 244 DCHECK(received_var.type == PP_VARTYPE_STRING); |
| 245 ppapi::VarTracker* tracker = ppapi::PpapiGlobals::Get()->GetVarTracker(); |
| 246 ppapi::StringVar* var = tracker->GetVar(received_var)->AsStringVar(); |
| 247 DCHECK(var); |
| 248 |
| 249 RenderViewImpl* render_view = it->second; |
| 250 render_view->Send( |
| 251 new BrowserPluginHostMsg_NavigateFromGuest( |
| 252 render_view->GetRoutingID(), |
| 253 instance, |
| 254 var->value())); |
| 255 } |
| 256 |
| 257 void GuestToEmbedderChannel::OnHandleFilteredInputEvent( |
| 258 PP_Instance instance, |
| 259 const ppapi::InputEventData& data, |
| 260 PP_Bool* result) { |
| 261 DCHECK(render_view_instances_.find(instance) != render_view_instances_.end()); |
| 262 |
| 263 RenderViewImpl* render_view = render_view_instances_[instance]; |
| 264 scoped_ptr<WebKit::WebInputEvent> web_input_event( |
| 265 webkit::ppapi::CreateWebInputEvent(data)); |
| 266 *result = PP_FromBool( |
| 267 render_view->GetWebView()->handleInputEvent(*web_input_event)); |
| 268 } |
| 269 |
| 270 void GuestToEmbedderChannel::OnContextLost(PP_Instance instance) { |
| 271 DCHECK(render_view_instances_.find(instance) != render_view_instances_.end()); |
| 272 RenderViewImpl* render_view = render_view_instances_[instance]; |
| 273 render_view->GetWebView()->loseCompositorContext(1); |
| 274 } |
| 275 |
| 276 } // namespace content |
OLD | NEW |