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