OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 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 "webkit/glue/plugins/webplugin_delegate_impl.h" | |
6 | |
7 #include <string> | |
8 #include <vector> | |
9 | |
10 #include "base/file_util.h" | |
11 #include "base/message_loop.h" | |
12 #include "base/process_util.h" | |
13 #include "base/scoped_ptr.h" | |
14 #include "base/string_util.h" | |
15 #include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" | |
16 #include "webkit/glue/plugins/plugin_constants_win.h" | |
17 #include "webkit/glue/plugins/plugin_instance.h" | |
18 #include "webkit/glue/plugins/plugin_lib.h" | |
19 #include "webkit/glue/plugins/plugin_list.h" | |
20 #include "webkit/glue/plugins/plugin_stream_url.h" | |
21 #include "webkit/glue/webkit_glue.h" | |
22 | |
23 using webkit_glue::WebPlugin; | |
24 using webkit_glue::WebPluginDelegate; | |
25 using webkit_glue::WebPluginResourceClient; | |
26 using WebKit::WebCursorInfo; | |
27 using WebKit::WebKeyboardEvent; | |
28 using WebKit::WebInputEvent; | |
29 using WebKit::WebMouseEvent; | |
30 | |
31 WebPluginDelegateImpl* WebPluginDelegateImpl::Create( | |
32 const FilePath& filename, | |
33 const std::string& mime_type, | |
34 gfx::PluginWindowHandle containing_view) { | |
35 scoped_refptr<NPAPI::PluginLib> plugin_lib( | |
36 NPAPI::PluginLib::CreatePluginLib(filename)); | |
37 if (plugin_lib.get() == NULL) | |
38 return NULL; | |
39 | |
40 NPError err = plugin_lib->NP_Initialize(); | |
41 if (err != NPERR_NO_ERROR) | |
42 return NULL; | |
43 | |
44 scoped_refptr<NPAPI::PluginInstance> instance( | |
45 plugin_lib->CreateInstance(mime_type)); | |
46 return new WebPluginDelegateImpl(containing_view, instance.get()); | |
47 } | |
48 | |
49 void WebPluginDelegateImpl::PluginDestroyed() { | |
50 if (handle_event_depth_) { | |
51 MessageLoop::current()->DeleteSoon(FROM_HERE, this); | |
52 } else { | |
53 delete this; | |
54 } | |
55 } | |
56 | |
57 bool WebPluginDelegateImpl::Initialize( | |
58 const GURL& url, | |
59 const std::vector<std::string>& arg_names, | |
60 const std::vector<std::string>& arg_values, | |
61 WebPlugin* plugin, | |
62 bool load_manually) { | |
63 plugin_ = plugin; | |
64 | |
65 instance_->set_web_plugin(plugin_); | |
66 if (quirks_ & PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES) { | |
67 NPAPI::PluginLib* plugin_lib = instance()->plugin_lib(); | |
68 if (plugin_lib->instance_count() > 1) { | |
69 return false; | |
70 } | |
71 } | |
72 | |
73 if (quirks_ & PLUGIN_QUIRK_DIE_AFTER_UNLOAD) | |
74 webkit_glue::SetForcefullyTerminatePluginProcess(true); | |
75 | |
76 int argc = 0; | |
77 scoped_array<char*> argn(new char*[arg_names.size()]); | |
78 scoped_array<char*> argv(new char*[arg_names.size()]); | |
79 for (size_t i = 0; i < arg_names.size(); ++i) { | |
80 if (quirks_ & PLUGIN_QUIRK_NO_WINDOWLESS && | |
81 LowerCaseEqualsASCII(arg_names[i], "windowlessvideo")) { | |
82 continue; | |
83 } | |
84 argn[argc] = const_cast<char*>(arg_names[i].c_str()); | |
85 argv[argc] = const_cast<char*>(arg_values[i].c_str()); | |
86 argc++; | |
87 } | |
88 | |
89 creation_succeeded_ = instance_->Start( | |
90 url, argn.get(), argv.get(), argc, load_manually); | |
91 if (!creation_succeeded_) | |
92 return false; | |
93 | |
94 windowless_ = instance_->windowless(); | |
95 if (!windowless_) { | |
96 if (!WindowedCreatePlugin()) | |
97 return false; | |
98 } else { | |
99 // For windowless plugins we should set the containing window handle | |
100 // as the instance window handle. This is what Safari does. Not having | |
101 // a valid window handle causes subtle bugs with plugins which retrieve | |
102 // the window handle and validate the same. The window handle can be | |
103 // retrieved via NPN_GetValue of NPNVnetscapeWindow. | |
104 instance_->set_window_handle(parent_); | |
105 } | |
106 | |
107 bool should_load = PlatformInitialize(); | |
108 | |
109 plugin_url_ = url.spec(); | |
110 | |
111 return should_load; | |
112 } | |
113 | |
114 void WebPluginDelegateImpl::DestroyInstance() { | |
115 if (instance_ && (instance_->npp()->ndata != NULL)) { | |
116 // Shutdown all streams before destroying so that | |
117 // no streams are left "in progress". Need to do | |
118 // this before calling set_web_plugin(NULL) because the | |
119 // instance uses the helper to do the download. | |
120 instance_->CloseStreams(); | |
121 | |
122 window_.window = NULL; | |
123 if (creation_succeeded_ && | |
124 !(quirks_ & PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY)) { | |
125 instance_->NPP_SetWindow(&window_); | |
126 } | |
127 | |
128 instance_->NPP_Destroy(); | |
129 | |
130 instance_->set_web_plugin(NULL); | |
131 | |
132 PlatformDestroyInstance(); | |
133 | |
134 instance_ = 0; | |
135 } | |
136 } | |
137 | |
138 void WebPluginDelegateImpl::UpdateGeometry( | |
139 const gfx::Rect& window_rect, | |
140 const gfx::Rect& clip_rect) { | |
141 | |
142 if (first_set_window_call_) { | |
143 first_set_window_call_ = false; | |
144 // Plugins like media player on Windows have a bug where in they handle the | |
145 // first geometry update and ignore the rest resulting in painting issues. | |
146 // This quirk basically ignores the first set window call sequence for | |
147 // these plugins and has been tested for Windows plugins only. | |
148 if (quirks_ & PLUGIN_QUIRK_IGNORE_FIRST_SETWINDOW_CALL) | |
149 return; | |
150 } | |
151 | |
152 if (windowless_) { | |
153 WindowlessUpdateGeometry(window_rect, clip_rect); | |
154 } else { | |
155 WindowedUpdateGeometry(window_rect, clip_rect); | |
156 } | |
157 } | |
158 | |
159 void WebPluginDelegateImpl::SetFocus(bool focused) { | |
160 DCHECK(windowless_); | |
161 // This is called when internal WebKit focus (the focused element on the page) | |
162 // changes, but plugins need to know about OS-level focus, so we have an extra | |
163 // layer of focus tracking. | |
164 // | |
165 // On Windows, historically browsers did not set focus events to windowless | |
166 // plugins when the toplevel window focus changes. Sending such focus events | |
167 // breaks full screen mode in Flash because it will come out of full screen | |
168 // mode when it loses focus, and its full screen window causes the browser to | |
169 // lose focus. | |
170 has_webkit_focus_ = focused; | |
171 #ifndef OS_WIN | |
172 if (containing_view_has_focus_) | |
173 SetPluginHasFocus(focused); | |
174 #else | |
175 SetPluginHasFocus(focused); | |
176 #endif | |
177 } | |
178 | |
179 void WebPluginDelegateImpl::SetPluginHasFocus(bool focused) { | |
180 if (focused == plugin_has_focus_) | |
181 return; | |
182 if (PlatformSetPluginHasFocus(focused)) | |
183 plugin_has_focus_ = focused; | |
184 } | |
185 | |
186 void WebPluginDelegateImpl::SetContentAreaHasFocus(bool has_focus) { | |
187 containing_view_has_focus_ = has_focus; | |
188 if (!windowless_) | |
189 return; | |
190 #ifndef OS_WIN // See SetFocus above. | |
191 SetPluginHasFocus(containing_view_has_focus_ && has_webkit_focus_); | |
192 #endif | |
193 } | |
194 | |
195 NPObject* WebPluginDelegateImpl::GetPluginScriptableObject() { | |
196 return instance_->GetPluginScriptableObject(); | |
197 } | |
198 | |
199 void WebPluginDelegateImpl::DidFinishLoadWithReason(const GURL& url, | |
200 NPReason reason, | |
201 int notify_id) { | |
202 if (quirks_ & PLUGIN_QUIRK_ALWAYS_NOTIFY_SUCCESS && | |
203 reason == NPRES_NETWORK_ERR) { | |
204 // Flash needs this or otherwise it unloads the launching swf object. | |
205 reason = NPRES_DONE; | |
206 } | |
207 | |
208 instance()->DidFinishLoadWithReason(url, reason, notify_id); | |
209 } | |
210 | |
211 int WebPluginDelegateImpl::GetProcessId() { | |
212 // We are in process, so the plugin pid is this current process pid. | |
213 return base::GetCurrentProcId(); | |
214 } | |
215 | |
216 void WebPluginDelegateImpl::SendJavaScriptStream(const GURL& url, | |
217 const std::string& result, | |
218 bool success, | |
219 int notify_id) { | |
220 instance()->SendJavaScriptStream(url, result, success, notify_id); | |
221 } | |
222 | |
223 void WebPluginDelegateImpl::DidReceiveManualResponse( | |
224 const GURL& url, const std::string& mime_type, | |
225 const std::string& headers, uint32 expected_length, uint32 last_modified) { | |
226 if (!windowless_) { | |
227 // Calling NPP_WriteReady before NPP_SetWindow causes movies to not load in | |
228 // Flash. See http://b/issue?id=892174. | |
229 DCHECK(windowed_did_set_window_); | |
230 } | |
231 | |
232 instance()->DidReceiveManualResponse(url, mime_type, headers, | |
233 expected_length, last_modified); | |
234 } | |
235 | |
236 void WebPluginDelegateImpl::DidReceiveManualData(const char* buffer, | |
237 int length) { | |
238 instance()->DidReceiveManualData(buffer, length); | |
239 } | |
240 | |
241 void WebPluginDelegateImpl::DidFinishManualLoading() { | |
242 instance()->DidFinishManualLoading(); | |
243 } | |
244 | |
245 void WebPluginDelegateImpl::DidManualLoadFail() { | |
246 instance()->DidManualLoadFail(); | |
247 } | |
248 | |
249 FilePath WebPluginDelegateImpl::GetPluginPath() { | |
250 return instance()->plugin_lib()->plugin_info().path; | |
251 } | |
252 | |
253 void WebPluginDelegateImpl::WindowedUpdateGeometry( | |
254 const gfx::Rect& window_rect, | |
255 const gfx::Rect& clip_rect) { | |
256 if (WindowedReposition(window_rect, clip_rect) || | |
257 !windowed_did_set_window_) { | |
258 // Let the plugin know that it has been moved | |
259 WindowedSetWindow(); | |
260 } | |
261 } | |
262 | |
263 bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event, | |
264 WebCursorInfo* cursor_info) { | |
265 DCHECK(windowless_) << "events should only be received in windowless mode"; | |
266 | |
267 bool pop_user_gesture = false; | |
268 if (IsUserGesture(event)) { | |
269 pop_user_gesture = true; | |
270 instance()->PushPopupsEnabledState(true); | |
271 } | |
272 | |
273 bool handled = PlatformHandleInputEvent(event, cursor_info); | |
274 | |
275 if (pop_user_gesture) { | |
276 instance()->PopPopupsEnabledState(); | |
277 } | |
278 | |
279 return handled; | |
280 } | |
281 | |
282 bool WebPluginDelegateImpl::IsUserGesture(const WebInputEvent& event) { | |
283 switch (event.type) { | |
284 case WebInputEvent::MouseDown: | |
285 case WebInputEvent::MouseUp: | |
286 case WebInputEvent::KeyDown: | |
287 case WebInputEvent::KeyUp: | |
288 return true; | |
289 default: | |
290 return false; | |
291 } | |
292 return false; | |
293 } | |
294 | |
295 WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient( | |
296 unsigned long resource_id, const GURL& url, int notify_id) { | |
297 return instance()->CreateStream( | |
298 resource_id, url, std::string(), notify_id); | |
299 } | |
300 | |
301 WebPluginResourceClient* WebPluginDelegateImpl::CreateSeekableResourceClient( | |
302 unsigned long resource_id, int range_request_id) { | |
303 return instance()->GetRangeRequest(range_request_id); | |
304 } | |
OLD | NEW |