diff options
Diffstat (limited to 'webkit/glue/plugins/webplugin_delegate_impl.cc')
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl.cc | 304 |
1 files changed, 304 insertions, 0 deletions
diff --git a/webkit/glue/plugins/webplugin_delegate_impl.cc b/webkit/glue/plugins/webplugin_delegate_impl.cc new file mode 100644 index 0000000..e3e4f9d --- /dev/null +++ b/webkit/glue/plugins/webplugin_delegate_impl.cc @@ -0,0 +1,304 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "webkit/glue/plugins/webplugin_delegate_impl.h" + +#include <string> +#include <vector> + +#include "base/file_util.h" +#include "base/message_loop.h" +#include "base/process_util.h" +#include "base/scoped_ptr.h" +#include "base/string_util.h" +#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" +#include "webkit/glue/plugins/plugin_constants_win.h" +#include "webkit/glue/plugins/plugin_instance.h" +#include "webkit/glue/plugins/plugin_lib.h" +#include "webkit/glue/plugins/plugin_list.h" +#include "webkit/glue/plugins/plugin_stream_url.h" +#include "webkit/glue/webkit_glue.h" + +using webkit_glue::WebPlugin; +using webkit_glue::WebPluginDelegate; +using webkit_glue::WebPluginResourceClient; +using WebKit::WebCursorInfo; +using WebKit::WebKeyboardEvent; +using WebKit::WebInputEvent; +using WebKit::WebMouseEvent; + +WebPluginDelegateImpl* WebPluginDelegateImpl::Create( + const FilePath& filename, + const std::string& mime_type, + gfx::PluginWindowHandle containing_view) { + scoped_refptr<NPAPI::PluginLib> plugin_lib( + NPAPI::PluginLib::CreatePluginLib(filename)); + if (plugin_lib.get() == NULL) + return NULL; + + NPError err = plugin_lib->NP_Initialize(); + if (err != NPERR_NO_ERROR) + return NULL; + + scoped_refptr<NPAPI::PluginInstance> instance( + plugin_lib->CreateInstance(mime_type)); + return new WebPluginDelegateImpl(containing_view, instance.get()); +} + +void WebPluginDelegateImpl::PluginDestroyed() { + if (handle_event_depth_) { + MessageLoop::current()->DeleteSoon(FROM_HERE, this); + } else { + delete this; + } +} + +bool WebPluginDelegateImpl::Initialize( + const GURL& url, + const std::vector<std::string>& arg_names, + const std::vector<std::string>& arg_values, + WebPlugin* plugin, + bool load_manually) { + plugin_ = plugin; + + instance_->set_web_plugin(plugin_); + if (quirks_ & PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES) { + NPAPI::PluginLib* plugin_lib = instance()->plugin_lib(); + if (plugin_lib->instance_count() > 1) { + return false; + } + } + + if (quirks_ & PLUGIN_QUIRK_DIE_AFTER_UNLOAD) + webkit_glue::SetForcefullyTerminatePluginProcess(true); + + int argc = 0; + scoped_array<char*> argn(new char*[arg_names.size()]); + scoped_array<char*> argv(new char*[arg_names.size()]); + for (size_t i = 0; i < arg_names.size(); ++i) { + if (quirks_ & PLUGIN_QUIRK_NO_WINDOWLESS && + LowerCaseEqualsASCII(arg_names[i], "windowlessvideo")) { + continue; + } + argn[argc] = const_cast<char*>(arg_names[i].c_str()); + argv[argc] = const_cast<char*>(arg_values[i].c_str()); + argc++; + } + + creation_succeeded_ = instance_->Start( + url, argn.get(), argv.get(), argc, load_manually); + if (!creation_succeeded_) + return false; + + windowless_ = instance_->windowless(); + if (!windowless_) { + if (!WindowedCreatePlugin()) + return false; + } else { + // For windowless plugins we should set the containing window handle + // as the instance window handle. This is what Safari does. Not having + // a valid window handle causes subtle bugs with plugins which retrieve + // the window handle and validate the same. The window handle can be + // retrieved via NPN_GetValue of NPNVnetscapeWindow. + instance_->set_window_handle(parent_); + } + + bool should_load = PlatformInitialize(); + + plugin_url_ = url.spec(); + + return should_load; +} + +void WebPluginDelegateImpl::DestroyInstance() { + if (instance_ && (instance_->npp()->ndata != NULL)) { + // Shutdown all streams before destroying so that + // no streams are left "in progress". Need to do + // this before calling set_web_plugin(NULL) because the + // instance uses the helper to do the download. + instance_->CloseStreams(); + + window_.window = NULL; + if (creation_succeeded_ && + !(quirks_ & PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY)) { + instance_->NPP_SetWindow(&window_); + } + + instance_->NPP_Destroy(); + + instance_->set_web_plugin(NULL); + + PlatformDestroyInstance(); + + instance_ = 0; + } +} + +void WebPluginDelegateImpl::UpdateGeometry( + const gfx::Rect& window_rect, + const gfx::Rect& clip_rect) { + + if (first_set_window_call_) { + first_set_window_call_ = false; + // Plugins like media player on Windows have a bug where in they handle the + // first geometry update and ignore the rest resulting in painting issues. + // This quirk basically ignores the first set window call sequence for + // these plugins and has been tested for Windows plugins only. + if (quirks_ & PLUGIN_QUIRK_IGNORE_FIRST_SETWINDOW_CALL) + return; + } + + if (windowless_) { + WindowlessUpdateGeometry(window_rect, clip_rect); + } else { + WindowedUpdateGeometry(window_rect, clip_rect); + } +} + +void WebPluginDelegateImpl::SetFocus(bool focused) { + DCHECK(windowless_); + // This is called when internal WebKit focus (the focused element on the page) + // changes, but plugins need to know about OS-level focus, so we have an extra + // layer of focus tracking. + // + // On Windows, historically browsers did not set focus events to windowless + // plugins when the toplevel window focus changes. Sending such focus events + // breaks full screen mode in Flash because it will come out of full screen + // mode when it loses focus, and its full screen window causes the browser to + // lose focus. + has_webkit_focus_ = focused; +#ifndef OS_WIN + if (containing_view_has_focus_) + SetPluginHasFocus(focused); +#else + SetPluginHasFocus(focused); +#endif +} + +void WebPluginDelegateImpl::SetPluginHasFocus(bool focused) { + if (focused == plugin_has_focus_) + return; + if (PlatformSetPluginHasFocus(focused)) + plugin_has_focus_ = focused; +} + +void WebPluginDelegateImpl::SetContentAreaHasFocus(bool has_focus) { + containing_view_has_focus_ = has_focus; + if (!windowless_) + return; +#ifndef OS_WIN // See SetFocus above. + SetPluginHasFocus(containing_view_has_focus_ && has_webkit_focus_); +#endif +} + +NPObject* WebPluginDelegateImpl::GetPluginScriptableObject() { + return instance_->GetPluginScriptableObject(); +} + +void WebPluginDelegateImpl::DidFinishLoadWithReason(const GURL& url, + NPReason reason, + int notify_id) { + if (quirks_ & PLUGIN_QUIRK_ALWAYS_NOTIFY_SUCCESS && + reason == NPRES_NETWORK_ERR) { + // Flash needs this or otherwise it unloads the launching swf object. + reason = NPRES_DONE; + } + + instance()->DidFinishLoadWithReason(url, reason, notify_id); +} + +int WebPluginDelegateImpl::GetProcessId() { + // We are in process, so the plugin pid is this current process pid. + return base::GetCurrentProcId(); +} + +void WebPluginDelegateImpl::SendJavaScriptStream(const GURL& url, + const std::string& result, + bool success, + int notify_id) { + instance()->SendJavaScriptStream(url, result, success, notify_id); +} + +void WebPluginDelegateImpl::DidReceiveManualResponse( + const GURL& url, const std::string& mime_type, + const std::string& headers, uint32 expected_length, uint32 last_modified) { + if (!windowless_) { + // Calling NPP_WriteReady before NPP_SetWindow causes movies to not load in + // Flash. See http://b/issue?id=892174. + DCHECK(windowed_did_set_window_); + } + + instance()->DidReceiveManualResponse(url, mime_type, headers, + expected_length, last_modified); +} + +void WebPluginDelegateImpl::DidReceiveManualData(const char* buffer, + int length) { + instance()->DidReceiveManualData(buffer, length); +} + +void WebPluginDelegateImpl::DidFinishManualLoading() { + instance()->DidFinishManualLoading(); +} + +void WebPluginDelegateImpl::DidManualLoadFail() { + instance()->DidManualLoadFail(); +} + +FilePath WebPluginDelegateImpl::GetPluginPath() { + return instance()->plugin_lib()->plugin_info().path; +} + +void WebPluginDelegateImpl::WindowedUpdateGeometry( + const gfx::Rect& window_rect, + const gfx::Rect& clip_rect) { + if (WindowedReposition(window_rect, clip_rect) || + !windowed_did_set_window_) { + // Let the plugin know that it has been moved + WindowedSetWindow(); + } +} + +bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event, + WebCursorInfo* cursor_info) { + DCHECK(windowless_) << "events should only be received in windowless mode"; + + bool pop_user_gesture = false; + if (IsUserGesture(event)) { + pop_user_gesture = true; + instance()->PushPopupsEnabledState(true); + } + + bool handled = PlatformHandleInputEvent(event, cursor_info); + + if (pop_user_gesture) { + instance()->PopPopupsEnabledState(); + } + + return handled; +} + +bool WebPluginDelegateImpl::IsUserGesture(const WebInputEvent& event) { + switch (event.type) { + case WebInputEvent::MouseDown: + case WebInputEvent::MouseUp: + case WebInputEvent::KeyDown: + case WebInputEvent::KeyUp: + return true; + default: + return false; + } + return false; +} + +WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient( + unsigned long resource_id, const GURL& url, int notify_id) { + return instance()->CreateStream( + resource_id, url, std::string(), notify_id); +} + +WebPluginResourceClient* WebPluginDelegateImpl::CreateSeekableResourceClient( + unsigned long resource_id, int range_request_id) { + return instance()->GetRangeRequest(range_request_id); +} |