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