| 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 |