Fix nullptr crash in OnEmbed
[chromium-blink-merge.git] / content / plugin / webplugin_delegate_stub.cc
blobae4ebee43f061bdaf73afd4a34007d4316e34f26
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"
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"
29 using blink::WebBindings;
30 using blink::WebCursorInfo;
32 namespace content {
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();
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();
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);
56 delete webplugin;
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);
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
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_);
89 // Remove the NPObject owner mapping for this instance.
90 if (delegate_)
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.
101 if (!in_destructor_)
102 AddRef();
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()
154 if (!in_destructor_)
155 Release();
157 DCHECK(handled);
158 return handled;
161 bool WebPluginDelegateStub::Send(IPC::Message* msg) {
162 return channel_->Send(msg);
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_);
171 *transparent = false;
172 *result = false;
173 if (params.arg_names.size() != params.arg_values.size()) {
174 NOTREACHED();
175 return;
178 const base::CommandLine& command_line =
179 *base::CommandLine::ForCurrentProcess();
180 base::FilePath path =
181 command_line.GetSwitchValuePath(switches::kPluginPath);
183 webplugin_ = new WebPluginProxy(channel_.get(),
184 instance_id_,
185 page_url_,
186 params.host_render_view_routing_id);
187 delegate_ = WebPluginDelegateImpl::Create(webplugin_, path, mime_type_);
188 if (delegate_) {
189 if (delegate_->GetQuirks() &
190 WebPluginDelegateImpl::PLUGIN_QUIRK_DIE_AFTER_UNLOAD) {
191 PluginThread::current()->SetForcefullyTerminatePluginProcess();
194 webplugin_->set_delegate(delegate_);
195 std::vector<std::string> arg_names = params.arg_names;
196 std::vector<std::string> arg_values = params.arg_values;
198 // Register the plugin as a valid object owner.
199 WebBindings::registerObjectOwner(delegate_->GetPluginNPP());
201 // Add an NPObject owner mapping for this instance, to support ownership
202 // tracking in the renderer.
203 channel_->AddMappingForNPObjectOwner(instance_id_,
204 delegate_->GetPluginNPP());
206 *result = delegate_->Initialize(params.url,
207 arg_names,
208 arg_values,
209 params.load_manually);
210 *transparent = delegate_->instance()->transparent();
214 void WebPluginDelegateStub::OnWillSendRequest(int id, const GURL& url,
215 int http_status_code) {
216 WebPluginResourceClient* client = webplugin_->GetResourceClient(id);
217 if (!client)
218 return;
220 client->WillSendRequest(url, http_status_code);
223 void WebPluginDelegateStub::OnDidReceiveResponse(
224 const PluginMsg_DidReceiveResponseParams& params) {
225 WebPluginResourceClient* client = webplugin_->GetResourceClient(params.id);
226 if (!client)
227 return;
229 client->DidReceiveResponse(params.mime_type,
230 params.headers,
231 params.expected_length,
232 params.last_modified,
233 params.request_is_seekable);
236 void WebPluginDelegateStub::OnDidReceiveData(int id,
237 const std::vector<char>& buffer,
238 int data_offset) {
239 WebPluginResourceClient* client = webplugin_->GetResourceClient(id);
240 if (!client)
241 return;
243 client->DidReceiveData(&buffer.front(), static_cast<int>(buffer.size()),
244 data_offset);
247 void WebPluginDelegateStub::OnDidFinishLoading(int id) {
248 WebPluginResourceClient* client = webplugin_->GetResourceClient(id);
249 if (!client)
250 return;
252 client->DidFinishLoading(id);
255 void WebPluginDelegateStub::OnDidFail(int id) {
256 WebPluginResourceClient* client = webplugin_->GetResourceClient(id);
257 if (!client)
258 return;
260 client->DidFail(id);
263 void WebPluginDelegateStub::OnDidFinishLoadWithReason(
264 const GURL& url, int reason, int notify_id) {
265 delegate_->DidFinishLoadWithReason(url, reason, notify_id);
268 void WebPluginDelegateStub::OnSetFocus(bool focused) {
269 delegate_->SetFocus(focused);
270 #if defined(OS_WIN) && !defined(USE_AURA)
271 if (focused)
272 webplugin_->UpdateIMEStatus();
273 #endif
276 void WebPluginDelegateStub::OnHandleInputEvent(
277 const blink::WebInputEvent *event,
278 bool* handled,
279 WebCursor* cursor) {
280 WebCursor::CursorInfo cursor_info;
281 *handled = delegate_->HandleInputEvent(*event, &cursor_info);
282 cursor->InitFromCursorInfo(cursor_info);
285 void WebPluginDelegateStub::OnPaint(const gfx::Rect& damaged_rect) {
286 webplugin_->Paint(damaged_rect);
289 void WebPluginDelegateStub::OnDidPaint() {
290 webplugin_->DidPaint();
293 void WebPluginDelegateStub::OnUpdateGeometry(
294 const PluginMsg_UpdateGeometry_Param& param) {
295 webplugin_->UpdateGeometry(
296 param.window_rect, param.clip_rect,
297 param.windowless_buffer0, param.windowless_buffer1,
298 param.windowless_buffer_index);
301 void WebPluginDelegateStub::OnGetPluginScriptableObject(int* route_id) {
302 NPObject* object = delegate_->GetPluginScriptableObject();
303 if (!object) {
304 *route_id = MSG_ROUTING_NONE;
305 return;
308 *route_id = channel_->GenerateRouteID();
309 // We will delete the stub immediately before calling PluginDestroyed on the
310 // delegate. It will delete itself sooner if the proxy tells it that it has
311 // been released, or if the channel to the proxy is closed.
312 NPObjectStub* scriptable_stub = new NPObjectStub(
313 object, channel_.get(), *route_id,
314 webplugin_->host_render_view_routing_id(), page_url_);
315 plugin_scriptable_object_ = scriptable_stub->AsWeakPtr();
317 // Release ref added by GetPluginScriptableObject (our stub holds its own).
318 WebBindings::releaseObject(object);
321 void WebPluginDelegateStub::OnGetFormValue(base::string16* value,
322 bool* success) {
323 *success = false;
324 if (!delegate_)
325 return;
326 *success = delegate_->GetFormValue(value);
329 void WebPluginDelegateStub::OnSendJavaScriptStream(const GURL& url,
330 const std::string& result,
331 bool success,
332 int notify_id) {
333 delegate_->SendJavaScriptStream(url, result, success, notify_id);
336 void WebPluginDelegateStub::OnSetContentAreaFocus(bool has_focus) {
337 if (delegate_)
338 delegate_->SetContentAreaHasFocus(has_focus);
341 #if defined(OS_WIN) && !defined(USE_AURA)
342 void WebPluginDelegateStub::OnImeCompositionUpdated(
343 const base::string16& text,
344 const std::vector<int>& clauses,
345 const std::vector<int>& target,
346 int cursor_position) {
347 if (delegate_)
348 delegate_->ImeCompositionUpdated(text, clauses, target, cursor_position);
349 webplugin_->UpdateIMEStatus();
352 void WebPluginDelegateStub::OnImeCompositionCompleted(
353 const base::string16& text) {
354 if (delegate_)
355 delegate_->ImeCompositionCompleted(text);
357 #endif
359 #if defined(OS_MACOSX)
360 void WebPluginDelegateStub::OnSetWindowFocus(bool has_focus) {
361 if (delegate_)
362 delegate_->SetWindowHasFocus(has_focus);
365 void WebPluginDelegateStub::OnContainerHidden() {
366 if (delegate_)
367 delegate_->SetContainerVisibility(false);
370 void WebPluginDelegateStub::OnContainerShown(gfx::Rect window_frame,
371 gfx::Rect view_frame,
372 bool has_focus) {
373 if (delegate_) {
374 delegate_->WindowFrameChanged(window_frame, view_frame);
375 delegate_->SetContainerVisibility(true);
376 delegate_->SetWindowHasFocus(has_focus);
380 void WebPluginDelegateStub::OnWindowFrameChanged(const gfx::Rect& window_frame,
381 const gfx::Rect& view_frame) {
382 if (delegate_)
383 delegate_->WindowFrameChanged(window_frame, view_frame);
386 void WebPluginDelegateStub::OnImeCompositionCompleted(
387 const base::string16& text) {
388 if (delegate_)
389 delegate_->ImeCompositionCompleted(text);
391 #endif // OS_MACOSX
393 void WebPluginDelegateStub::OnDidReceiveManualResponse(
394 const GURL& url,
395 const PluginMsg_DidReceiveResponseParams& params) {
396 delegate_->DidReceiveManualResponse(url, params.mime_type, params.headers,
397 params.expected_length,
398 params.last_modified);
401 void WebPluginDelegateStub::OnDidReceiveManualData(
402 const std::vector<char>& buffer) {
403 delegate_->DidReceiveManualData(&buffer.front(),
404 static_cast<int>(buffer.size()));
407 void WebPluginDelegateStub::OnDidFinishManualLoading() {
408 delegate_->DidFinishManualLoading();
411 void WebPluginDelegateStub::OnDidManualLoadFail() {
412 delegate_->DidManualLoadFail();
415 void WebPluginDelegateStub::OnHandleURLRequestReply(
416 unsigned long resource_id, const GURL& url, int notify_id) {
417 WebPluginResourceClient* resource_client =
418 delegate_->CreateResourceClient(resource_id, url, notify_id);
419 webplugin_->OnResourceCreated(resource_id, resource_client);
422 void WebPluginDelegateStub::OnHTTPRangeRequestReply(
423 unsigned long resource_id, int range_request_id) {
424 WebPluginResourceClient* resource_client =
425 delegate_->CreateSeekableResourceClient(resource_id, range_request_id);
426 webplugin_->OnResourceCreated(resource_id, resource_client);
429 void WebPluginDelegateStub::OnFetchURL(
430 const PluginMsg_FetchURL_Params& params) {
431 const char* data = NULL;
432 if (params.post_data.size())
433 data = &params.post_data[0];
435 delegate_->FetchURL(params.resource_id,
436 params.notify_id,
437 params.url,
438 params.first_party_for_cookies,
439 params.method,
440 data,
441 static_cast<unsigned int>(params.post_data.size()),
442 Referrer(params.referrer, params.referrer_policy),
443 params.notify_redirect,
444 params.is_plugin_src_load,
445 channel_->renderer_id(),
446 params.render_frame_id,
447 webplugin_->host_render_view_routing_id());
450 } // namespace content