• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/plugin/webplugin_delegate_stub.h"
6 
7 #include "build/build_config.h"
8 
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "content/child/npapi/plugin_instance.h"
13 #include "content/child/npapi/webplugin_delegate_impl.h"
14 #include "content/child/npapi/webplugin_resource_client.h"
15 #include "content/child/plugin_messages.h"
16 #include "content/common/cursors/webcursor.h"
17 #include "content/plugin/plugin_channel.h"
18 #include "content/plugin/plugin_thread.h"
19 #include "content/plugin/webplugin_proxy.h"
20 #include "content/public/common/content_client.h"
21 #include "content/public/common/content_constants.h"
22 #include "content/public/common/content_switches.h"
23 #include "skia/ext/platform_device.h"
24 #include "third_party/WebKit/public/platform/WebCursorInfo.h"
25 #include "third_party/WebKit/public/web/WebBindings.h"
26 #include "third_party/npapi/bindings/npapi.h"
27 #include "third_party/npapi/bindings/npruntime.h"
28 
29 using blink::WebBindings;
30 using blink::WebCursorInfo;
31 
32 namespace content {
33 
DestroyWebPluginAndDelegate(base::WeakPtr<NPObjectStub> scriptable_object,WebPluginDelegateImpl * delegate,WebPlugin * webplugin)34 static void DestroyWebPluginAndDelegate(
35     base::WeakPtr<NPObjectStub> scriptable_object,
36     WebPluginDelegateImpl* delegate,
37     WebPlugin* webplugin) {
38   // The plugin may not expect us to try to release the scriptable object
39   // after calling NPP_Destroy on the instance, so delete the stub now.
40   if (scriptable_object.get())
41     scriptable_object->DeleteSoon();
42 
43   if (delegate) {
44     // Save the object owner Id so we can unregister it as a valid owner
45     // after the instance has been destroyed.
46     NPP owner = delegate->GetPluginNPP();
47 
48     // WebPlugin must outlive WebPluginDelegate.
49     delegate->PluginDestroyed();
50 
51     // PluginDestroyed can call into script, so only unregister as an object
52     // owner after that has completed.
53     WebBindings::unregisterObjectOwner(owner);
54   }
55 
56   delete webplugin;
57 }
58 
WebPluginDelegateStub(const std::string & mime_type,int instance_id,PluginChannel * channel)59 WebPluginDelegateStub::WebPluginDelegateStub(
60     const std::string& mime_type, int instance_id, PluginChannel* channel) :
61     mime_type_(mime_type),
62     instance_id_(instance_id),
63     channel_(channel),
64     delegate_(NULL),
65     webplugin_(NULL),
66     in_destructor_(false) {
67   DCHECK(channel);
68 }
69 
~WebPluginDelegateStub()70 WebPluginDelegateStub::~WebPluginDelegateStub() {
71   in_destructor_ = true;
72   GetContentClient()->SetActiveURL(page_url_);
73 
74   if (channel_->in_send()) {
75     // The delegate or an npobject is in the callstack, so don't delete it
76     // right away.
77     base::MessageLoop::current()->PostNonNestableTask(
78         FROM_HERE,
79         base::Bind(&DestroyWebPluginAndDelegate,
80                    plugin_scriptable_object_,
81                    delegate_,
82                    webplugin_));
83   } else {
84     // Safe to delete right away.
85     DestroyWebPluginAndDelegate(
86         plugin_scriptable_object_, delegate_, webplugin_);
87   }
88 
89   // Remove the NPObject owner mapping for this instance.
90   if (delegate_)
91     channel_->RemoveMappingForNPObjectOwner(instance_id_);
92 }
93 
OnMessageReceived(const IPC::Message & msg)94 bool WebPluginDelegateStub::OnMessageReceived(const IPC::Message& msg) {
95   GetContentClient()->SetActiveURL(page_url_);
96 
97   // A plugin can execute a script to delete itself in any of its NPP methods.
98   // Hold an extra reference to ourself so that if this does occur and we're
99   // handling a sync message, we don't crash when attempting to send a reply.
100   // The exception to this is when we're already in the destructor.
101   if (!in_destructor_)
102     AddRef();
103 
104   bool handled = true;
105   IPC_BEGIN_MESSAGE_MAP(WebPluginDelegateStub, msg)
106     IPC_MESSAGE_HANDLER(PluginMsg_Init, OnInit)
107     IPC_MESSAGE_HANDLER(PluginMsg_WillSendRequest, OnWillSendRequest)
108     IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveResponse, OnDidReceiveResponse)
109     IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveData, OnDidReceiveData)
110     IPC_MESSAGE_HANDLER(PluginMsg_DidFinishLoading, OnDidFinishLoading)
111     IPC_MESSAGE_HANDLER(PluginMsg_DidFail, OnDidFail)
112     IPC_MESSAGE_HANDLER(PluginMsg_DidFinishLoadWithReason,
113                         OnDidFinishLoadWithReason)
114     IPC_MESSAGE_HANDLER(PluginMsg_SetFocus, OnSetFocus)
115     IPC_MESSAGE_HANDLER(PluginMsg_HandleInputEvent, OnHandleInputEvent)
116     IPC_MESSAGE_HANDLER(PluginMsg_Paint, OnPaint)
117     IPC_MESSAGE_HANDLER(PluginMsg_DidPaint, OnDidPaint)
118     IPC_MESSAGE_HANDLER(PluginMsg_GetPluginScriptableObject,
119                         OnGetPluginScriptableObject)
120     IPC_MESSAGE_HANDLER(PluginMsg_GetFormValue, OnGetFormValue)
121     IPC_MESSAGE_HANDLER(PluginMsg_UpdateGeometry, OnUpdateGeometry)
122     IPC_MESSAGE_HANDLER(PluginMsg_UpdateGeometrySync, OnUpdateGeometry)
123     IPC_MESSAGE_HANDLER(PluginMsg_SendJavaScriptStream,
124                         OnSendJavaScriptStream)
125     IPC_MESSAGE_HANDLER(PluginMsg_SetContentAreaFocus, OnSetContentAreaFocus)
126 #if defined(OS_WIN) && !defined(USE_AURA)
127     IPC_MESSAGE_HANDLER(PluginMsg_ImeCompositionUpdated,
128                         OnImeCompositionUpdated)
129     IPC_MESSAGE_HANDLER(PluginMsg_ImeCompositionCompleted,
130                         OnImeCompositionCompleted)
131 #endif
132 #if defined(OS_MACOSX)
133     IPC_MESSAGE_HANDLER(PluginMsg_SetWindowFocus, OnSetWindowFocus)
134     IPC_MESSAGE_HANDLER(PluginMsg_ContainerHidden, OnContainerHidden)
135     IPC_MESSAGE_HANDLER(PluginMsg_ContainerShown, OnContainerShown)
136     IPC_MESSAGE_HANDLER(PluginMsg_WindowFrameChanged, OnWindowFrameChanged)
137     IPC_MESSAGE_HANDLER(PluginMsg_ImeCompositionCompleted,
138                         OnImeCompositionCompleted)
139 #endif
140     IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveManualResponse,
141                         OnDidReceiveManualResponse)
142     IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveManualData, OnDidReceiveManualData)
143     IPC_MESSAGE_HANDLER(PluginMsg_DidFinishManualLoading,
144                         OnDidFinishManualLoading)
145     IPC_MESSAGE_HANDLER(PluginMsg_DidManualLoadFail, OnDidManualLoadFail)
146     IPC_MESSAGE_HANDLER(PluginMsg_HandleURLRequestReply,
147                         OnHandleURLRequestReply)
148     IPC_MESSAGE_HANDLER(PluginMsg_HTTPRangeRequestReply,
149                         OnHTTPRangeRequestReply)
150     IPC_MESSAGE_HANDLER(PluginMsg_FetchURL, OnFetchURL)
151     IPC_MESSAGE_UNHANDLED(handled = false)
152   IPC_END_MESSAGE_MAP()
153 
154   if (!in_destructor_)
155     Release();
156 
157   DCHECK(handled);
158   return handled;
159 }
160 
Send(IPC::Message * msg)161 bool WebPluginDelegateStub::Send(IPC::Message* msg) {
162   return channel_->Send(msg);
163 }
164 
OnInit(const PluginMsg_Init_Params & params,bool * transparent,bool * result)165 void WebPluginDelegateStub::OnInit(const PluginMsg_Init_Params& params,
166                                    bool* transparent,
167                                    bool* result) {
168   page_url_ = params.page_url;
169   GetContentClient()->SetActiveURL(page_url_);
170 
171   *transparent = false;
172   *result = false;
173   if (params.arg_names.size() != params.arg_values.size()) {
174     NOTREACHED();
175     return;
176   }
177 
178   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
179   base::FilePath path =
180       command_line.GetSwitchValuePath(switches::kPluginPath);
181 
182   webplugin_ = new WebPluginProxy(channel_.get(),
183                                   instance_id_,
184                                   page_url_,
185                                   params.host_render_view_routing_id);
186   delegate_ = WebPluginDelegateImpl::Create(webplugin_, path, mime_type_);
187   if (delegate_) {
188     if (delegate_->GetQuirks() &
189         WebPluginDelegateImpl::PLUGIN_QUIRK_DIE_AFTER_UNLOAD) {
190       PluginThread::current()->SetForcefullyTerminatePluginProcess();
191     }
192 
193     webplugin_->set_delegate(delegate_);
194     std::vector<std::string> arg_names = params.arg_names;
195     std::vector<std::string> arg_values = params.arg_values;
196 
197     // Register the plugin as a valid object owner.
198     WebBindings::registerObjectOwner(delegate_->GetPluginNPP());
199 
200     // Add an NPObject owner mapping for this instance, to support ownership
201     // tracking in the renderer.
202     channel_->AddMappingForNPObjectOwner(instance_id_,
203                                          delegate_->GetPluginNPP());
204 
205     *result = delegate_->Initialize(params.url,
206                                     arg_names,
207                                     arg_values,
208                                     params.load_manually);
209     *transparent = delegate_->instance()->transparent();
210   }
211 }
212 
OnWillSendRequest(int id,const GURL & url,int http_status_code)213 void WebPluginDelegateStub::OnWillSendRequest(int id, const GURL& url,
214                                               int http_status_code) {
215   WebPluginResourceClient* client = webplugin_->GetResourceClient(id);
216   if (!client)
217     return;
218 
219   client->WillSendRequest(url, http_status_code);
220 }
221 
OnDidReceiveResponse(const PluginMsg_DidReceiveResponseParams & params)222 void WebPluginDelegateStub::OnDidReceiveResponse(
223     const PluginMsg_DidReceiveResponseParams& params) {
224   WebPluginResourceClient* client = webplugin_->GetResourceClient(params.id);
225   if (!client)
226     return;
227 
228   client->DidReceiveResponse(params.mime_type,
229                              params.headers,
230                              params.expected_length,
231                              params.last_modified,
232                              params.request_is_seekable);
233 }
234 
OnDidReceiveData(int id,const std::vector<char> & buffer,int data_offset)235 void WebPluginDelegateStub::OnDidReceiveData(int id,
236                                              const std::vector<char>& buffer,
237                                              int data_offset) {
238   WebPluginResourceClient* client = webplugin_->GetResourceClient(id);
239   if (!client)
240     return;
241 
242   client->DidReceiveData(&buffer.front(), static_cast<int>(buffer.size()),
243                          data_offset);
244 }
245 
OnDidFinishLoading(int id)246 void WebPluginDelegateStub::OnDidFinishLoading(int id) {
247   WebPluginResourceClient* client = webplugin_->GetResourceClient(id);
248   if (!client)
249     return;
250 
251   client->DidFinishLoading(id);
252 }
253 
OnDidFail(int id)254 void WebPluginDelegateStub::OnDidFail(int id) {
255   WebPluginResourceClient* client = webplugin_->GetResourceClient(id);
256   if (!client)
257     return;
258 
259   client->DidFail(id);
260 }
261 
OnDidFinishLoadWithReason(const GURL & url,int reason,int notify_id)262 void WebPluginDelegateStub::OnDidFinishLoadWithReason(
263     const GURL& url, int reason, int notify_id) {
264   delegate_->DidFinishLoadWithReason(url, reason, notify_id);
265 }
266 
OnSetFocus(bool focused)267 void WebPluginDelegateStub::OnSetFocus(bool focused) {
268   delegate_->SetFocus(focused);
269 #if defined(OS_WIN) && !defined(USE_AURA)
270   if (focused)
271     webplugin_->UpdateIMEStatus();
272 #endif
273 }
274 
OnHandleInputEvent(const blink::WebInputEvent * event,bool * handled,WebCursor * cursor)275 void WebPluginDelegateStub::OnHandleInputEvent(
276     const blink::WebInputEvent *event,
277     bool* handled,
278     WebCursor* cursor) {
279   WebCursor::CursorInfo cursor_info;
280   *handled = delegate_->HandleInputEvent(*event, &cursor_info);
281   cursor->InitFromCursorInfo(cursor_info);
282 }
283 
OnPaint(const gfx::Rect & damaged_rect)284 void WebPluginDelegateStub::OnPaint(const gfx::Rect& damaged_rect) {
285   webplugin_->Paint(damaged_rect);
286 }
287 
OnDidPaint()288 void WebPluginDelegateStub::OnDidPaint() {
289   webplugin_->DidPaint();
290 }
291 
OnUpdateGeometry(const PluginMsg_UpdateGeometry_Param & param)292 void WebPluginDelegateStub::OnUpdateGeometry(
293     const PluginMsg_UpdateGeometry_Param& param) {
294   webplugin_->UpdateGeometry(
295       param.window_rect, param.clip_rect,
296       param.windowless_buffer0, param.windowless_buffer1,
297       param.windowless_buffer_index);
298 }
299 
OnGetPluginScriptableObject(int * route_id)300 void WebPluginDelegateStub::OnGetPluginScriptableObject(int* route_id) {
301   NPObject* object = delegate_->GetPluginScriptableObject();
302   if (!object) {
303     *route_id = MSG_ROUTING_NONE;
304     return;
305   }
306 
307   *route_id = channel_->GenerateRouteID();
308   // We will delete the stub immediately before calling PluginDestroyed on the
309   // delegate. It will delete itself sooner if the proxy tells it that it has
310   // been released, or if the channel to the proxy is closed.
311   NPObjectStub* scriptable_stub = new NPObjectStub(
312       object, channel_.get(), *route_id,
313       webplugin_->host_render_view_routing_id(), page_url_);
314   plugin_scriptable_object_ = scriptable_stub->AsWeakPtr();
315 
316   // Release ref added by GetPluginScriptableObject (our stub holds its own).
317   WebBindings::releaseObject(object);
318 }
319 
OnGetFormValue(base::string16 * value,bool * success)320 void WebPluginDelegateStub::OnGetFormValue(base::string16* value,
321                                            bool* success) {
322   *success = false;
323   if (!delegate_)
324     return;
325   *success = delegate_->GetFormValue(value);
326 }
327 
OnSendJavaScriptStream(const GURL & url,const std::string & result,bool success,int notify_id)328 void WebPluginDelegateStub::OnSendJavaScriptStream(const GURL& url,
329                                                    const std::string& result,
330                                                    bool success,
331                                                    int notify_id) {
332   delegate_->SendJavaScriptStream(url, result, success, notify_id);
333 }
334 
OnSetContentAreaFocus(bool has_focus)335 void WebPluginDelegateStub::OnSetContentAreaFocus(bool has_focus) {
336   if (delegate_)
337     delegate_->SetContentAreaHasFocus(has_focus);
338 }
339 
340 #if defined(OS_WIN) && !defined(USE_AURA)
OnImeCompositionUpdated(const base::string16 & text,const std::vector<int> & clauses,const std::vector<int> & target,int cursor_position)341 void WebPluginDelegateStub::OnImeCompositionUpdated(
342     const base::string16& text,
343     const std::vector<int>& clauses,
344     const std::vector<int>& target,
345     int cursor_position) {
346   if (delegate_)
347     delegate_->ImeCompositionUpdated(text, clauses, target, cursor_position);
348   webplugin_->UpdateIMEStatus();
349 }
350 
OnImeCompositionCompleted(const base::string16 & text)351 void WebPluginDelegateStub::OnImeCompositionCompleted(
352     const base::string16& text) {
353   if (delegate_)
354     delegate_->ImeCompositionCompleted(text);
355 }
356 #endif
357 
358 #if defined(OS_MACOSX)
OnSetWindowFocus(bool has_focus)359 void WebPluginDelegateStub::OnSetWindowFocus(bool has_focus) {
360   if (delegate_)
361     delegate_->SetWindowHasFocus(has_focus);
362 }
363 
OnContainerHidden()364 void WebPluginDelegateStub::OnContainerHidden() {
365   if (delegate_)
366     delegate_->SetContainerVisibility(false);
367 }
368 
OnContainerShown(gfx::Rect window_frame,gfx::Rect view_frame,bool has_focus)369 void WebPluginDelegateStub::OnContainerShown(gfx::Rect window_frame,
370                                              gfx::Rect view_frame,
371                                              bool has_focus) {
372   if (delegate_) {
373     delegate_->WindowFrameChanged(window_frame, view_frame);
374     delegate_->SetContainerVisibility(true);
375     delegate_->SetWindowHasFocus(has_focus);
376   }
377 }
378 
OnWindowFrameChanged(const gfx::Rect & window_frame,const gfx::Rect & view_frame)379 void WebPluginDelegateStub::OnWindowFrameChanged(const gfx::Rect& window_frame,
380                                                  const gfx::Rect& view_frame) {
381   if (delegate_)
382     delegate_->WindowFrameChanged(window_frame, view_frame);
383 }
384 
OnImeCompositionCompleted(const base::string16 & text)385 void WebPluginDelegateStub::OnImeCompositionCompleted(
386     const base::string16& text) {
387   if (delegate_)
388     delegate_->ImeCompositionCompleted(text);
389 }
390 #endif  // OS_MACOSX
391 
OnDidReceiveManualResponse(const GURL & url,const PluginMsg_DidReceiveResponseParams & params)392 void WebPluginDelegateStub::OnDidReceiveManualResponse(
393     const GURL& url,
394     const PluginMsg_DidReceiveResponseParams& params) {
395   delegate_->DidReceiveManualResponse(url, params.mime_type, params.headers,
396                                       params.expected_length,
397                                       params.last_modified);
398 }
399 
OnDidReceiveManualData(const std::vector<char> & buffer)400 void WebPluginDelegateStub::OnDidReceiveManualData(
401     const std::vector<char>& buffer) {
402   delegate_->DidReceiveManualData(&buffer.front(),
403                                   static_cast<int>(buffer.size()));
404 }
405 
OnDidFinishManualLoading()406 void WebPluginDelegateStub::OnDidFinishManualLoading() {
407   delegate_->DidFinishManualLoading();
408 }
409 
OnDidManualLoadFail()410 void WebPluginDelegateStub::OnDidManualLoadFail() {
411   delegate_->DidManualLoadFail();
412 }
413 
OnHandleURLRequestReply(unsigned long resource_id,const GURL & url,int notify_id)414 void WebPluginDelegateStub::OnHandleURLRequestReply(
415     unsigned long resource_id, const GURL& url, int notify_id) {
416   WebPluginResourceClient* resource_client =
417       delegate_->CreateResourceClient(resource_id, url, notify_id);
418   webplugin_->OnResourceCreated(resource_id, resource_client);
419 }
420 
OnHTTPRangeRequestReply(unsigned long resource_id,int range_request_id)421 void WebPluginDelegateStub::OnHTTPRangeRequestReply(
422     unsigned long resource_id, int range_request_id) {
423   WebPluginResourceClient* resource_client =
424       delegate_->CreateSeekableResourceClient(resource_id, range_request_id);
425   webplugin_->OnResourceCreated(resource_id, resource_client);
426 }
427 
OnFetchURL(const PluginMsg_FetchURL_Params & params)428 void WebPluginDelegateStub::OnFetchURL(
429     const PluginMsg_FetchURL_Params& params) {
430   const char* data = NULL;
431   if (params.post_data.size())
432     data = &params.post_data[0];
433 
434   delegate_->FetchURL(params.resource_id,
435                       params.notify_id,
436                       params.url,
437                       params.first_party_for_cookies,
438                       params.method,
439                       data,
440                       static_cast<unsigned int>(params.post_data.size()),
441                       params.referrer,
442                       params.notify_redirect,
443                       params.is_plugin_src_load,
444                       channel_->renderer_id(),
445                       params.render_frame_id,
446                       webplugin_->host_render_view_routing_id());
447 }
448 
449 }  // namespace content
450