// Copyright (c) 2006-2008 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 #include #include "base/file_util.h" #include "base/message_loop.h" #include "base/process_util.h" #include "base/scoped_ptr.h" #include "base/stats_counters.h" #include "base/string_util.h" #include "webkit/api/public/WebInputEvent.h" #include "webkit/glue/glue_util.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 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 instance = plugin_lib->CreateInstance(mime_type); return new WebPluginDelegateImpl(containing_view, instance.get()); } bool WebPluginDelegateImpl::Initialize( const GURL& url, const std::vector& arg_names, const std::vector& 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 argn(new char*[arg_names.size()]); scoped_array 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(arg_names[i].c_str()); argv[argc] = const_cast(arg_values[i].c_str()); argc++; } bool start_result = instance_->Start( url, argn.get(), argv.get(), argc, load_manually); if (!start_result) 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 retreive // the window handle and validate the same. The window handle can be // retreived via NPN_GetValue of NPNVnetscapeWindow. instance_->set_window_handle(parent_); } PlatformInitialize(); plugin_url_ = url.spec(); return true; } 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 (!(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 (windowless_) { WindowlessUpdateGeometry(window_rect, clip_rect); } else { WindowedUpdateGeometry(window_rect, clip_rect); } } NPObject* WebPluginDelegateImpl::GetPluginScriptableObject() { return instance_->GetPluginScriptableObject(); } void WebPluginDelegateImpl::DidFinishLoadWithReason(const GURL& url, NPReason reason, intptr_t notify_data) { instance()->DidFinishLoadWithReason( url, reason, reinterpret_cast(notify_data)); } 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, bool notify_needed, intptr_t notify_data) { instance()->SendJavaScriptStream(url, result, success, notify_needed, notify_data); } 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(); } } WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient( int resource_id, const GURL& url, bool notify_needed, intptr_t notify_data, intptr_t existing_stream) { // Stream already exists. This typically happens for range requests // initiated via NPN_RequestRead. if (existing_stream) { NPAPI::PluginStream* plugin_stream = reinterpret_cast(existing_stream); return plugin_stream->AsResourceClient(); } std::string mime_type; NPAPI::PluginStreamUrl *stream = instance()->CreateStream( resource_id, url, mime_type, notify_needed, reinterpret_cast(notify_data)); return stream; }