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