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/child/npapi/webplugin_delegate_impl.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/process/process_handle.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "content/child/npapi/plugin_instance.h"
16 #include "content/child/npapi/plugin_lib.h"
17 #include "content/child/npapi/plugin_stream_url.h"
18 #include "content/child/npapi/plugin_url_fetcher.h"
19 #include "third_party/WebKit/public/web/WebInputEvent.h"
21 using blink::WebCursorInfo
;
22 using blink::WebInputEvent
;
26 WebPluginDelegateImpl
* WebPluginDelegateImpl::Create(
28 const base::FilePath
& filename
,
29 const std::string
& mime_type
) {
30 scoped_refptr
<PluginLib
> plugin_lib(PluginLib::CreatePluginLib(filename
));
31 if (plugin_lib
.get() == NULL
)
34 NPError err
= plugin_lib
->NP_Initialize();
35 if (err
!= NPERR_NO_ERROR
)
38 scoped_refptr
<PluginInstance
> instance(plugin_lib
->CreateInstance(mime_type
));
39 return new WebPluginDelegateImpl(plugin
, instance
.get());
42 void WebPluginDelegateImpl::PluginDestroyed() {
43 if (handle_event_depth_
) {
44 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
50 bool WebPluginDelegateImpl::Initialize(
52 const std::vector
<std::string
>& arg_names
,
53 const std::vector
<std::string
>& arg_values
,
55 if (instance_
->plugin_lib()->plugin_info().name
.find(
56 base::ASCIIToUTF16("QuickTime Plug-in")) != std::wstring::npos
) {
57 quirks_
|= PLUGIN_QUIRK_COPY_STREAM_DATA
;
60 instance_
->set_web_plugin(plugin_
);
61 if (quirks_
& PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES
) {
62 PluginLib
* plugin_lib
= instance()->plugin_lib();
63 if (plugin_lib
->instance_count() > 1) {
69 scoped_ptr
<char*[]> argn(new char*[arg_names
.size()]);
70 scoped_ptr
<char*[]> argv(new char*[arg_names
.size()]);
71 for (size_t i
= 0; i
< arg_names
.size(); ++i
) {
72 if (quirks_
& PLUGIN_QUIRK_NO_WINDOWLESS
&&
73 LowerCaseEqualsASCII(arg_names
[i
], "windowlessvideo")) {
76 argn
[argc
] = const_cast<char*>(arg_names
[i
].c_str());
77 argv
[argc
] = const_cast<char*>(arg_values
[i
].c_str());
81 creation_succeeded_
= instance_
->Start(
82 url
, argn
.get(), argv
.get(), argc
, load_manually
);
83 if (!creation_succeeded_
) {
84 VLOG(1) << "Couldn't start plugin instance";
88 windowless_
= instance_
->windowless();
90 if (!WindowedCreatePlugin()) {
91 VLOG(1) << "Couldn't create windowed plugin";
96 bool should_load
= PlatformInitialize();
98 plugin_url_
= url
.spec();
103 void WebPluginDelegateImpl::DestroyInstance() {
104 if (instance_
.get() && (instance_
->npp()->ndata
!= NULL
)) {
105 // Shutdown all streams before destroying so that
106 // no streams are left "in progress". Need to do
107 // this before calling set_web_plugin(NULL) because the
108 // instance uses the helper to do the download.
109 instance_
->CloseStreams();
111 window_
.window
= NULL
;
112 if (creation_succeeded_
&&
113 !(quirks_
& PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY
)) {
114 instance_
->NPP_SetWindow(&window_
);
117 instance_
->NPP_Destroy();
119 instance_
->set_web_plugin(NULL
);
121 PlatformDestroyInstance();
127 void WebPluginDelegateImpl::UpdateGeometry(
128 const gfx::Rect
& window_rect
,
129 const gfx::Rect
& clip_rect
) {
131 if (first_set_window_call_
) {
132 first_set_window_call_
= false;
133 // Plugins like media player on Windows have a bug where in they handle the
134 // first geometry update and ignore the rest resulting in painting issues.
135 // This quirk basically ignores the first set window call sequence for
136 // these plugins and has been tested for Windows plugins only.
137 if (quirks_
& PLUGIN_QUIRK_IGNORE_FIRST_SETWINDOW_CALL
)
142 WindowlessUpdateGeometry(window_rect
, clip_rect
);
144 WindowedUpdateGeometry(window_rect
, clip_rect
);
148 void WebPluginDelegateImpl::SetFocus(bool focused
) {
150 // This is called when internal WebKit focus (the focused element on the page)
151 // changes, but plugins need to know about OS-level focus, so we have an extra
152 // layer of focus tracking.
154 // On Windows, historically browsers did not set focus events to windowless
155 // plugins when the toplevel window focus changes. Sending such focus events
156 // breaks full screen mode in Flash because it will come out of full screen
157 // mode when it loses focus, and its full screen window causes the browser to
159 has_webkit_focus_
= focused
;
161 if (containing_view_has_focus_
)
162 SetPluginHasFocus(focused
);
164 SetPluginHasFocus(focused
);
168 void WebPluginDelegateImpl::SetPluginHasFocus(bool focused
) {
169 if (focused
== plugin_has_focus_
)
171 if (PlatformSetPluginHasFocus(focused
))
172 plugin_has_focus_
= focused
;
175 void WebPluginDelegateImpl::SetContentAreaHasFocus(bool has_focus
) {
176 containing_view_has_focus_
= has_focus
;
179 #if !defined(OS_WIN) // See SetFocus above.
180 SetPluginHasFocus(containing_view_has_focus_
&& has_webkit_focus_
);
184 NPObject
* WebPluginDelegateImpl::GetPluginScriptableObject() {
185 return instance_
->GetPluginScriptableObject();
188 NPP
WebPluginDelegateImpl::GetPluginNPP() {
189 return instance_
->npp();
192 bool WebPluginDelegateImpl::GetFormValue(base::string16
* value
) {
193 return instance_
->GetFormValue(value
);
196 void WebPluginDelegateImpl::DidFinishLoadWithReason(const GURL
& url
,
199 if (quirks_
& PLUGIN_QUIRK_ALWAYS_NOTIFY_SUCCESS
&&
200 reason
== NPRES_NETWORK_ERR
) {
201 // Flash needs this or otherwise it unloads the launching swf object.
205 instance()->DidFinishLoadWithReason(url
, reason
, notify_id
);
208 int WebPluginDelegateImpl::GetProcessId() {
209 // We are in process, so the plugin pid is this current process pid.
210 return base::GetCurrentProcId();
213 void WebPluginDelegateImpl::SendJavaScriptStream(const GURL
& url
,
214 const std::string
& result
,
217 instance()->SendJavaScriptStream(url
, result
, success
, notify_id
);
220 void WebPluginDelegateImpl::DidReceiveManualResponse(
221 const GURL
& url
, const std::string
& mime_type
,
222 const std::string
& headers
, uint32 expected_length
, uint32 last_modified
) {
224 // Calling NPP_WriteReady before NPP_SetWindow causes movies to not load in
225 // Flash. See http://b/issue?id=892174.
226 DCHECK(windowed_did_set_window_
);
229 instance()->DidReceiveManualResponse(url
, mime_type
, headers
,
230 expected_length
, last_modified
);
233 void WebPluginDelegateImpl::DidReceiveManualData(const char* buffer
,
235 instance()->DidReceiveManualData(buffer
, length
);
238 void WebPluginDelegateImpl::DidFinishManualLoading() {
239 instance()->DidFinishManualLoading();
242 void WebPluginDelegateImpl::DidManualLoadFail() {
243 instance()->DidManualLoadFail();
246 base::FilePath
WebPluginDelegateImpl::GetPluginPath() {
247 return instance()->plugin_lib()->plugin_info().path
;
250 void WebPluginDelegateImpl::WindowedUpdateGeometry(
251 const gfx::Rect
& window_rect
,
252 const gfx::Rect
& clip_rect
) {
253 if (WindowedReposition(window_rect
, clip_rect
) ||
254 !windowed_did_set_window_
) {
255 // Let the plugin know that it has been moved
260 bool WebPluginDelegateImpl::HandleInputEvent(
261 const WebInputEvent
& event
,
262 WebCursor::CursorInfo
* cursor_info
) {
263 DCHECK(windowless_
) << "events should only be received in windowless mode";
265 bool pop_user_gesture
= false;
266 if (IsUserGesture(event
)) {
267 pop_user_gesture
= true;
268 instance()->PushPopupsEnabledState(true);
271 bool handled
= PlatformHandleInputEvent(event
, cursor_info
);
273 if (pop_user_gesture
) {
274 instance()->PopPopupsEnabledState();
280 bool WebPluginDelegateImpl::IsUserGesture(const WebInputEvent
& event
) {
281 switch (event
.type
) {
282 case WebInputEvent::MouseDown
:
283 case WebInputEvent::MouseUp
:
284 case WebInputEvent::KeyDown
:
285 case WebInputEvent::KeyUp
:
292 WebPluginResourceClient
* WebPluginDelegateImpl::CreateResourceClient(
293 unsigned long resource_id
, const GURL
& url
, int notify_id
) {
294 return instance()->CreateStream(
295 resource_id
, url
, std::string(), notify_id
);
298 WebPluginResourceClient
* WebPluginDelegateImpl::CreateSeekableResourceClient(
299 unsigned long resource_id
, int range_request_id
) {
300 WebPluginResourceClient
* resource_client
= instance()->GetRangeRequest(
303 resource_client
->AddRangeRequestResourceId(resource_id
);
304 return resource_client
;
307 void WebPluginDelegateImpl::FetchURL(unsigned long resource_id
,
310 const GURL
& first_party_for_cookies
,
311 const std::string
& method
,
314 const Referrer
& referrer
,
315 bool notify_redirects
,
316 bool is_plugin_src_load
,
319 int render_view_id
) {
320 // TODO(jam): once we switch over to resource loading always happening in this
321 // code path, remove WebPluginResourceClient abstraction.
322 PluginStreamUrl
* plugin_stream
= instance()->CreateStream(
323 resource_id
, url
, std::string(), notify_id
);
325 bool copy_stream_data
= !!(quirks_
& PLUGIN_QUIRK_COPY_STREAM_DATA
);
326 plugin_stream
->SetPluginURLFetcher(new PluginURLFetcher(
327 plugin_stream
, url
, first_party_for_cookies
, method
, buf
, len
,
328 referrer
, std::string(), notify_redirects
, is_plugin_src_load
, origin_pid
,
329 render_frame_id
, render_view_id
, resource_id
, copy_stream_data
));
332 } // namespace content