OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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 "chrome/plugin/webplugin_delegate_stub.h" | |
6 | |
7 #include "build/build_config.h" | |
8 | |
9 #include "base/command_line.h" | |
10 #include "chrome/plugin/npobject_stub.h" | |
11 #include "chrome/plugin/plugin_channel.h" | |
12 #include "chrome/plugin/plugin_thread.h" | |
13 #include "chrome/plugin/webplugin_proxy.h" | |
14 #include "content/common/content_client.h" | |
15 #include "content/common/content_switches.h" | |
16 #include "content/common/plugin_messages.h" | |
17 #include "third_party/npapi/bindings/npapi.h" | |
18 #include "third_party/npapi/bindings/npruntime.h" | |
19 #include "skia/ext/platform_device.h" | |
20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h" | |
21 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h" | |
22 #include "webkit/plugins/npapi/webplugin_delegate_impl.h" | |
23 #include "webkit/glue/webcursor.h" | |
24 | |
25 #if defined(OS_WIN) | |
26 #include "base/scoped_ptr.h" | |
27 #include "printing/native_metafile_factory.h" | |
28 #include "printing/native_metafile.h" | |
29 #endif // defined(OS_WIN) | |
30 | |
31 using WebKit::WebBindings; | |
32 using WebKit::WebCursorInfo; | |
33 using webkit::npapi::WebPlugin; | |
34 using webkit::npapi::WebPluginResourceClient; | |
35 | |
36 class FinishDestructionTask : public Task { | |
37 public: | |
38 FinishDestructionTask(webkit::npapi::WebPluginDelegateImpl* delegate, | |
39 WebPlugin* webplugin) | |
40 : delegate_(delegate), webplugin_(webplugin) { | |
41 } | |
42 | |
43 void Run() { | |
44 // WebPlugin must outlive WebPluginDelegate. | |
45 if (delegate_) | |
46 delegate_->PluginDestroyed(); | |
47 | |
48 delete webplugin_; | |
49 } | |
50 | |
51 private: | |
52 webkit::npapi::WebPluginDelegateImpl* delegate_; | |
53 webkit::npapi::WebPlugin* webplugin_; | |
54 }; | |
55 | |
56 WebPluginDelegateStub::WebPluginDelegateStub( | |
57 const std::string& mime_type, int instance_id, PluginChannel* channel) : | |
58 mime_type_(mime_type), | |
59 instance_id_(instance_id), | |
60 channel_(channel), | |
61 delegate_(NULL), | |
62 webplugin_(NULL), | |
63 in_destructor_(false) { | |
64 DCHECK(channel); | |
65 } | |
66 | |
67 WebPluginDelegateStub::~WebPluginDelegateStub() { | |
68 in_destructor_ = true; | |
69 content::GetContentClient()->SetActiveURL(page_url_); | |
70 | |
71 if (channel_->in_send()) { | |
72 // The delegate or an npobject is in the callstack, so don't delete it | |
73 // right away. | |
74 MessageLoop::current()->PostNonNestableTask(FROM_HERE, | |
75 new FinishDestructionTask(delegate_, webplugin_)); | |
76 } else { | |
77 // Safe to delete right away. | |
78 if (delegate_) | |
79 delegate_->PluginDestroyed(); | |
80 | |
81 delete webplugin_; | |
82 } | |
83 } | |
84 | |
85 bool WebPluginDelegateStub::OnMessageReceived(const IPC::Message& msg) { | |
86 content::GetContentClient()->SetActiveURL(page_url_); | |
87 | |
88 // A plugin can execute a script to delete itself in any of its NPP methods. | |
89 // Hold an extra reference to ourself so that if this does occur and we're | |
90 // handling a sync message, we don't crash when attempting to send a reply. | |
91 // The exception to this is when we're already in the destructor. | |
92 if (!in_destructor_) | |
93 AddRef(); | |
94 | |
95 bool handled = true; | |
96 IPC_BEGIN_MESSAGE_MAP(WebPluginDelegateStub, msg) | |
97 IPC_MESSAGE_HANDLER(PluginMsg_Init, OnInit) | |
98 IPC_MESSAGE_HANDLER(PluginMsg_WillSendRequest, OnWillSendRequest) | |
99 IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveResponse, OnDidReceiveResponse) | |
100 IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveData, OnDidReceiveData) | |
101 IPC_MESSAGE_HANDLER(PluginMsg_DidFinishLoading, OnDidFinishLoading) | |
102 IPC_MESSAGE_HANDLER(PluginMsg_DidFail, OnDidFail) | |
103 IPC_MESSAGE_HANDLER(PluginMsg_DidFinishLoadWithReason, | |
104 OnDidFinishLoadWithReason) | |
105 IPC_MESSAGE_HANDLER(PluginMsg_SetFocus, OnSetFocus) | |
106 IPC_MESSAGE_HANDLER(PluginMsg_HandleInputEvent, OnHandleInputEvent) | |
107 IPC_MESSAGE_HANDLER(PluginMsg_Paint, OnPaint) | |
108 IPC_MESSAGE_HANDLER(PluginMsg_DidPaint, OnDidPaint) | |
109 IPC_MESSAGE_HANDLER(PluginMsg_Print, OnPrint) | |
110 IPC_MESSAGE_HANDLER(PluginMsg_GetPluginScriptableObject, | |
111 OnGetPluginScriptableObject) | |
112 IPC_MESSAGE_HANDLER(PluginMsg_UpdateGeometry, OnUpdateGeometry) | |
113 IPC_MESSAGE_HANDLER(PluginMsg_UpdateGeometrySync, OnUpdateGeometry) | |
114 IPC_MESSAGE_HANDLER(PluginMsg_SendJavaScriptStream, | |
115 OnSendJavaScriptStream) | |
116 IPC_MESSAGE_HANDLER(PluginMsg_SetContentAreaFocus, OnSetContentAreaFocus) | |
117 #if defined(OS_MACOSX) | |
118 IPC_MESSAGE_HANDLER(PluginMsg_SetWindowFocus, OnSetWindowFocus) | |
119 IPC_MESSAGE_HANDLER(PluginMsg_ContainerHidden, OnContainerHidden) | |
120 IPC_MESSAGE_HANDLER(PluginMsg_ContainerShown, OnContainerShown) | |
121 IPC_MESSAGE_HANDLER(PluginMsg_WindowFrameChanged, OnWindowFrameChanged) | |
122 IPC_MESSAGE_HANDLER(PluginMsg_ImeCompositionCompleted, | |
123 OnImeCompositionCompleted) | |
124 #endif | |
125 IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveManualResponse, | |
126 OnDidReceiveManualResponse) | |
127 IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveManualData, OnDidReceiveManualData) | |
128 IPC_MESSAGE_HANDLER(PluginMsg_DidFinishManualLoading, | |
129 OnDidFinishManualLoading) | |
130 IPC_MESSAGE_HANDLER(PluginMsg_DidManualLoadFail, OnDidManualLoadFail) | |
131 IPC_MESSAGE_HANDLER(PluginMsg_InstallMissingPlugin, OnInstallMissingPlugin) | |
132 IPC_MESSAGE_HANDLER(PluginMsg_HandleURLRequestReply, | |
133 OnHandleURLRequestReply) | |
134 IPC_MESSAGE_HANDLER(PluginMsg_HTTPRangeRequestReply, | |
135 OnHTTPRangeRequestReply) | |
136 #if defined(OS_MACOSX) | |
137 IPC_MESSAGE_HANDLER(PluginMsg_SetFakeAcceleratedSurfaceWindowHandle, | |
138 OnSetFakeAcceleratedSurfaceWindowHandle) | |
139 #endif | |
140 IPC_MESSAGE_UNHANDLED(handled = false) | |
141 IPC_END_MESSAGE_MAP() | |
142 | |
143 if (!in_destructor_) | |
144 Release(); | |
145 | |
146 DCHECK(handled); | |
147 return handled; | |
148 } | |
149 | |
150 bool WebPluginDelegateStub::Send(IPC::Message* msg) { | |
151 return channel_->Send(msg); | |
152 } | |
153 | |
154 void WebPluginDelegateStub::OnInit(const PluginMsg_Init_Params& params, | |
155 bool* result) { | |
156 page_url_ = params.page_url; | |
157 content::GetContentClient()->SetActiveURL(page_url_); | |
158 | |
159 *result = false; | |
160 if (params.arg_names.size() != params.arg_values.size()) { | |
161 NOTREACHED(); | |
162 return; | |
163 } | |
164 | |
165 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); | |
166 FilePath path = | |
167 command_line.GetSwitchValuePath(switches::kPluginPath); | |
168 | |
169 gfx::PluginWindowHandle parent = gfx::kNullPluginWindow; | |
170 #if defined(OS_WIN) | |
171 parent = gfx::NativeViewFromId(params.containing_window); | |
172 #elif defined(OS_LINUX) | |
173 // This code is disabled, See issue 17110. | |
174 // The problem is that the XID can change at arbitrary times (e.g. when the | |
175 // tab is detached then reattached), so we need to be able to track these | |
176 // changes, and let the PluginInstance know. | |
177 // PluginThread::current()->Send(new PluginProcessHostMsg_MapNativeViewId( | |
178 // params.containing_window, &parent)); | |
179 #endif | |
180 | |
181 webplugin_ = new WebPluginProxy( | |
182 channel_, instance_id_, page_url_, params.containing_window, | |
183 params.host_render_view_routing_id); | |
184 delegate_ = webkit::npapi::WebPluginDelegateImpl::Create( | |
185 path, mime_type_, parent); | |
186 if (delegate_) { | |
187 webplugin_->set_delegate(delegate_); | |
188 *result = delegate_->Initialize(params.url, | |
189 params.arg_names, | |
190 params.arg_values, | |
191 webplugin_, | |
192 params.load_manually); | |
193 } | |
194 } | |
195 | |
196 void WebPluginDelegateStub::OnWillSendRequest(int id, const GURL& url, | |
197 int http_status_code) { | |
198 WebPluginResourceClient* client = webplugin_->GetResourceClient(id); | |
199 if (!client) | |
200 return; | |
201 | |
202 client->WillSendRequest(url, http_status_code); | |
203 } | |
204 | |
205 void WebPluginDelegateStub::OnDidReceiveResponse( | |
206 const PluginMsg_DidReceiveResponseParams& params) { | |
207 WebPluginResourceClient* client = webplugin_->GetResourceClient(params.id); | |
208 if (!client) | |
209 return; | |
210 | |
211 client->DidReceiveResponse(params.mime_type, | |
212 params.headers, | |
213 params.expected_length, | |
214 params.last_modified, | |
215 params.request_is_seekable); | |
216 } | |
217 | |
218 void WebPluginDelegateStub::OnDidReceiveData(int id, | |
219 const std::vector<char>& buffer, | |
220 int data_offset) { | |
221 WebPluginResourceClient* client = webplugin_->GetResourceClient(id); | |
222 if (!client) | |
223 return; | |
224 | |
225 client->DidReceiveData(&buffer.front(), static_cast<int>(buffer.size()), | |
226 data_offset); | |
227 } | |
228 | |
229 void WebPluginDelegateStub::OnDidFinishLoading(int id) { | |
230 WebPluginResourceClient* client = webplugin_->GetResourceClient(id); | |
231 if (!client) | |
232 return; | |
233 | |
234 client->DidFinishLoading(); | |
235 } | |
236 | |
237 void WebPluginDelegateStub::OnDidFail(int id) { | |
238 WebPluginResourceClient* client = webplugin_->GetResourceClient(id); | |
239 if (!client) | |
240 return; | |
241 | |
242 client->DidFail(); | |
243 } | |
244 | |
245 void WebPluginDelegateStub::OnDidFinishLoadWithReason( | |
246 const GURL& url, int reason, int notify_id) { | |
247 delegate_->DidFinishLoadWithReason(url, reason, notify_id); | |
248 } | |
249 | |
250 void WebPluginDelegateStub::OnSetFocus(bool focused) { | |
251 delegate_->SetFocus(focused); | |
252 } | |
253 | |
254 void WebPluginDelegateStub::OnHandleInputEvent( | |
255 const WebKit::WebInputEvent *event, | |
256 bool* handled, | |
257 WebCursor* cursor) { | |
258 WebCursorInfo cursor_info; | |
259 *handled = delegate_->HandleInputEvent(*event, &cursor_info); | |
260 cursor->InitFromCursorInfo(cursor_info); | |
261 } | |
262 | |
263 void WebPluginDelegateStub::OnPaint(const gfx::Rect& damaged_rect) { | |
264 webplugin_->Paint(damaged_rect); | |
265 } | |
266 | |
267 void WebPluginDelegateStub::OnDidPaint() { | |
268 webplugin_->DidPaint(); | |
269 } | |
270 | |
271 void WebPluginDelegateStub::OnPrint(base::SharedMemoryHandle* shared_memory, | |
272 uint32* size) { | |
273 #if defined(OS_WIN) | |
274 scoped_ptr<printing::NativeMetafile> metafile( | |
275 printing::NativeMetafileFactory::CreateMetafile()); | |
276 if (!metafile->CreateDc(NULL, NULL)) { | |
277 NOTREACHED(); | |
278 return; | |
279 } | |
280 HDC hdc = metafile->context(); | |
281 skia::PlatformDevice::InitializeDC(hdc); | |
282 delegate_->Print(hdc); | |
283 if (!metafile->Close()) { | |
284 NOTREACHED(); | |
285 return; | |
286 } | |
287 | |
288 *size = metafile->GetDataSize(); | |
289 DCHECK(*size); | |
290 base::SharedMemory shared_buf; | |
291 CreateSharedBuffer(*size, &shared_buf, shared_memory); | |
292 | |
293 // Retrieve a copy of the data. | |
294 bool success = metafile->GetData(shared_buf.memory(), *size); | |
295 DCHECK(success); | |
296 #else | |
297 // TODO(port): plugin printing. | |
298 NOTIMPLEMENTED(); | |
299 #endif | |
300 } | |
301 | |
302 void WebPluginDelegateStub::OnUpdateGeometry( | |
303 const PluginMsg_UpdateGeometry_Param& param) { | |
304 webplugin_->UpdateGeometry( | |
305 param.window_rect, param.clip_rect, | |
306 param.windowless_buffer, param.background_buffer, | |
307 param.transparent | |
308 #if defined(OS_MACOSX) | |
309 , | |
310 param.ack_key | |
311 #endif | |
312 ); | |
313 } | |
314 | |
315 void WebPluginDelegateStub::OnGetPluginScriptableObject(int* route_id) { | |
316 NPObject* object = delegate_->GetPluginScriptableObject(); | |
317 if (!object) { | |
318 *route_id = MSG_ROUTING_NONE; | |
319 return; | |
320 } | |
321 | |
322 *route_id = channel_->GenerateRouteID(); | |
323 // The stub will delete itself when the proxy tells it that it's released, or | |
324 // otherwise when the channel is closed. | |
325 new NPObjectStub( | |
326 object, channel_.get(), *route_id, webplugin_->containing_window(), | |
327 page_url_); | |
328 | |
329 // Release ref added by GetPluginScriptableObject (our stub holds its own). | |
330 WebBindings::releaseObject(object); | |
331 } | |
332 | |
333 void WebPluginDelegateStub::OnSendJavaScriptStream(const GURL& url, | |
334 const std::string& result, | |
335 bool success, | |
336 int notify_id) { | |
337 delegate_->SendJavaScriptStream(url, result, success, notify_id); | |
338 } | |
339 | |
340 void WebPluginDelegateStub::OnSetContentAreaFocus(bool has_focus) { | |
341 if (delegate_) | |
342 delegate_->SetContentAreaHasFocus(has_focus); | |
343 } | |
344 | |
345 #if defined(OS_MACOSX) | |
346 void WebPluginDelegateStub::OnSetWindowFocus(bool has_focus) { | |
347 if (delegate_) | |
348 delegate_->SetWindowHasFocus(has_focus); | |
349 } | |
350 | |
351 void WebPluginDelegateStub::OnContainerHidden() { | |
352 if (delegate_) | |
353 delegate_->SetContainerVisibility(false); | |
354 } | |
355 | |
356 void WebPluginDelegateStub::OnContainerShown(gfx::Rect window_frame, | |
357 gfx::Rect view_frame, | |
358 bool has_focus) { | |
359 if (delegate_) { | |
360 delegate_->WindowFrameChanged(window_frame, view_frame); | |
361 delegate_->SetContainerVisibility(true); | |
362 delegate_->SetWindowHasFocus(has_focus); | |
363 } | |
364 } | |
365 | |
366 void WebPluginDelegateStub::OnWindowFrameChanged(const gfx::Rect& window_frame, | |
367 const gfx::Rect& view_frame) { | |
368 if (delegate_) | |
369 delegate_->WindowFrameChanged(window_frame, view_frame); | |
370 } | |
371 | |
372 void WebPluginDelegateStub::OnImeCompositionCompleted(const string16& text) { | |
373 if (delegate_) | |
374 delegate_->ImeCompositionCompleted(text); | |
375 } | |
376 #endif // OS_MACOSX | |
377 | |
378 void WebPluginDelegateStub::OnDidReceiveManualResponse( | |
379 const GURL& url, | |
380 const PluginMsg_DidReceiveResponseParams& params) { | |
381 delegate_->DidReceiveManualResponse(url, params.mime_type, params.headers, | |
382 params.expected_length, | |
383 params.last_modified); | |
384 } | |
385 | |
386 void WebPluginDelegateStub::OnDidReceiveManualData( | |
387 const std::vector<char>& buffer) { | |
388 delegate_->DidReceiveManualData(&buffer.front(), | |
389 static_cast<int>(buffer.size())); | |
390 } | |
391 | |
392 void WebPluginDelegateStub::OnDidFinishManualLoading() { | |
393 delegate_->DidFinishManualLoading(); | |
394 } | |
395 | |
396 void WebPluginDelegateStub::OnDidManualLoadFail() { | |
397 delegate_->DidManualLoadFail(); | |
398 } | |
399 | |
400 void WebPluginDelegateStub::OnInstallMissingPlugin() { | |
401 delegate_->InstallMissingPlugin(); | |
402 } | |
403 | |
404 void WebPluginDelegateStub::CreateSharedBuffer( | |
405 uint32 size, | |
406 base::SharedMemory* shared_buf, | |
407 base::SharedMemoryHandle* remote_handle) { | |
408 if (!shared_buf->CreateAndMapAnonymous(size)) { | |
409 NOTREACHED(); | |
410 shared_buf->Close(); | |
411 return; | |
412 } | |
413 | |
414 #if defined(OS_WIN) | |
415 BOOL result = DuplicateHandle(GetCurrentProcess(), | |
416 shared_buf->handle(), | |
417 channel_->renderer_handle(), | |
418 remote_handle, 0, FALSE, | |
419 DUPLICATE_SAME_ACCESS); | |
420 DCHECK_NE(result, 0); | |
421 | |
422 // If the calling function's shared_buf is on the stack, its destructor will | |
423 // close the shared memory buffer handle. This is fine since we already | |
424 // duplicated the handle to the renderer process so it will stay "alive". | |
425 #else | |
426 // TODO(port): this should use TransportDIB. | |
427 NOTIMPLEMENTED(); | |
428 #endif | |
429 } | |
430 | |
431 void WebPluginDelegateStub::OnHandleURLRequestReply( | |
432 unsigned long resource_id, const GURL& url, int notify_id) { | |
433 WebPluginResourceClient* resource_client = | |
434 delegate_->CreateResourceClient(resource_id, url, notify_id); | |
435 webplugin_->OnResourceCreated(resource_id, resource_client); | |
436 } | |
437 | |
438 void WebPluginDelegateStub::OnHTTPRangeRequestReply( | |
439 unsigned long resource_id, int range_request_id) { | |
440 WebPluginResourceClient* resource_client = | |
441 delegate_->CreateSeekableResourceClient(resource_id, range_request_id); | |
442 webplugin_->OnResourceCreated(resource_id, resource_client); | |
443 } | |
444 | |
445 #if defined(OS_MACOSX) | |
446 void WebPluginDelegateStub::OnSetFakeAcceleratedSurfaceWindowHandle( | |
447 gfx::PluginWindowHandle window) { | |
448 delegate_->set_windowed_handle(window); | |
449 } | |
450 #endif | |
451 | |
OLD | NEW |