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.
5 #include "content/plugin/webplugin_delegate_stub.h"
7 #include "build/build_config.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"
29 using blink::WebBindings
;
30 using blink::WebCursorInfo
;
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();
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();
48 // WebPlugin must outlive WebPluginDelegate.
49 delegate
->PluginDestroyed();
51 // PluginDestroyed can call into script, so only unregister as an object
52 // owner after that has completed.
53 WebBindings::unregisterObjectOwner(owner
);
59 WebPluginDelegateStub::WebPluginDelegateStub(
60 const std::string
& mime_type
, int instance_id
, PluginChannel
* channel
) :
61 mime_type_(mime_type
),
62 instance_id_(instance_id
),
66 in_destructor_(false) {
70 WebPluginDelegateStub::~WebPluginDelegateStub() {
71 in_destructor_
= true;
72 GetContentClient()->SetActiveURL(page_url_
);
74 if (channel_
->in_send()) {
75 // The delegate or an npobject is in the callstack, so don't delete it
77 base::MessageLoop::current()->PostNonNestableTask(
79 base::Bind(&DestroyWebPluginAndDelegate
,
80 plugin_scriptable_object_
,
84 // Safe to delete right away.
85 DestroyWebPluginAndDelegate(
86 plugin_scriptable_object_
, delegate_
, webplugin_
);
89 // Remove the NPObject owner mapping for this instance.
91 channel_
->RemoveMappingForNPObjectOwner(instance_id_
);
94 bool WebPluginDelegateStub::OnMessageReceived(const IPC::Message
& msg
) {
95 GetContentClient()->SetActiveURL(page_url_
);
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.
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
)
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
)
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()
161 bool WebPluginDelegateStub::Send(IPC::Message
* msg
) {
162 return channel_
->Send(msg
);
165 void WebPluginDelegateStub::OnInit(const PluginMsg_Init_Params
& params
,
168 page_url_
= params
.page_url
;
169 GetContentClient()->SetActiveURL(page_url_
);
171 *transparent
= false;
173 if (params
.arg_names
.size() != params
.arg_values
.size()) {
178 const CommandLine
& command_line
= *CommandLine::ForCurrentProcess();
179 base::FilePath path
=
180 command_line
.GetSwitchValuePath(switches::kPluginPath
);
182 webplugin_
= new WebPluginProxy(channel_
.get(),
185 params
.host_render_view_routing_id
);
186 delegate_
= WebPluginDelegateImpl::Create(webplugin_
, path
, mime_type_
);
188 if (delegate_
->GetQuirks() &
189 WebPluginDelegateImpl::PLUGIN_QUIRK_DIE_AFTER_UNLOAD
) {
190 PluginThread::current()->SetForcefullyTerminatePluginProcess();
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
;
197 // Register the plugin as a valid object owner.
198 WebBindings::registerObjectOwner(delegate_
->GetPluginNPP());
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());
205 *result
= delegate_
->Initialize(params
.url
,
208 params
.load_manually
);
209 *transparent
= delegate_
->instance()->transparent();
213 void WebPluginDelegateStub::OnWillSendRequest(int id
, const GURL
& url
,
214 int http_status_code
) {
215 WebPluginResourceClient
* client
= webplugin_
->GetResourceClient(id
);
219 client
->WillSendRequest(url
, http_status_code
);
222 void WebPluginDelegateStub::OnDidReceiveResponse(
223 const PluginMsg_DidReceiveResponseParams
& params
) {
224 WebPluginResourceClient
* client
= webplugin_
->GetResourceClient(params
.id
);
228 client
->DidReceiveResponse(params
.mime_type
,
230 params
.expected_length
,
231 params
.last_modified
,
232 params
.request_is_seekable
);
235 void WebPluginDelegateStub::OnDidReceiveData(int id
,
236 const std::vector
<char>& buffer
,
238 WebPluginResourceClient
* client
= webplugin_
->GetResourceClient(id
);
242 client
->DidReceiveData(&buffer
.front(), static_cast<int>(buffer
.size()),
246 void WebPluginDelegateStub::OnDidFinishLoading(int id
) {
247 WebPluginResourceClient
* client
= webplugin_
->GetResourceClient(id
);
251 client
->DidFinishLoading(id
);
254 void WebPluginDelegateStub::OnDidFail(int id
) {
255 WebPluginResourceClient
* client
= webplugin_
->GetResourceClient(id
);
262 void WebPluginDelegateStub::OnDidFinishLoadWithReason(
263 const GURL
& url
, int reason
, int notify_id
) {
264 delegate_
->DidFinishLoadWithReason(url
, reason
, notify_id
);
267 void WebPluginDelegateStub::OnSetFocus(bool focused
) {
268 delegate_
->SetFocus(focused
);
269 #if defined(OS_WIN) && !defined(USE_AURA)
271 webplugin_
->UpdateIMEStatus();
275 void WebPluginDelegateStub::OnHandleInputEvent(
276 const blink::WebInputEvent
*event
,
279 WebCursor::CursorInfo cursor_info
;
280 *handled
= delegate_
->HandleInputEvent(*event
, &cursor_info
);
281 cursor
->InitFromCursorInfo(cursor_info
);
284 void WebPluginDelegateStub::OnPaint(const gfx::Rect
& damaged_rect
) {
285 webplugin_
->Paint(damaged_rect
);
288 void WebPluginDelegateStub::OnDidPaint() {
289 webplugin_
->DidPaint();
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
);
300 void WebPluginDelegateStub::OnGetPluginScriptableObject(int* route_id
) {
301 NPObject
* object
= delegate_
->GetPluginScriptableObject();
303 *route_id
= MSG_ROUTING_NONE
;
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();
316 // Release ref added by GetPluginScriptableObject (our stub holds its own).
317 WebBindings::releaseObject(object
);
320 void WebPluginDelegateStub::OnGetFormValue(base::string16
* value
,
325 *success
= delegate_
->GetFormValue(value
);
328 void WebPluginDelegateStub::OnSendJavaScriptStream(const GURL
& url
,
329 const std::string
& result
,
332 delegate_
->SendJavaScriptStream(url
, result
, success
, notify_id
);
335 void WebPluginDelegateStub::OnSetContentAreaFocus(bool has_focus
) {
337 delegate_
->SetContentAreaHasFocus(has_focus
);
340 #if defined(OS_WIN) && !defined(USE_AURA)
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
) {
347 delegate_
->ImeCompositionUpdated(text
, clauses
, target
, cursor_position
);
348 webplugin_
->UpdateIMEStatus();
351 void WebPluginDelegateStub::OnImeCompositionCompleted(
352 const base::string16
& text
) {
354 delegate_
->ImeCompositionCompleted(text
);
358 #if defined(OS_MACOSX)
359 void WebPluginDelegateStub::OnSetWindowFocus(bool has_focus
) {
361 delegate_
->SetWindowHasFocus(has_focus
);
364 void WebPluginDelegateStub::OnContainerHidden() {
366 delegate_
->SetContainerVisibility(false);
369 void WebPluginDelegateStub::OnContainerShown(gfx::Rect window_frame
,
370 gfx::Rect view_frame
,
373 delegate_
->WindowFrameChanged(window_frame
, view_frame
);
374 delegate_
->SetContainerVisibility(true);
375 delegate_
->SetWindowHasFocus(has_focus
);
379 void WebPluginDelegateStub::OnWindowFrameChanged(const gfx::Rect
& window_frame
,
380 const gfx::Rect
& view_frame
) {
382 delegate_
->WindowFrameChanged(window_frame
, view_frame
);
385 void WebPluginDelegateStub::OnImeCompositionCompleted(
386 const base::string16
& text
) {
388 delegate_
->ImeCompositionCompleted(text
);
392 void WebPluginDelegateStub::OnDidReceiveManualResponse(
394 const PluginMsg_DidReceiveResponseParams
& params
) {
395 delegate_
->DidReceiveManualResponse(url
, params
.mime_type
, params
.headers
,
396 params
.expected_length
,
397 params
.last_modified
);
400 void WebPluginDelegateStub::OnDidReceiveManualData(
401 const std::vector
<char>& buffer
) {
402 delegate_
->DidReceiveManualData(&buffer
.front(),
403 static_cast<int>(buffer
.size()));
406 void WebPluginDelegateStub::OnDidFinishManualLoading() {
407 delegate_
->DidFinishManualLoading();
410 void WebPluginDelegateStub::OnDidManualLoadFail() {
411 delegate_
->DidManualLoadFail();
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
);
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
);
428 void WebPluginDelegateStub::OnFetchURL(
429 const PluginMsg_FetchURL_Params
& params
) {
430 const char* data
= NULL
;
431 if (params
.post_data
.size())
432 data
= ¶ms
.post_data
[0];
434 delegate_
->FetchURL(params
.resource_id
,
437 params
.first_party_for_cookies
,
440 static_cast<unsigned int>(params
.post_data
.size()),
441 Referrer(params
.referrer
, params
.referrer_policy
),
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());
449 } // namespace content