diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-31 04:32:30 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-31 04:32:30 +0000 |
commit | e612d764f473f54807cb24bedc1b147bb9672ca6 (patch) | |
tree | 361f7de9eb49f81e201b6eefafa6cc8d7061d575 /webkit/glue/plugins | |
parent | 711abaeaaec2bb552d9fe161200778f449fd2da0 (diff) | |
download | chromium_src-e612d764f473f54807cb24bedc1b147bb9672ca6.zip chromium_src-e612d764f473f54807cb24bedc1b147bb9672ca6.tar.gz chromium_src-e612d764f473f54807cb24bedc1b147bb9672ca6.tar.bz2 |
Move plugin-related files in webkit/glue to webkit/glue/plugins to make them
easier to find. With a random subset of files in webkit/glue, it's impossible
to predict where you should find a file. No code change
TEST=none
BUG=none
Review URL: http://codereview.chromium.org/1559008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@43177 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue/plugins')
22 files changed, 2279 insertions, 25 deletions
diff --git a/webkit/glue/plugins/gtk_plugin_container_manager.cc b/webkit/glue/plugins/gtk_plugin_container_manager.cc index 53b6f4d..9d9ee4b 100644 --- a/webkit/glue/plugins/gtk_plugin_container_manager.cc +++ b/webkit/glue/plugins/gtk_plugin_container_manager.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -9,7 +9,7 @@ #include "base/logging.h" #include "gfx/gtk_util.h" #include "webkit/glue/plugins/gtk_plugin_container.h" -#include "webkit/glue/webplugin.h" +#include "webkit/glue/plugins/webplugin.h" GtkWidget* GtkPluginContainerManager::CreatePluginContainer( gfx::PluginWindowHandle id) { diff --git a/webkit/glue/plugins/mac_accelerated_surface_container.cc b/webkit/glue/plugins/mac_accelerated_surface_container.cc index 7d9ae67..8eca9d2 100644 --- a/webkit/glue/plugins/mac_accelerated_surface_container.cc +++ b/webkit/glue/plugins/mac_accelerated_surface_container.cc @@ -6,8 +6,8 @@ #include "app/surface/io_surface_support_mac.h" #include "base/logging.h" -#include "webkit/glue/webplugin.h" #include "webkit/glue/plugins/mac_accelerated_surface_container_manager.h" +#include "webkit/glue/plugins/webplugin.h" MacAcceleratedSurfaceContainer::MacAcceleratedSurfaceContainer() : x_(0), diff --git a/webkit/glue/plugins/mac_accelerated_surface_container_manager.cc b/webkit/glue/plugins/mac_accelerated_surface_container_manager.cc index a149661..635348f 100644 --- a/webkit/glue/plugins/mac_accelerated_surface_container_manager.cc +++ b/webkit/glue/plugins/mac_accelerated_surface_container_manager.cc @@ -5,8 +5,8 @@ #include "webkit/glue/plugins/mac_accelerated_surface_container_manager.h" #include "base/logging.h" -#include "webkit/glue/webplugin.h" #include "webkit/glue/plugins/mac_accelerated_surface_container.h" +#include "webkit/glue/plugins/webplugin.h" MacAcceleratedSurfaceContainerManager::MacAcceleratedSurfaceContainerManager() : current_id_(0) { diff --git a/webkit/glue/plugins/npapi_extension_thunk.cc b/webkit/glue/plugins/npapi_extension_thunk.cc index 0c25655..141d960 100644 --- a/webkit/glue/plugins/npapi_extension_thunk.cc +++ b/webkit/glue/plugins/npapi_extension_thunk.cc @@ -9,10 +9,10 @@ #include "base/utf_string_conversions.h" #include "third_party/npapi/bindings/npapi_extensions.h" #include "webkit/glue/plugins/plugin_instance.h" +#include "webkit/glue/plugins/webplugin.h" +#include "webkit/glue/plugins/webplugin_delegate.h" #include "webkit/glue/scoped_clipboard_writer_glue.h" #include "webkit/glue/webkit_glue.h" -#include "webkit/glue/webplugin.h" -#include "webkit/glue/webplugin_delegate.h" // FindInstance() // Finds a PluginInstance from an NPP. diff --git a/webkit/glue/plugins/plugin_host.cc b/webkit/glue/plugins/plugin_host.cc index b262188..bc2a6f2 100644 --- a/webkit/glue/plugins/plugin_host.cc +++ b/webkit/glue/plugins/plugin_host.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -16,14 +16,14 @@ #include "net/base/net_util.h" #include "third_party/WebKit/WebKit/chromium/public/WebBindings.h" #include "webkit/default_plugin/default_plugin_shared.h" -#include "webkit/glue/webplugininfo.h" -#include "webkit/glue/webplugin_delegate.h" #include "webkit/glue/webkit_glue.h" #include "webkit/glue/plugins/npapi_extension_thunk.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/plugins/webplugin_delegate.h" +#include "webkit/glue/plugins/webplugininfo.h" #include "third_party/npapi/bindings/npapi_extensions.h" #include "third_party/npapi/bindings/npruntime.h" diff --git a/webkit/glue/plugins/plugin_instance.cc b/webkit/glue/plugins/plugin_instance.cc index 037d043..db5ccbf 100644 --- a/webkit/glue/plugins/plugin_instance.cc +++ b/webkit/glue/plugins/plugin_instance.cc @@ -10,13 +10,13 @@ #include "base/message_loop.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" -#include "webkit/glue/webplugin.h" -#include "webkit/glue/webplugin_delegate.h" #include "webkit/glue/webkit_glue.h" #include "webkit/glue/plugins/plugin_host.h" #include "webkit/glue/plugins/plugin_lib.h" #include "webkit/glue/plugins/plugin_stream_url.h" #include "webkit/glue/plugins/plugin_string_stream.h" +#include "webkit/glue/plugins/webplugin.h" +#include "webkit/glue/plugins/webplugin_delegate.h" #include "net/base/escape.h" #if defined(OS_MACOSX) diff --git a/webkit/glue/plugins/plugin_lib.h b/webkit/glue/plugins/plugin_lib.h index 6af2893..dc0b304 100644 --- a/webkit/glue/plugins/plugin_lib.h +++ b/webkit/glue/plugins/plugin_lib.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// 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. @@ -14,7 +14,7 @@ #include "base/ref_counted.h" #include "build/build_config.h" #include "webkit/glue/plugins/plugin_list.h" -#include "webkit/glue/webplugin.h" +#include "webkit/glue/plugins/webplugin.h" struct WebPluginInfo; diff --git a/webkit/glue/plugins/plugin_list.h b/webkit/glue/plugins/plugin_list.h index b80d83b..d4aa31c 100644 --- a/webkit/glue/plugins/plugin_list.h +++ b/webkit/glue/plugins/plugin_list.h @@ -14,7 +14,7 @@ #include "base/file_path.h" #include "base/lock.h" #include "third_party/npapi/bindings/nphostapi.h" -#include "webkit/glue/webplugininfo.h" +#include "webkit/glue/plugins/webplugininfo.h" class GURL; diff --git a/webkit/glue/plugins/plugin_stream_url.cc b/webkit/glue/plugins/plugin_stream_url.cc index 38f7edd..6694139 100644 --- a/webkit/glue/plugins/plugin_stream_url.cc +++ b/webkit/glue/plugins/plugin_stream_url.cc @@ -1,12 +1,12 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// 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/plugin_stream_url.h" -#include "webkit/glue/webplugin.h" #include "webkit/glue/plugins/plugin_host.h" #include "webkit/glue/plugins/plugin_instance.h" +#include "webkit/glue/plugins/webplugin.h" namespace NPAPI { diff --git a/webkit/glue/plugins/plugin_stream_url.h b/webkit/glue/plugins/plugin_stream_url.h index 7d3f59a..688723c 100644 --- a/webkit/glue/plugins/plugin_stream_url.h +++ b/webkit/glue/plugins/plugin_stream_url.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// 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. @@ -6,8 +6,8 @@ #define WEBKIT_GLUE_PLUGIN_PLUGIN_STREAM_URL_H__ -#include "webkit/glue/webplugin.h" #include "webkit/glue/plugins/plugin_stream.h" +#include "webkit/glue/plugins/webplugin.h" #include "googleurl/src/gurl.h" namespace NPAPI { diff --git a/webkit/glue/plugins/webplugin.cc b/webkit/glue/plugins/webplugin.cc new file mode 100644 index 0000000..6443318 --- /dev/null +++ b/webkit/glue/plugins/webplugin.cc @@ -0,0 +1,23 @@ +// 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.h" + +namespace webkit_glue { + +WebPluginGeometry::WebPluginGeometry() + : window(gfx::kNullPluginWindow), + rects_valid(false), + visible(false) { +} + +bool WebPluginGeometry::Equals(const WebPluginGeometry& rhs) const { + return window == rhs.window && + window_rect == rhs.window_rect && + clip_rect == rhs.clip_rect && + cutout_rects == rhs.cutout_rects && + rects_valid == rhs.rects_valid && + visible == rhs.visible; +} +} // namespace webkit_glue diff --git a/webkit/glue/plugins/webplugin.h b/webkit/glue/plugins/webplugin.h new file mode 100644 index 0000000..cde5fce --- /dev/null +++ b/webkit/glue/plugins/webplugin.h @@ -0,0 +1,194 @@ +// Copyright (c) 2006-2009 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. + +#ifndef WEBKIT_GLUE_WEBPLUGIN_H_ +#define WEBKIT_GLUE_WEBPLUGIN_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "gfx/native_widget_types.h" +#include "gfx/rect.h" + +// TODO(port): this typedef is obviously incorrect on non-Windows +// platforms, but now a lot of code now accidentally depends on them +// existing. #ifdef out these declarations and fix all the users. +typedef void* HANDLE; + +class GURL; +struct NPObject; + +namespace WebKit { +class WebFrame; +} + +namespace webkit_glue { + +class WebPluginDelegate; +class WebPluginParentView; +class WebPluginResourceClient; + +// Describes the new location for a plugin window. +struct WebPluginGeometry { + WebPluginGeometry(); + + bool Equals(const WebPluginGeometry& rhs) const; + + // On Windows, this is the plugin window in the plugin process. + // On X11, this is the XID of the plugin-side GtkPlug containing the + // GtkSocket hosting the actual plugin window. + // + // On Mac OS X, all of the plugin types are currently "windowless" + // (window == 0) except for the special case of the GPU plugin, + // which currently performs rendering on behalf of the Pepper 3D API + // and WebGL. The GPU plugin uses a simple integer for the + // PluginWindowHandle which is used to map to a side data structure + // containing information about the plugin. Soon this plugin will be + // generalized, at which point this mechanism will be rethought or + // removed. + gfx::PluginWindowHandle window; + gfx::Rect window_rect; + // Clip rect (include) and cutouts (excludes), relative to + // window_rect origin. + gfx::Rect clip_rect; + std::vector<gfx::Rect> cutout_rects; + bool rects_valid; + bool visible; +}; + +// The WebKit side of a plugin implementation. It provides wrappers around +// operations that need to interact with the frame and other WebCore objects. +class WebPlugin { + public: + virtual ~WebPlugin() {} + + // Called by the plugin delegate to let the WebPlugin know if the plugin is + // windowed (i.e. handle is not NULL) or windowless (handle is NULL). This + // tells the WebPlugin to send mouse/keyboard events to the plugin delegate, + // as well as the information about the HDC for paint operations. + virtual void SetWindow(gfx::PluginWindowHandle window) = 0; + + // Whether input events should be sent to the delegate. + virtual void SetAcceptsInputEvents(bool accepts) = 0; + + // Called by the plugin delegate to let it know that the window is being + // destroyed. + virtual void WillDestroyWindow(gfx::PluginWindowHandle window) = 0; +#if defined(OS_WIN) + // The pump_messages_event is a event handle which is valid only for + // windowless plugins and is used in NPP_HandleEvent calls to pump messages + // if the plugin enters a modal loop. + // Cancels a pending request. + virtual void SetWindowlessPumpEvent(HANDLE pump_messages_event) = 0; +#endif + virtual void CancelResource(unsigned long id) = 0; + virtual void Invalidate() = 0; + virtual void InvalidateRect(const gfx::Rect& rect) = 0; + + // Returns the NPObject for the browser's window object. + virtual NPObject* GetWindowScriptNPObject() = 0; + + // Returns the DOM element that loaded the plugin. + virtual NPObject* GetPluginElement() = 0; + + // Cookies + virtual void SetCookie(const GURL& url, + const GURL& first_party_for_cookies, + const std::string& cookie) = 0; + virtual std::string GetCookies(const GURL& url, + const GURL& first_party_for_cookies) = 0; + + // Shows a modal HTML dialog containing the given URL. json_arguments are + // passed to the dialog via the DOM 'window.chrome.dialogArguments', and the + // retval is the string returned by 'window.chrome.send("DialogClose", + // retval)'. + virtual void ShowModalHTMLDialog(const GURL& url, int width, int height, + const std::string& json_arguments, + std::string* json_retval) = 0; + + // When a default plugin has downloaded the plugin list and finds it is + // available, it calls this method to notify the renderer. Also it will update + // the status when user clicks on the plugin to install. + virtual void OnMissingPluginStatus(int status) = 0; + + // Handles GetURL/GetURLNotify/PostURL/PostURLNotify requests initiated + // by plugins. If the plugin wants notification of the result, notify_id will + // be non-zero. + virtual void HandleURLRequest(const char* url, + const char* method, + const char* target, + const char* buf, + unsigned int len, + int notify_id, + bool popups_allowed) = 0; + + // Cancels document load. + virtual void CancelDocumentLoad() = 0; + + // Initiates a HTTP range request for an existing stream. + virtual void InitiateHTTPRangeRequest(const char* url, + const char* range_info, + int range_request_id) = 0; + + // Returns true iff in off the record (Incognito) mode. + virtual bool IsOffTheRecord() = 0; + + // Called when the WebPluginResourceClient instance is deleted. + virtual void ResourceClientDeleted( + WebPluginResourceClient* resource_client) {} + + // Defers the loading of the resource identified by resource_id. This is + // controlled by the defer parameter. + virtual void SetDeferResourceLoading(unsigned long resource_id, + bool defer) = 0; + +#if defined(OS_MACOSX) + // Synthesize a fake window handle for the plug-in to identify the instance + // to the browser, allowing mapping to a surface for hardware accelleration + // of plug-in content. The browser generates the handle which is then set on + // the plug-in. + virtual void BindFakePluginWindowHandle() {} + + // Tell the browser (via the renderer) to invalidate because the + // accelerated buffers have changed. + virtual void AcceleratedFrameBuffersDidSwap(gfx::PluginWindowHandle window) {} + + // Tell the renderer and browser to associate the given plugin handle with + // |accelerated_surface_identifier|. The geometry is used to resize any + // native "window" (which on the Mac is a CALayer). + virtual void SetAcceleratedSurface(gfx::PluginWindowHandle window, + int32 width, + int32 height, + uint64 accelerated_surface_identifier) {} +#endif + + // Gets the WebPluginDelegate that implements the interface. + // This API is only for use with Pepper, and is only overridden + // by in-renderer implementations. + virtual WebPluginDelegate* delegate() { return NULL; } +}; + +// Simpler version of ResourceHandleClient that lends itself to proxying. +class WebPluginResourceClient { + public: + virtual ~WebPluginResourceClient() {} + virtual void WillSendRequest(const GURL& url) = 0; + // The request_is_seekable parameter indicates whether byte range requests + // can be issued for the underlying stream. + virtual void DidReceiveResponse(const std::string& mime_type, + const std::string& headers, + uint32 expected_length, + uint32 last_modified, + bool request_is_seekable) = 0; + virtual void DidReceiveData(const char* buffer, int length, + int data_offset) = 0; + virtual void DidFinishLoading() = 0; + virtual void DidFail() = 0; + virtual bool IsMultiByteResponseExpected() = 0; +}; + +} // namespace webkit_glue + +#endif // #ifndef WEBKIT_GLUE_WEBPLUGIN_H_ diff --git a/webkit/glue/plugins/webplugin_delegate.h b/webkit/glue/plugins/webplugin_delegate.h new file mode 100644 index 0000000..0b08c9e --- /dev/null +++ b/webkit/glue/plugins/webplugin_delegate.h @@ -0,0 +1,161 @@ +// 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. + +#ifndef WEBKIT_GLUE_WEBPLUGIN_DELEGATE_H_ +#define WEBKIT_GLUE_WEBPLUGIN_DELEGATE_H_ + +#include <string> +#include <vector> + +#include "base/string16.h" +#include "build/build_config.h" +#include "gfx/native_widget_types.h" +#include "third_party/npapi/bindings/npapi.h" +#include "third_party/npapi/bindings/npapi_extensions.h" +#include "third_party/WebKit/WebKit/chromium/public/WebCanvas.h" +#include "webkit/glue/plugins/webplugin_2d_device_delegate.h" +#include "webkit/glue/plugins/webplugin_3d_device_delegate.h" +#include "webkit/glue/plugins/webplugin_audio_device_delegate.h" +#include "webkit/glue/plugins/webplugin_file_delegate.h" +#include "webkit/glue/plugins/webplugin_print_delegate.h" + + +class FilePath; +class GURL; +struct NPObject; + +namespace WebKit { +class WebInputEvent; +struct WebCursorInfo; +} + +namespace gfx { +class Rect; +} + +namespace webkit_glue { + +class WebPlugin; +class WebPluginResourceClient; + +// This is the interface that a plugin implementation needs to provide. +class WebPluginDelegate : public WebPlugin2DDeviceDelegate, + public WebPlugin3DDeviceDelegate, + public WebPluginAudioDeviceDelegate, + public WebPluginPrintDelegate, + public WebPluginFileDelegate { + public: + virtual ~WebPluginDelegate() {} + + // Initializes the plugin implementation with the given (UTF8) arguments. + // Note that the lifetime of WebPlugin must be longer than this delegate. + // If this function returns false the plugin isn't started and shouldn't be + // called again. If this method succeeds, then the WebPlugin is valid until + // PluginDestroyed is called. + // The load_manually parameter if true indicates that the plugin data would + // be passed from webkit. if false indicates that the plugin should download + // the data. This also controls whether the plugin is instantiated as a full + // page plugin (NP_FULL) or embedded (NP_EMBED). + virtual bool Initialize(const GURL& url, + const std::vector<std::string>& arg_names, + const std::vector<std::string>& arg_values, + WebPlugin* plugin, + bool load_manually) = 0; + + // Called when the WebPlugin is being destroyed. This is a signal to the + // delegate that it should tear-down the plugin implementation and not call + // methods on the WebPlugin again. + virtual void PluginDestroyed() = 0; + + // Update the geometry of the plugin. This is a request to move the + // plugin, relative to its containing window, to the coords given by + // window_rect. Its contents should be clipped to the coords given + // by clip_rect, which are relative to the origin of the plugin + // window. The clip_rect is in plugin-relative coordinates. + virtual void UpdateGeometry(const gfx::Rect& window_rect, + const gfx::Rect& clip_rect) = 0; + + // Tells the plugin to paint the damaged rect. |canvas| is only used for + // windowless plugins. + virtual void Paint(WebKit::WebCanvas* canvas, const gfx::Rect& rect) = 0; + + // Tells the plugin to print itself. + virtual void Print(gfx::NativeDrawingContext hdc) = 0; + + // Informs the plugin that it now has focus. This is only called in + // windowless mode. + virtual void SetFocus() = 0; + + // For windowless plugins, gives them a user event like mouse/keyboard. + // Returns whether the event was handled. This is only called in windowsless + // mode. See NPAPI NPP_HandleEvent for more information. + virtual bool HandleInputEvent(const WebKit::WebInputEvent& event, + WebKit::WebCursorInfo* cursor) = 0; + + // Gets the NPObject associated with the plugin for scripting. + virtual NPObject* GetPluginScriptableObject() = 0; + + // Receives notification about a resource load that the plugin initiated + // for a frame. + virtual void DidFinishLoadWithReason(const GURL& url, NPReason reason, + int notify_id) = 0; + + // Returns the process id of the process that is running the plugin. + virtual int GetProcessId() = 0; + + // The result, UTF-8 encoded, of the script execution is returned via this + // function. + virtual void SendJavaScriptStream(const GURL& url, + const std::string& result, + bool success, + int notify_id) = 0; + + // Receives notification about data being available. + virtual void DidReceiveManualResponse(const GURL& url, + const std::string& mime_type, + const std::string& headers, + uint32 expected_length, + uint32 last_modified) = 0; + + // Receives the data. + virtual void DidReceiveManualData(const char* buffer, int length) = 0; + + // Indicates end of data load. + virtual void DidFinishManualLoading() = 0; + + // Indicates a failure in data receipt. + virtual void DidManualLoadFail() = 0; + + // Only supported when the plugin is the default plugin. + virtual void InstallMissingPlugin() = 0; + + // Creates a WebPluginResourceClient instance and returns the same. + virtual WebPluginResourceClient* CreateResourceClient( + unsigned long resource_id, + const GURL& url, + int notify_id) = 0; + + // Creates a WebPluginResourceClient instance for an existing stream that is + // has become seekable. + virtual WebPluginResourceClient* CreateSeekableResourceClient( + unsigned long resource_id, int range_request_id) = 0; + + // See WebPluginContainerImpl's description of the interface. + virtual bool SupportsFind() { return false; } + virtual void StartFind(const std::string& search_text, + bool case_sensitive, + int identifier) {} + virtual void SelectFindResult(bool forward) {} + virtual void StopFind() {} + virtual void NumberOfFindResultsChanged(int total, bool final_result) {} + virtual void SelectedFindResultChanged(int index) {} + + // Used for zooming of full page plugins. 0 means reset, while -1 means zoom + // out and +1 means zoom in. + virtual void Zoom(int factor) {} +}; + +} // namespace webkit_glue + +#endif // WEBKIT_GLUE_WEBPLUGIN_DELEGATE_H_ diff --git a/webkit/glue/plugins/webplugin_delegate_impl.h b/webkit/glue/plugins/webplugin_delegate_impl.h index a66f282..3295a08 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl.h +++ b/webkit/glue/plugins/webplugin_delegate_impl.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -19,8 +19,8 @@ #include "gfx/native_widget_types.h" #include "gfx/rect.h" #include "third_party/npapi/bindings/npapi.h" +#include "webkit/glue/plugins/webplugin_delegate.h" #include "webkit/glue/webcursor.h" -#include "webkit/glue/webplugin_delegate.h" #if defined(OS_MACOSX) #include "app/surface/accelerated_surface_mac.h" diff --git a/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc b/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc index 2c6b239..2501b01 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc +++ b/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc @@ -20,13 +20,13 @@ #include "skia/ext/platform_canvas.h" #include "third_party/WebKit/WebKit/chromium/public/WebCursorInfo.h" #include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" -#include "webkit/glue/webplugin.h" #include "webkit/glue/plugins/gtk_plugin_container.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/plugins/webplugin.h" #include "webkit/glue/webkit_glue.h" #include "third_party/npapi/bindings/npapi_x11.h" diff --git a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm index 1d0b138..bf74453 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm +++ b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// 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. @@ -19,13 +19,13 @@ #include "base/string_util.h" #include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" #include "webkit/default_plugin/plugin_impl.h" -#include "webkit/glue/webplugin.h" #include "webkit/glue/plugins/coregraphics_private_symbols_mac.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/plugins/plugin_web_event_converter_mac.h" +#include "webkit/glue/plugins/webplugin.h" #include "webkit/glue/webkit_glue.h" #ifndef NP_NO_CARBON @@ -1125,7 +1125,7 @@ bool WebPluginDelegateImpl::PlatformHandleInputEvent( if (!(event_converter.get() && event_converter->InitWithEvent(event))) return false; void* plugin_event = event_converter->plugin_event(); - + if (fabsf(zoom_level - 1.0) > kEpsilon) event_converter->SetZoomLevel(zoom_level); diff --git a/webkit/glue/plugins/webplugin_delegate_impl_win.cc b/webkit/glue/plugins/webplugin_delegate_impl_win.cc index 2c31856..1c83565 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl_win.cc +++ b/webkit/glue/plugins/webplugin_delegate_impl_win.cc @@ -24,8 +24,8 @@ #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/plugins/webplugin.h" #include "webkit/glue/webkit_glue.h" -#include "webkit/glue/webplugin.h" using WebKit::WebCursorInfo; using WebKit::WebKeyboardEvent; diff --git a/webkit/glue/plugins/webplugin_impl.cc b/webkit/glue/plugins/webplugin_impl.cc new file mode 100644 index 0000000..e701675 --- /dev/null +++ b/webkit/glue/plugins/webplugin_impl.cc @@ -0,0 +1,1207 @@ +// 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 "base/logging.h" +#include "base/message_loop.h" +#include "base/string_util.h" +#include "base/utf_string_conversions.h" +#include "gfx/rect.h" +#include "net/base/escape.h" +#include "net/base/net_errors.h" +#include "skia/ext/platform_canvas.h" +#include "third_party/WebKit/WebKit/chromium/public/WebConsoleMessage.h" +#include "third_party/WebKit/WebKit/chromium/public/WebCookieJar.h" +#include "third_party/WebKit/WebKit/chromium/public/WebCString.h" +#include "third_party/WebKit/WebKit/chromium/public/WebCursorInfo.h" +#include "third_party/WebKit/WebKit/chromium/public/WebDevToolsAgent.h" +#include "third_party/WebKit/WebKit/chromium/public/WebData.h" +#include "third_party/WebKit/WebKit/chromium/public/WebDocument.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/WebKit/chromium/public/WebHTTPBody.h" +#include "third_party/WebKit/WebKit/chromium/public/WebHTTPHeaderVisitor.h" +#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" +#include "third_party/WebKit/WebKit/chromium/public/WebKit.h" +#include "third_party/WebKit/WebKit/chromium/public/WebKitClient.h" +#include "third_party/WebKit/WebKit/chromium/public/WebPluginContainer.h" +#include "third_party/WebKit/WebKit/chromium/public/WebPluginParams.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURL.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURLError.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURLLoader.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURLLoaderClient.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURLResponse.h" +#include "third_party/WebKit/WebKit/chromium/public/WebView.h" +#include "webkit/glue/multipart_response_delegate.h" +#include "webkit/glue/plugins/plugin_host.h" +#include "webkit/glue/plugins/plugin_instance.h" +#include "webkit/glue/plugins/webplugin_delegate.h" +#include "webkit/glue/plugins/webplugin_impl.h" +#include "webkit/glue/plugins/webplugin_page_delegate.h" +#include "googleurl/src/gurl.h" + +using WebKit::WebCanvas; +using WebKit::WebConsoleMessage; +using WebKit::WebCookieJar; +using WebKit::WebCString; +using WebKit::WebCursorInfo; +using WebKit::WebData; +using WebKit::WebDataSource; +using WebKit::WebDevToolsAgent; +using WebKit::WebFrame; +using WebKit::WebHTTPBody; +using WebKit::WebHTTPHeaderVisitor; +using WebKit::WebInputEvent; +using WebKit::WebKeyboardEvent; +using WebKit::WebMouseEvent; +using WebKit::WebPluginContainer; +using WebKit::WebPluginParams; +using WebKit::WebRect; +using WebKit::WebString; +using WebKit::WebURL; +using WebKit::WebURLError; +using WebKit::WebURLLoader; +using WebKit::WebURLLoaderClient; +using WebKit::WebURLRequest; +using WebKit::WebURLResponse; +using WebKit::WebVector; +using WebKit::WebView; +using webkit_glue::MultipartResponseDelegate; + +namespace webkit_glue { +namespace { + +// This class handles individual multipart responses. It is instantiated when +// we receive HTTP status code 206 in the HTTP response. This indicates +// that the response could have multiple parts each separated by a boundary +// specified in the response header. +class MultiPartResponseClient : public WebURLLoaderClient { + public: + explicit MultiPartResponseClient(WebPluginResourceClient* resource_client) + : resource_client_(resource_client) { + Clear(); + } + + virtual void willSendRequest( + WebURLLoader*, WebURLRequest&, const WebURLResponse&) {} + virtual void didSendData( + WebURLLoader*, unsigned long long, unsigned long long) {} + + // Called when the multipart parser encounters an embedded multipart + // response. + virtual void didReceiveResponse( + WebURLLoader*, const WebURLResponse& response) { + if (!MultipartResponseDelegate::ReadContentRanges( + response, + &byte_range_lower_bound_, + &byte_range_upper_bound_)) { + NOTREACHED(); + return; + } + + resource_response_ = response; + } + + // Receives individual part data from a multipart response. + virtual void didReceiveData( + WebURLLoader*, const char* data, int data_size) { + // TODO(ananta) + // We should defer further loads on multipart resources on the same lines + // as regular resources requested by plugins to prevent reentrancy. + resource_client_->DidReceiveData( + data, data_size, byte_range_lower_bound_); + } + + virtual void didFinishLoading(WebURLLoader*) {} + virtual void didFail(WebURLLoader*, const WebURLError&) {} + + void Clear() { + resource_response_.reset(); + byte_range_lower_bound_ = 0; + byte_range_upper_bound_ = 0; + } + + private: + WebURLResponse resource_response_; + // The lower bound of the byte range. + int byte_range_lower_bound_; + // The upper bound of the byte range. + int byte_range_upper_bound_; + // The handler for the data. + WebPluginResourceClient* resource_client_; +}; + +class HeaderFlattener : public WebHTTPHeaderVisitor { + public: + HeaderFlattener(std::string* buf) : buf_(buf) { + } + + virtual void visitHeader(const WebString& name, const WebString& value) { + // TODO(darin): Should we really exclude headers with an empty value? + if (!name.isEmpty() && !value.isEmpty()) { + buf_->append(name.utf8()); + buf_->append(": "); + buf_->append(value.utf8()); + buf_->append("\n"); + } + } + + private: + std::string* buf_; +}; + +std::string GetAllHeaders(const WebURLResponse& response) { + // TODO(darin): It is possible for httpStatusText to be empty and still have + // an interesting response, so this check seems wrong. + std::string result; + const WebString& status = response.httpStatusText(); + if (status.isEmpty()) + return result; + + // TODO(darin): Shouldn't we also report HTTP version numbers? + result = StringPrintf("HTTP %d ", response.httpStatusCode()); + result.append(status.utf8()); + result.append("\n"); + + HeaderFlattener flattener(&result); + response.visitHTTPHeaderFields(&flattener); + + return result; +} + +struct ResponseInfo { + GURL url; + std::string mime_type; + uint32 last_modified; + uint32 expected_length; +}; + +void GetResponseInfo(const WebURLResponse& response, + ResponseInfo* response_info) { + response_info->url = response.url(); + response_info->mime_type = response.mimeType().utf8(); + + // Measured in seconds since 12:00 midnight GMT, January 1, 1970. + response_info->last_modified = + static_cast<uint32>(response.lastModifiedDate()); + + // If the length comes in as -1, then it indicates that it was not + // read off the HTTP headers. We replicate Safari webkit behavior here, + // which is to set it to 0. + response_info->expected_length = + static_cast<uint32>(std::max(response.expectedContentLength(), 0LL)); + + WebString content_encoding = + response.httpHeaderField(WebString::fromUTF8("Content-Encoding")); + if (!content_encoding.isNull() && + !EqualsASCII(content_encoding, "identity")) { + // Don't send the compressed content length to the plugin, which only + // cares about the decoded length. + response_info->expected_length = 0; + } +} + +} // namespace + +// WebKit::WebPlugin ---------------------------------------------------------- + +bool WebPluginImpl::initialize(WebPluginContainer* container) { + if (!page_delegate_) + return false; + + std::string actual_mime_type; + WebPluginDelegate* plugin_delegate = page_delegate_->CreatePluginDelegate( + plugin_url_, mime_type_, &actual_mime_type); + if (!plugin_delegate) + return NULL; + + // Set the container before Initialize because the plugin may + // synchronously call NPN_GetValue to get its container during its + // initialization. + SetContainer(container); + bool ok = plugin_delegate->Initialize( + plugin_url_, arg_names_, arg_values_, this, load_manually_); + if (!ok) { + plugin_delegate->PluginDestroyed(); + return false; + } + + if (!actual_mime_type.empty()) + mime_type_ = actual_mime_type; + delegate_ = plugin_delegate; + + return true; +} + +void WebPluginImpl::destroy() { + SetContainer(NULL); + MessageLoop::current()->DeleteSoon(FROM_HERE, this); +} + +NPObject* WebPluginImpl::scriptableObject() { + return delegate_->GetPluginScriptableObject(); +} + +void WebPluginImpl::paint(WebCanvas* canvas, const WebRect& paint_rect) { + if (!delegate_) + return; + + // Note that |canvas| is only used when in windowless mode. + delegate_->Paint(canvas, paint_rect); +} + +void WebPluginImpl::updateGeometry( + const WebRect& window_rect, const WebRect& clip_rect, + const WebVector<WebRect>& cutout_rects, bool is_visible) { + WebPluginGeometry new_geometry; + new_geometry.window = window_; + new_geometry.window_rect = window_rect; + new_geometry.clip_rect = clip_rect; + new_geometry.visible = is_visible; + new_geometry.rects_valid = true; + for (size_t i = 0; i < cutout_rects.size(); ++i) + new_geometry.cutout_rects.push_back(cutout_rects[i]); + + // Only send DidMovePlugin if the geometry changed in some way. + if (window_ && + page_delegate_ && + (first_geometry_update_ || !new_geometry.Equals(geometry_))) { + page_delegate_->DidMovePlugin(new_geometry); + } + + // Only UpdateGeometry if either the window or clip rects have changed. + if (first_geometry_update_ || + new_geometry.window_rect != geometry_.window_rect || + new_geometry.clip_rect != geometry_.clip_rect) { + // Notify the plugin that its parameters have changed. + delegate_->UpdateGeometry(new_geometry.window_rect, new_geometry.clip_rect); + } + + // Initiate a download on the plugin url. This should be done for the + // first update geometry sequence. We need to ensure that the plugin + // receives the geometry update before it starts receiving data. + if (first_geometry_update_) { + // An empty url corresponds to an EMBED tag with no src attribute. + if (!load_manually_ && plugin_url_.is_valid()) { + // The Flash plugin hangs for a while if it receives data before + // receiving valid plugin geometry. By valid geometry we mean the + // geometry received by a call to setFrameRect in the Webkit + // layout code path. To workaround this issue we download the + // plugin source url on a timer. + MessageLoop::current()->PostDelayedTask( + FROM_HERE, method_factory_.NewRunnableMethod( + &WebPluginImpl::OnDownloadPluginSrcUrl), 0); + } + } + + first_geometry_update_ = false; + geometry_ = new_geometry; +} + +void WebPluginImpl::updateFocus(bool focused) { + if (focused && accepts_input_events_) + delegate_->SetFocus(); +} + +void WebPluginImpl::updateVisibility(bool visible) { + if (!window_ || !page_delegate_) + return; + + WebPluginGeometry move; + move.window = window_; + move.window_rect = gfx::Rect(); + move.clip_rect = gfx::Rect(); + move.rects_valid = false; + move.visible = visible; + + page_delegate_->DidMovePlugin(move); +} + +bool WebPluginImpl::acceptsInputEvents() { + return accepts_input_events_; +} + +bool WebPluginImpl::handleInputEvent( + const WebInputEvent& event, WebCursorInfo& cursor_info) { + return delegate_->HandleInputEvent(event, &cursor_info); +} + +void WebPluginImpl::didReceiveResponse(const WebURLResponse& response) { + ignore_response_error_ = false; + + ResponseInfo response_info; + GetResponseInfo(response, &response_info); + + delegate_->DidReceiveManualResponse( + response_info.url, + response_info.mime_type, + GetAllHeaders(response), + response_info.expected_length, + response_info.last_modified); +} + +void WebPluginImpl::didReceiveData(const char* data, int data_length) { + delegate_->DidReceiveManualData(data, data_length); +} + +void WebPluginImpl::didFinishLoading() { + delegate_->DidFinishManualLoading(); +} + +void WebPluginImpl::didFailLoading(const WebURLError& error) { + if (!ignore_response_error_) + delegate_->DidManualLoadFail(); +} + +void WebPluginImpl::didFinishLoadingFrameRequest( + const WebURL& url, void* notify_data) { + if (delegate_) { + // We're converting a void* into an arbitrary int id. Though + // these types are the same size on all the platforms we support, + // the compiler may complain as though they are different, so to + // make the casting gods happy go through an intptr_t (the union + // of void* and int) rather than converting straight across. + delegate_->DidFinishLoadWithReason( + url, NPRES_DONE, reinterpret_cast<intptr_t>(notify_data)); + } +} + +void WebPluginImpl::didFailLoadingFrameRequest( + const WebURL& url, void* notify_data, const WebURLError& error) { + if (!delegate_) + return; + + NPReason reason = + error.reason == net::ERR_ABORTED ? NPRES_USER_BREAK : NPRES_NETWORK_ERR; + // See comment in didFinishLoadingFrameRequest about the cast here. + delegate_->DidFinishLoadWithReason( + url, reason, reinterpret_cast<intptr_t>(notify_data)); +} + +bool WebPluginImpl::supportsPaginatedPrint() { + if (!delegate_) + return false; + return delegate_->PrintSupportsPrintExtension(); +} + +int WebPluginImpl::printBegin(const WebRect& printable_area, int printer_dpi) { + if (!delegate_) + return 0; + + if (!supportsPaginatedPrint()) + return 0; + + return delegate_->PrintBegin(printable_area, printer_dpi); +} + +bool WebPluginImpl::printPage(int page_number, WebCanvas* canvas) { + if (!delegate_) + return false; + + return delegate_->PrintPage(page_number, canvas); +} + +void WebPluginImpl::printEnd() { + if (delegate_) + delegate_->PrintEnd(); +} + + +// ----------------------------------------------------------------------------- + +WebPluginImpl::WebPluginImpl( + WebFrame* webframe, const WebPluginParams& params, + const base::WeakPtr<WebPluginPageDelegate>& page_delegate) + : windowless_(false), + window_(NULL), + accepts_input_events_(false), + page_delegate_(page_delegate), + webframe_(webframe), + delegate_(NULL), + container_(NULL), + plugin_url_(params.url), + load_manually_(params.loadManually), + first_geometry_update_(true), + ignore_response_error_(false), + mime_type_(params.mimeType.utf8()), + ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { + DCHECK_EQ(params.attributeNames.size(), params.attributeValues.size()); + StringToLowerASCII(&mime_type_); + + for (size_t i = 0; i < params.attributeNames.size(); ++i) { + arg_names_.push_back(params.attributeNames[i].utf8()); + arg_values_.push_back(params.attributeValues[i].utf8()); + } +} + +WebPluginImpl::~WebPluginImpl() { +} + +void WebPluginImpl::SetWindow(gfx::PluginWindowHandle window) { +#if defined(OS_MACOSX) + // The only time this is called twice, and the second time with a + // non-zero PluginWindowHandle, is the case when this WebPluginImpl + // is created on behalf of the GPU plugin. This entire code path + // will go away soon, as soon as the GPU plugin becomes the GPU + // process, so it is being separated out for easy deletion. + + // The logic we want here is: if (window) DCHECK(!window_); + DCHECK(!(window_ && window)); + window_ = window; + // Lie to ourselves about being windowless even if we got a fake + // plugin window handle, so we continue to get input events. + windowless_ = true; + accepts_input_events_ = true; + // We do not really need to notify the page delegate that a plugin + // window was created -- so don't. +#else + if (window) { + DCHECK(!windowless_); + window_ = window; + accepts_input_events_ = false; + if (page_delegate_) { + // Tell the view delegate that the plugin window was created, so that it + // can create necessary container widgets. + page_delegate_->CreatedPluginWindow(window); + } + } else { + DCHECK(!window_); // Make sure not called twice. + windowless_ = true; + accepts_input_events_ = true; + } +#endif +} + +void WebPluginImpl::WillDestroyWindow(gfx::PluginWindowHandle window) { + DCHECK_EQ(window, window_); + window_ = NULL; + if (page_delegate_) + page_delegate_->WillDestroyPluginWindow(window); +} + +GURL WebPluginImpl::CompleteURL(const char* url) { + if (!webframe_) { + NOTREACHED(); + return GURL(); + } + // TODO(darin): Is conversion from UTF8 correct here? + return webframe_->completeURL(WebString::fromUTF8(url)); +} + +void WebPluginImpl::CancelResource(unsigned long id) { + for (size_t i = 0; i < clients_.size(); ++i) { + if (clients_[i].id == id) { + if (clients_[i].loader.get()) { + clients_[i].loader->setDefersLoading(false); + clients_[i].loader->cancel(); + RemoveClient(i); + } + return; + } + } +} + +bool WebPluginImpl::SetPostData(WebURLRequest* request, + const char *buf, + uint32 length) { + std::vector<std::string> names; + std::vector<std::string> values; + std::vector<char> body; + bool rv = NPAPI::PluginHost::SetPostData(buf, length, &names, &values, &body); + + for (size_t i = 0; i < names.size(); ++i) { + request->addHTTPHeaderField(WebString::fromUTF8(names[i]), + WebString::fromUTF8(values[i])); + } + + WebString content_type_header = WebString::fromUTF8("Content-Type"); + const WebString& content_type = + request->httpHeaderField(content_type_header); + if (content_type.isEmpty()) { + request->setHTTPHeaderField( + content_type_header, + WebString::fromUTF8("application/x-www-form-urlencoded")); + } + + WebHTTPBody http_body; + if (body.size()) { + http_body.initialize(); + http_body.appendData(WebData(&body[0], body.size())); + } + request->setHTTPBody(http_body); + + return rv; +} + +WebPluginImpl::RoutingStatus WebPluginImpl::RouteToFrame( + const char* url, + bool is_javascript_url, + const char* method, + const char* target, + const char* buf, + unsigned int len, + int notify_id, + Referrer referrer_flag) { + // If there is no target, there is nothing to do + if (!target) + return NOT_ROUTED; + + // This could happen if the WebPluginContainer was already deleted. + if (!webframe_) + return NOT_ROUTED; + + WebString target_str = WebString::fromUTF8(target); + + // Take special action for JavaScript URLs + if (is_javascript_url) { + WebFrame* target_frame = + webframe_->view()->findFrameByName(target_str, webframe_); + // For security reasons, do not allow JavaScript on frames + // other than this frame. + if (target_frame != webframe_) { + // TODO(darin): Localize this message. + const char kMessage[] = + "Ignoring cross-frame javascript URL load requested by plugin."; + webframe_->addMessageToConsole( + WebConsoleMessage(WebConsoleMessage::LevelError, + WebString::fromUTF8(kMessage))); + return ROUTED; + } + + // Route javascript calls back to the plugin. + return NOT_ROUTED; + } + + // If we got this far, we're routing content to a target frame. + // Go fetch the URL. + + GURL complete_url = CompleteURL(url); + + if (strcmp(method, "GET") != 0) { + // We're only going to route HTTP/HTTPS requests + if (!(complete_url.SchemeIs("http") || complete_url.SchemeIs("https"))) + return INVALID_URL; + } + + WebURLRequest request(complete_url); + SetReferrer(&request, referrer_flag); + + request.setHTTPMethod(WebString::fromUTF8(method)); + request.setFirstPartyForCookies( + webframe_->document().firstPartyForCookies()); + if (len > 0) { + if (!SetPostData(&request, buf, len)) { + // Uhoh - we're in trouble. There isn't a good way + // to recover at this point. Break out. + NOTREACHED(); + return ROUTED; + } + } + + container_->loadFrameRequest( + request, target_str, notify_id != 0, reinterpret_cast<void*>(notify_id)); + return ROUTED; +} + +NPObject* WebPluginImpl::GetWindowScriptNPObject() { + if (!webframe_) { + NOTREACHED(); + return NULL; + } + return webframe_->windowObject(); +} + +NPObject* WebPluginImpl::GetPluginElement() { + return container_->scriptableObjectForElement(); +} + +void WebPluginImpl::SetCookie(const GURL& url, + const GURL& first_party_for_cookies, + const std::string& cookie) { + if (!page_delegate_) + return; + + WebCookieJar* cookie_jar = page_delegate_->GetCookieJar(); + if (!cookie_jar) { + DLOG(WARNING) << "No cookie jar!"; + return; + } + + cookie_jar->setCookie( + url, first_party_for_cookies, WebString::fromUTF8(cookie)); +} + +std::string WebPluginImpl::GetCookies(const GURL& url, + const GURL& first_party_for_cookies) { + if (!page_delegate_) + return std::string(); + + WebCookieJar* cookie_jar = page_delegate_->GetCookieJar(); + if (!cookie_jar) { + DLOG(WARNING) << "No cookie jar!"; + return std::string(); + } + + return UTF16ToUTF8(cookie_jar->cookies(url, first_party_for_cookies)); +} + +void WebPluginImpl::ShowModalHTMLDialog(const GURL& url, int width, int height, + const std::string& json_arguments, + std::string* json_retval) { + if (page_delegate_) { + page_delegate_->ShowModalHTMLDialogForPlugin( + url, gfx::Size(width, height), json_arguments, json_retval); + } +} + +void WebPluginImpl::OnMissingPluginStatus(int status) { + NOTREACHED(); +} + +void WebPluginImpl::Invalidate() { + if (container_) + container_->invalidate(); +} + +void WebPluginImpl::InvalidateRect(const gfx::Rect& rect) { + if (container_) + container_->invalidateRect(rect); +} + +void WebPluginImpl::OnDownloadPluginSrcUrl() { + HandleURLRequestInternal( + plugin_url_.spec().c_str(), "GET", NULL, NULL, 0, 0, false, DOCUMENT_URL); +} + +WebPluginResourceClient* WebPluginImpl::GetClientFromLoader( + WebURLLoader* loader) { + ClientInfo* client_info = GetClientInfoFromLoader(loader); + if (client_info) + return client_info->client; + return NULL; +} + +WebPluginImpl::ClientInfo* WebPluginImpl::GetClientInfoFromLoader( + WebURLLoader* loader) { + for (size_t i = 0; i < clients_.size(); ++i) { + if (clients_[i].loader.get() == loader) + return &clients_[i]; + } + + NOTREACHED(); + return 0; +} + +void WebPluginImpl::willSendRequest(WebURLLoader* loader, + WebURLRequest& request, + const WebURLResponse&) { + WebPluginResourceClient* client = GetClientFromLoader(loader); + if (client) + client->WillSendRequest(request.url()); +} + +void WebPluginImpl::didSendData(WebURLLoader* loader, + unsigned long long bytes_sent, + unsigned long long total_bytes_to_be_sent) { +} + +void WebPluginImpl::didReceiveResponse(WebURLLoader* loader, + const WebURLResponse& response) { + static const int kHttpPartialResponseStatusCode = 206; + static const int kHttpResponseSuccessStatusCode = 200; + + WebPluginResourceClient* client = GetClientFromLoader(loader); + if (!client) + return; + + ResponseInfo response_info; + GetResponseInfo(response, &response_info); + + bool request_is_seekable = true; + if (client->IsMultiByteResponseExpected()) { + if (response.httpStatusCode() == kHttpPartialResponseStatusCode) { + HandleHttpMultipartResponse(response, client); + return; + } else if (response.httpStatusCode() == kHttpResponseSuccessStatusCode) { + // If the client issued a byte range request and the server responds with + // HTTP 200 OK, it indicates that the server does not support byte range + // requests. + // We need to emulate Firefox behavior by doing the following:- + // 1. Destroy the plugin instance in the plugin process. Ensure that + // existing resource requests initiated for the plugin instance + // continue to remain valid. + // 2. Create a new plugin instance and notify it about the response + // received here. + if (!ReinitializePluginForResponse(loader)) { + NOTREACHED(); + return; + } + + // The server does not support byte range requests. No point in creating + // seekable streams. + request_is_seekable = false; + + delete client; + client = NULL; + + // Create a new resource client for this request. + for (size_t i = 0; i < clients_.size(); ++i) { + if (clients_[i].loader.get() == loader) { + WebPluginResourceClient* resource_client = + delegate_->CreateResourceClient(clients_[i].id, plugin_url_, 0); + clients_[i].client = resource_client; + client = resource_client; + break; + } + } + + DCHECK(client != NULL); + } + } + + // Calling into a plugin could result in reentrancy if the plugin yields + // control to the OS like entering a modal loop etc. Prevent this by + // stopping further loading until the plugin notifies us that it is ready to + // accept data + loader->setDefersLoading(true); + + client->DidReceiveResponse( + response_info.mime_type, + GetAllHeaders(response), + response_info.expected_length, + response_info.last_modified, + request_is_seekable); + + if (WebDevToolsAgent* devtools_agent = GetDevToolsAgent()) { + ClientInfo* client_info = GetClientInfoFromLoader(loader); + if (client_info) + devtools_agent->didReceiveResponse(client_info->id, response); + } + + // Bug http://b/issue?id=925559. The flash plugin would not handle the HTTP + // error codes in the stream header and as a result, was unaware of the + // fate of the HTTP requests issued via NPN_GetURLNotify. Webkit and FF + // destroy the stream and invoke the NPP_DestroyStream function on the + // plugin if the HTTP request fails. + const GURL& url = response.url(); + if (url.SchemeIs("http") || url.SchemeIs("https")) { + if (response.httpStatusCode() < 100 || response.httpStatusCode() >= 400) { + // The plugin instance could be in the process of deletion here. + // Verify if the WebPluginResourceClient instance still exists before + // use. + ClientInfo* client_info = GetClientInfoFromLoader(loader); + if (client_info) { + client_info->pending_failure_notification = true; + } + } + } +} + +void WebPluginImpl::didReceiveData(WebURLLoader* loader, + const char *buffer, + int length) { + WebPluginResourceClient* client = GetClientFromLoader(loader); + if (!client) + return; + + // ClientInfo can be removed from clients_ vector by next statements. + if (WebDevToolsAgent* devtools_agent = GetDevToolsAgent()) { + ClientInfo* client_info = GetClientInfoFromLoader(loader); + if (client_info) + devtools_agent->didReceiveData(client_info->id, length); + } + MultiPartResponseHandlerMap::iterator index = + multi_part_response_map_.find(client); + if (index != multi_part_response_map_.end()) { + MultipartResponseDelegate* multi_part_handler = (*index).second; + DCHECK(multi_part_handler != NULL); + multi_part_handler->OnReceivedData(buffer, length); + } else { + loader->setDefersLoading(true); + client->DidReceiveData(buffer, length, 0); + } +} + +void WebPluginImpl::didFinishLoading(WebURLLoader* loader) { + ClientInfo* client_info = GetClientInfoFromLoader(loader); + if (client_info && client_info->client) { + MultiPartResponseHandlerMap::iterator index = + multi_part_response_map_.find(client_info->client); + if (index != multi_part_response_map_.end()) { + delete (*index).second; + multi_part_response_map_.erase(index); + if (page_delegate_) + page_delegate_->DidStopLoadingForPlugin(); + } + loader->setDefersLoading(true); + WebPluginResourceClient* resource_client = client_info->client; + // The ClientInfo can get deleted in the call to DidFinishLoading below. + // It is not safe to access this structure after that. + client_info->client = NULL; + resource_client->DidFinishLoading(); + + if (WebDevToolsAgent* devtools_agent = GetDevToolsAgent()) + devtools_agent->didFinishLoading(client_info->id); + } +} + +void WebPluginImpl::didFail(WebURLLoader* loader, + const WebURLError& error) { + ClientInfo* client_info = GetClientInfoFromLoader(loader); + if (client_info && client_info->client) { + loader->setDefersLoading(true); + WebPluginResourceClient* resource_client = client_info->client; + // The ClientInfo can get deleted in the call to DidFail below. + // It is not safe to access this structure after that. + client_info->client = NULL; + resource_client->DidFail(); + + if (WebDevToolsAgent* devtools_agent = GetDevToolsAgent()) + devtools_agent->didFailLoading(client_info->id, error); + } +} + +void WebPluginImpl::RemoveClient(size_t i) { + clients_.erase(clients_.begin() + i); +} + +void WebPluginImpl::RemoveClient(WebURLLoader* loader) { + for (size_t i = 0; i < clients_.size(); ++i) { + if (clients_[i].loader.get() == loader) { + RemoveClient(i); + return; + } + } +} + +void WebPluginImpl::SetContainer(WebPluginContainer* container) { + if (!container) + TearDownPluginInstance(NULL); + container_ = container; +} + +void WebPluginImpl::HandleURLRequest(const char* url, + const char* method, + const char* target, + const char* buf, + unsigned int len, + int notify_id, + bool popups_allowed) { + // GetURL/PostURL requests initiated explicitly by plugins should specify the + // plugin SRC url as the referrer if it is available. + HandleURLRequestInternal( + url, method, target, buf, len, notify_id, popups_allowed, PLUGIN_SRC); +} + +void WebPluginImpl::HandleURLRequestInternal(const char* url, + const char* method, + const char* target, + const char* buf, + unsigned int len, + int notify_id, + bool popups_allowed, + Referrer referrer_flag) { + // For this request, we either route the output to a frame + // because a target has been specified, or we handle the request + // here, i.e. by executing the script if it is a javascript url + // or by initiating a download on the URL, etc. There is one special + // case in that the request is a javascript url and the target is "_self", + // in which case we route the output to the plugin rather than routing it + // to the plugin's frame. + bool is_javascript_url = StartsWithASCII(url, "javascript:", false); + RoutingStatus routing_status = RouteToFrame( + url, is_javascript_url, method, target, buf, len, notify_id, + referrer_flag); + if (routing_status == ROUTED) + return; + + if (is_javascript_url) { + GURL gurl(url); + WebString result = container_->executeScriptURL(gurl, popups_allowed); + + // delegate_ could be NULL because executeScript caused the container to + // be deleted. + if (delegate_) { + delegate_->SendJavaScriptStream( + gurl, result.utf8(), !result.isNull(), notify_id); + } + + return; + } + + unsigned long resource_id = GetNextResourceId(); + if (!resource_id) + return; + + GURL complete_url = CompleteURL(url); + WebPluginResourceClient* resource_client = delegate_->CreateResourceClient( + resource_id, complete_url, notify_id); + if (!resource_client) + return; + + // If the RouteToFrame call returned a failure then inform the result + // back to the plugin asynchronously. + if ((routing_status == INVALID_URL) || + (routing_status == GENERAL_FAILURE)) { + resource_client->DidFail(); + return; + } + + // CreateResourceClient() sends a synchronous IPC message so it's possible + // that TearDownPluginInstance() may have been called in the nested + // message loop. If so, don't start the request. + if (!delegate_) + return; + + InitiateHTTPRequest(resource_id, resource_client, complete_url, method, buf, + len, NULL, referrer_flag); +} + +unsigned long WebPluginImpl::GetNextResourceId() { + if (!webframe_) + return 0; + WebView* view = webframe_->view(); + if (!view) + return 0; + return view->createUniqueIdentifierForRequest(); +} + +bool WebPluginImpl::InitiateHTTPRequest(unsigned long resource_id, + WebPluginResourceClient* client, + const GURL& url, + const char* method, + const char* buf, + int buf_len, + const char* range_info, + Referrer referrer_flag) { + if (!client) { + NOTREACHED(); + return false; + } + + ClientInfo info; + info.id = resource_id; + info.client = client; + info.request.initialize(); + info.request.setURL(url); + info.request.setFirstPartyForCookies( + webframe_->document().firstPartyForCookies()); + info.request.setRequestorProcessID(delegate_->GetProcessId()); + info.request.setTargetType(WebURLRequest::TargetIsObject); + info.request.setHTTPMethod(WebString::fromUTF8(method)); + info.pending_failure_notification = false; + + if (range_info) { + info.request.addHTTPHeaderField(WebString::fromUTF8("Range"), + WebString::fromUTF8(range_info)); + } + + if (strcmp(method, "POST") == 0) { + // Adds headers or form data to a request. This must be called before + // we initiate the actual request. + SetPostData(&info.request, buf, buf_len); + } + + SetReferrer(&info.request, referrer_flag); + + // Sets the routing id to associate the ResourceRequest with the RenderView. + webframe_->dispatchWillSendRequest(info.request); + if (WebDevToolsAgent* devtools_agent = GetDevToolsAgent()) { + devtools_agent->identifierForInitialRequest(resource_id, webframe_, + info.request); + devtools_agent->willSendRequest(resource_id, info.request); + } + + info.loader.reset(WebKit::webKitClient()->createURLLoader()); + if (!info.loader.get()) + return false; + info.loader->loadAsynchronously(info.request, this); + + clients_.push_back(info); + return true; +} + +void WebPluginImpl::CancelDocumentLoad() { + if (webframe_) { + ignore_response_error_ = true; + webframe_->stopLoading(); + } +} + +void WebPluginImpl::InitiateHTTPRangeRequest( + const char* url, const char* range_info, int range_request_id) { + unsigned long resource_id = GetNextResourceId(); + if (!resource_id) + return; + + GURL complete_url = CompleteURL(url); + + WebPluginResourceClient* resource_client = + delegate_->CreateSeekableResourceClient(resource_id, range_request_id); + InitiateHTTPRequest( + resource_id, resource_client, complete_url, "GET", NULL, 0, range_info, + load_manually_ ? NO_REFERRER : PLUGIN_SRC); +} + +void WebPluginImpl::SetDeferResourceLoading(unsigned long resource_id, + bool defer) { + std::vector<ClientInfo>::iterator client_index = clients_.begin(); + while (client_index != clients_.end()) { + ClientInfo& client_info = *client_index; + + if (client_info.id == resource_id) { + client_info.loader->setDefersLoading(defer); + + // If we determined that the request had failed via the HTTP headers + // in the response then we send out a failure notification to the + // plugin process, as certain plugins don't handle HTTP failure codes + // correctly. + if (!defer && client_info.client && + client_info.pending_failure_notification) { + // The ClientInfo and the iterator can become invalid due to the call + // to DidFail below. + WebPluginResourceClient* resource_client = client_info.client; + client_info.loader->cancel(); + clients_.erase(client_index++); + resource_client->DidFail(); + + // Report that resource loading finished. + if (WebDevToolsAgent* devtools_agent = GetDevToolsAgent()) + devtools_agent->didFinishLoading(resource_id); + } + break; + } + client_index++; + } +} + +void WebPluginImpl::HandleHttpMultipartResponse( + const WebURLResponse& response, WebPluginResourceClient* client) { + std::string multipart_boundary; + if (!MultipartResponseDelegate::ReadMultipartBoundary( + response, &multipart_boundary)) { + NOTREACHED(); + return; + } + + if (page_delegate_) + page_delegate_->DidStartLoadingForPlugin(); + + MultiPartResponseClient* multi_part_response_client = + new MultiPartResponseClient(client); + + MultipartResponseDelegate* multi_part_response_handler = + new MultipartResponseDelegate(multi_part_response_client, NULL, + response, + multipart_boundary); + multi_part_response_map_[client] = multi_part_response_handler; +} + +bool WebPluginImpl::ReinitializePluginForResponse( + WebURLLoader* loader) { + WebFrame* webframe = webframe_; + if (!webframe) + return false; + + WebView* webview = webframe->view(); + if (!webview) + return false; + + WebPluginContainer* container_widget = container_; + + // Destroy the current plugin instance. + TearDownPluginInstance(loader); + + container_ = container_widget; + webframe_ = webframe; + + std::string actual_mime_type; + WebPluginDelegate* plugin_delegate = page_delegate_->CreatePluginDelegate( + plugin_url_, mime_type_, &actual_mime_type); + + bool ok = plugin_delegate->Initialize( + plugin_url_, arg_names_, arg_values_, this, load_manually_); + + if (!ok) { + container_ = NULL; + // TODO(iyengar) Should we delete the current plugin instance here? + return false; + } + + mime_type_ = actual_mime_type; + delegate_ = plugin_delegate; + + // Force a geometry update to occur to ensure that the plugin becomes + // visible. + container_->reportGeometry(); + + // The plugin move sequences accumulated via DidMove are sent to the browser + // whenever the renderer paints. Force a paint here to ensure that changes + // to the plugin window are propagated to the browser. + container_->invalidate(); + return true; +} + +void WebPluginImpl::TearDownPluginInstance( + WebURLLoader* loader_to_ignore) { + // The container maintains a list of JSObjects which are related to this + // plugin. Tell the frame we're gone so that it can invalidate all of + // those sub JSObjects. + if (container_) + container_->clearScriptObjects(); + + if (delegate_) { + // Call PluginDestroyed() first to prevent the plugin from calling us back + // in the middle of tearing down the render tree. + delegate_->PluginDestroyed(); + delegate_ = NULL; + } + + // Cancel any pending requests because otherwise this deleted object will + // be called by the ResourceDispatcher. + std::vector<ClientInfo>::iterator client_index = clients_.begin(); + while (client_index != clients_.end()) { + ClientInfo& client_info = *client_index; + + if (loader_to_ignore == client_info.loader) { + client_index++; + continue; + } + + if (client_info.loader.get()) + client_info.loader->cancel(); + + client_index = clients_.erase(client_index); + } + + // This needs to be called now and not in the destructor since the + // webframe_ might not be valid anymore. + webframe_ = NULL; + method_factory_.RevokeAll(); +} + +void WebPluginImpl::SetReferrer(WebKit::WebURLRequest* request, + Referrer referrer_flag) { + switch (referrer_flag) { + case DOCUMENT_URL: + webframe_->setReferrerForRequest(*request, GURL()); + break; + + case PLUGIN_SRC: + webframe_->setReferrerForRequest(*request, plugin_url_); + break; + + default: + break; + } +} + +WebDevToolsAgent* WebPluginImpl::GetDevToolsAgent() { + if (!webframe_) + return NULL; + WebView* view = webframe_->view(); + if (!view) + return NULL; + return view->devToolsAgent(); +} + +} // namespace webkit_glue diff --git a/webkit/glue/plugins/webplugin_impl.h b/webkit/glue/plugins/webplugin_impl.h new file mode 100644 index 0000000..fd6ea25 --- /dev/null +++ b/webkit/glue/plugins/webplugin_impl.h @@ -0,0 +1,321 @@ +// 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. + +#ifndef WEBKIT_GLUE_WEBPLUGIN_IMPL_H_ +#define WEBKIT_GLUE_WEBPLUGIN_IMPL_H_ + +#include <string> +#include <map> +#include <vector> + +#include "base/basictypes.h" +#include "base/linked_ptr.h" +#include "base/task.h" +#include "base/weak_ptr.h" +#include "gfx/native_widget_types.h" +#include "googleurl/src/gurl.h" +#include "third_party/WebKit/WebKit/chromium/public/WebPlugin.h" +#include "third_party/WebKit/WebKit/chromium/public/WebRect.h" +#include "third_party/WebKit/WebKit/chromium/public/WebString.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURLLoaderClient.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h" +#include "third_party/WebKit/WebKit/chromium/public/WebVector.h" +#include "webkit/glue/plugins/webplugin.h" + +class WebViewDelegate; + +namespace WebKit { +class WebDevToolsAgent; +class WebFrame; +class WebPluginContainer; +class WebURLResponse; +class WebURLLoader; +class WebURLRequest; +} + +namespace webkit_glue { + +class MultipartResponseDelegate; +class WebPluginDelegate; +class WebPluginPageDelegate; + +// This is the WebKit side of the plugin implementation that forwards calls, +// after changing out of WebCore types, to a delegate. The delegate may +// be in a different process. +class WebPluginImpl : public WebPlugin, + public WebKit::WebPlugin, + public WebKit::WebURLLoaderClient { + public: + WebPluginImpl( + WebKit::WebFrame* frame, + const WebKit::WebPluginParams& params, + const base::WeakPtr<WebPluginPageDelegate>& page_delegate); + virtual ~WebPluginImpl(); + + // Helper function for sorting post data. + static bool SetPostData(WebKit::WebURLRequest* request, + const char* buf, + uint32 length); + + virtual WebPluginDelegate* delegate() { return delegate_; } + + private: + // WebKit::WebPlugin methods: + virtual bool initialize( + WebKit::WebPluginContainer* container); + virtual void destroy(); + virtual NPObject* scriptableObject(); + virtual void paint( + WebKit::WebCanvas* canvas, const WebKit::WebRect& paint_rect); + virtual void updateGeometry( + const WebKit::WebRect& frame_rect, const WebKit::WebRect& clip_rect, + const WebKit::WebVector<WebKit::WebRect>& cut_outs, bool is_visible); + virtual void updateFocus(bool focused); + virtual void updateVisibility(bool visible); + virtual bool acceptsInputEvents(); + virtual bool handleInputEvent( + const WebKit::WebInputEvent& event, WebKit::WebCursorInfo& cursor_info); + virtual void didReceiveResponse(const WebKit::WebURLResponse& response); + virtual void didReceiveData(const char* data, int data_length); + virtual void didFinishLoading(); + virtual void didFailLoading(const WebKit::WebURLError& error); + virtual void didFinishLoadingFrameRequest( + const WebKit::WebURL& url, void* notify_data); + virtual void didFailLoadingFrameRequest( + const WebKit::WebURL& url, void* notify_data, + const WebKit::WebURLError& error); + virtual bool supportsPaginatedPrint(); + virtual int printBegin(const WebKit::WebRect& printable_area, + int printer_dpi); + virtual bool printPage(int page_number, WebKit::WebCanvas* canvas); + virtual void printEnd(); + + // WebPlugin implementation: + void SetWindow(gfx::PluginWindowHandle window); + + // Whether input events should be sent to the delegate. + virtual void SetAcceptsInputEvents(bool accepts) { + accepts_input_events_ = accepts; + } + + void WillDestroyWindow(gfx::PluginWindowHandle window); +#if defined(OS_WIN) + void SetWindowlessPumpEvent(HANDLE pump_messages_event) { } +#endif + + // Given a (maybe partial) url, completes using the base url. + GURL CompleteURL(const char* url); + + // Executes the script passed in. The notify_needed and notify_data arguments + // are passed in by the plugin process. These indicate whether the plugin + // expects a notification on script execution. We pass them back to the + // plugin as is. This avoids having to track the notification arguments in + // the plugin process. + bool ExecuteScript(const std::string& url, const std::wstring& script, + bool notify_needed, intptr_t notify_data, + bool popups_allowed); + + enum RoutingStatus { + ROUTED, + NOT_ROUTED, + INVALID_URL, + GENERAL_FAILURE + }; + + // Determines the referrer value sent along with outgoing HTTP requests + // issued by plugins. + enum Referrer { + PLUGIN_SRC, + DOCUMENT_URL, + NO_REFERRER + }; + + // Given a download request, check if we need to route the output to a frame. + // Returns ROUTED if the load is done and routed to a frame, NOT_ROUTED or + // corresponding error codes otherwise. + RoutingStatus RouteToFrame(const char* url, + bool is_javascript_url, + const char* method, + const char* target, + const char* buf, + unsigned int len, + int notify_id, + Referrer referrer_flag); + + // Cancels a pending request. + void CancelResource(unsigned long id); + + // Returns the next avaiable resource id. Returns 0 if the operation fails. + // It may fail if the page has already been closed. + unsigned long GetNextResourceId(); + + // Initiates HTTP GET/POST requests. + // Returns true on success. + bool InitiateHTTPRequest(unsigned long resource_id, + WebPluginResourceClient* client, + const GURL& url, + const char* method, + const char* buf, + int len, + const char* range_info, + Referrer referrer_flag); + + gfx::Rect GetWindowClipRect(const gfx::Rect& rect); + + NPObject* GetWindowScriptNPObject(); + NPObject* GetPluginElement(); + + void SetCookie(const GURL& url, + const GURL& first_party_for_cookies, + const std::string& cookie); + std::string GetCookies(const GURL& url, + const GURL& first_party_for_cookies); + + void ShowModalHTMLDialog(const GURL& url, int width, int height, + const std::string& json_arguments, + std::string* json_retval); + void OnMissingPluginStatus(int status); + void Invalidate(); + void InvalidateRect(const gfx::Rect& rect); + + // Sets the actual Widget for the plugin. + void SetContainer(WebKit::WebPluginContainer* container); + + // Destroys the plugin instance. + // The response_handle_to_ignore parameter if not NULL indicates the + // resource handle to be left valid during plugin shutdown. + void TearDownPluginInstance(WebKit::WebURLLoader* loader_to_ignore); + + // WebURLLoaderClient implementation. We implement this interface in the + // renderer process, and then use the simple WebPluginResourceClient interface + // to relay the callbacks to the plugin. + virtual void willSendRequest(WebKit::WebURLLoader* loader, + WebKit::WebURLRequest& request, + const WebKit::WebURLResponse&); + virtual void didSendData(WebKit::WebURLLoader* loader, + unsigned long long bytes_sent, + unsigned long long total_bytes_to_be_sent); + virtual void didReceiveResponse(WebKit::WebURLLoader* loader, + const WebKit::WebURLResponse& response); + virtual void didReceiveData(WebKit::WebURLLoader* loader, const char *buffer, + int length); + virtual void didFinishLoading(WebKit::WebURLLoader* loader); + virtual void didFail(WebKit::WebURLLoader* loader, const WebKit::WebURLError&); + + // Helper function to remove the stored information about a resource + // request given its index in m_clients. + void RemoveClient(size_t i); + + // Helper function to remove the stored information about a resource + // request given a handle. + void RemoveClient(WebKit::WebURLLoader* loader); + + void HandleURLRequest(const char* url, + const char *method, + const char* target, + const char* buf, + unsigned int len, + int notify_id, + bool popups_allowed); + + void CancelDocumentLoad(); + + void InitiateHTTPRangeRequest( + const char* url, const char* range_info, int pending_request_id); + + void SetDeferResourceLoading(unsigned long resource_id, bool defer); + + // Ignore in-process plugins mode for this flag. + bool IsOffTheRecord() { return false; } + + // Handles HTTP multipart responses, i.e. responses received with a HTTP + // status code of 206. + void HandleHttpMultipartResponse(const WebKit::WebURLResponse& response, + WebPluginResourceClient* client); + + void HandleURLRequestInternal(const char* url, + const char* method, + const char* target, + const char* buf, + unsigned int len, + int notify_id, + bool popups_allowed, + Referrer referrer_flag); + + // Tears down the existing plugin instance and creates a new plugin instance + // to handle the response identified by the loader parameter. + bool ReinitializePluginForResponse(WebKit::WebURLLoader* loader); + + // Delayed task for downloading the plugin source URL. + void OnDownloadPluginSrcUrl(); + + struct ClientInfo { + unsigned long id; + WebPluginResourceClient* client; + WebKit::WebURLRequest request; + bool pending_failure_notification; + linked_ptr<WebKit::WebURLLoader> loader; + }; + + // Helper functions + WebPluginResourceClient* GetClientFromLoader(WebKit::WebURLLoader* loader); + ClientInfo* GetClientInfoFromLoader(WebKit::WebURLLoader* loader); + + // Helper function to set the referrer on the request passed in. + void SetReferrer(WebKit::WebURLRequest* request, Referrer referrer_flag); + + // Returns DevToolsAgent for the frame or 0. + WebKit::WebDevToolsAgent* GetDevToolsAgent(); + + std::vector<ClientInfo> clients_; + + bool windowless_; + gfx::PluginWindowHandle window_; + bool accepts_input_events_; + base::WeakPtr<WebPluginPageDelegate> page_delegate_; + WebKit::WebFrame* webframe_; + + WebPluginDelegate* delegate_; + + // This is just a weak reference. + WebKit::WebPluginContainer* container_; + + typedef std::map<WebPluginResourceClient*, + webkit_glue::MultipartResponseDelegate*> + MultiPartResponseHandlerMap; + // Tracks HTTP multipart response handlers instantiated for + // a WebPluginResourceClient instance. + MultiPartResponseHandlerMap multi_part_response_map_; + + // The plugin source URL. + GURL plugin_url_; + + // Indicates if the download would be initiated by the plugin or us. + bool load_manually_; + + // Indicates if this is the first geometry update received by the plugin. + bool first_geometry_update_; + + // Set to true if the next response error should be ignored. + bool ignore_response_error_; + + // The current plugin geometry and clip rectangle. + WebPluginGeometry geometry_; + + // The mime type of the plugin. + std::string mime_type_; + + // Holds the list of argument names and values passed to the plugin. We keep + // these so that we can re-initialize the plugin if we need to. + std::vector<std::string> arg_names_; + std::vector<std::string> arg_values_; + + ScopedRunnableMethodFactory<WebPluginImpl> method_factory_; + + DISALLOW_COPY_AND_ASSIGN(WebPluginImpl); +}; + +} // namespace webkit_glue + +#endif // #ifndef WEBKIT_GLUE_WEBPLUGIN_IMPL_H_ diff --git a/webkit/glue/plugins/webplugin_impl_unittest.cc b/webkit/glue/plugins/webplugin_impl_unittest.cc new file mode 100644 index 0000000..e70e39a --- /dev/null +++ b/webkit/glue/plugins/webplugin_impl_unittest.cc @@ -0,0 +1,232 @@ +// 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 "base/string_util.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/WebKit/chromium/public/WebCString.h" +#include "third_party/WebKit/WebKit/chromium/public/WebString.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h" +#include "webkit/glue/plugins/webplugin_impl.h" + +using WebKit::WebHTTPBody; +using WebKit::WebString; +using WebKit::WebURLRequest; +using webkit_glue::WebPluginImpl; + +namespace { + +class WebPluginImplTest : public testing::Test { +}; + +} + +static std::string GetHeader(const WebURLRequest& request, const char* name) { + std::string result; + TrimWhitespace( + request.httpHeaderField(WebString::fromUTF8(name)).utf8(), + TRIM_ALL, + &result); + return result; +} + +static std::string GetBodyText(const WebURLRequest& request) { + const WebHTTPBody& body = request.httpBody(); + if (body.isNull()) + return std::string(); + + std::string result; + size_t i = 0; + WebHTTPBody::Element element; + while (body.elementAt(i++, element)) { + if (element.type == WebHTTPBody::Element::TypeData) { + result.append(element.data.data(), element.data.size()); + } else { + NOTREACHED() << "unexpected element type encountered!"; + } + } + return result; +} + +// The Host functions for NPN_PostURL and NPN_PostURLNotify +// need to parse out some HTTP headers. Make sure it works +// with the following tests + +TEST(WebPluginImplTest, PostParserSimple) { + // Test a simple case with headers & data + const char *ex1 = "foo: bar\nContent-length: 10\n\nabcdefghij"; + WebURLRequest request; + request.initialize(); + bool rv = WebPluginImpl::SetPostData(&request, ex1, + static_cast<uint32>(strlen(ex1))); + EXPECT_EQ(true, rv); + EXPECT_EQ("bar", GetHeader(request, "foo")); + EXPECT_EQ(0U, GetHeader(request, "bar").length()); + EXPECT_EQ(0U, GetHeader(request, "Content-length").length()); + EXPECT_EQ("abcdefghij", GetBodyText(request)); +} + +TEST(WebPluginImplTest, PostParserLongHeader) { + // Test a simple case with long headers + const char *ex1 = "foo: 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n\nabcdefghij"; + WebURLRequest request; + request.initialize(); + bool rv = WebPluginImpl::SetPostData(&request, ex1, + static_cast<uint32>(strlen(ex1))); + EXPECT_EQ(true, rv); + EXPECT_EQ(100U, GetHeader(request, "foo").length()); +} + +TEST(WebPluginImplTest, PostParserManyHeaders) { + // Test a simple case with long headers + const char *ex1 = "h1:h1\nh2:h2\nh3:h3\nh4:h4\nh5:h5\nh6:h6\nh7:h7\nh8:h8\nh9:h9\nh10:h10\n\nbody"; + WebURLRequest request; + request.initialize(); + bool rv = WebPluginImpl::SetPostData(&request, ex1, + static_cast<uint32>(strlen(ex1))); + EXPECT_EQ(true, rv); + EXPECT_EQ("h1", GetHeader(request, "h1")); + EXPECT_EQ("h2", GetHeader(request, "h2")); + EXPECT_EQ("h3", GetHeader(request, "h3")); + EXPECT_EQ("h4", GetHeader(request, "h4")); + EXPECT_EQ("h5", GetHeader(request, "h5")); + EXPECT_EQ("h6", GetHeader(request, "h6")); + EXPECT_EQ("h7", GetHeader(request, "h7")); + EXPECT_EQ("h8", GetHeader(request, "h8")); + EXPECT_EQ("h9", GetHeader(request, "h9")); + EXPECT_EQ("h10", GetHeader(request, "h10")); + EXPECT_EQ("body", GetBodyText(request)); +} + +TEST(WebPluginImplTest, PostParserDuplicateHeaders) { + // Test a simple case with long headers + // What value gets returned doesn't really matter. It shouldn't error + // out. + const char *ex1 = "h1:h1\nh1:h2\n\nbody"; + WebURLRequest request; + request.initialize(); + bool rv = WebPluginImpl::SetPostData(&request, ex1, + static_cast<uint32>(strlen(ex1))); + EXPECT_EQ(true, rv); +} + +TEST(WebPluginImplTest, PostParserNoHeaders) { + // Test a simple case with no headers but with data + const char *ex1 = "\nabcdefghij"; + WebURLRequest request; + request.initialize(); + bool rv = WebPluginImpl::SetPostData(&request, ex1, + static_cast<uint32>(strlen(ex1))); + EXPECT_EQ(true, rv); + EXPECT_EQ(0U, GetHeader(request, "foo").length()); + EXPECT_EQ(0U, GetHeader(request, "bar").length()); + EXPECT_EQ(0U, GetHeader(request, "Content-length").length()); + EXPECT_EQ("abcdefghij", GetBodyText(request)); +} + +TEST(WebPluginImplTest, PostParserNoBody) { + // Test a simple case with headers and no body + const char *ex1 = "Foo:bar\n\n"; + WebURLRequest request; + request.initialize(); + bool rv = WebPluginImpl::SetPostData(&request, ex1, + static_cast<uint32>(strlen(ex1))); + EXPECT_EQ(true, rv); + EXPECT_EQ("bar", GetHeader(request, "foo")); + EXPECT_EQ(0U, GetHeader(request, "bar").length()); + EXPECT_EQ(0U, GetHeader(request, "Content-length").length()); + EXPECT_EQ(0U, GetBodyText(request).length()); +} + +TEST(WebPluginImplTest, PostParserBodyWithNewLines) { + // Test a simple case with headers and no body + const char *ex1 = "Foo:bar\n\n\n\nabcdefg\n\nabcdefg"; + WebURLRequest request; + request.initialize(); + bool rv = WebPluginImpl::SetPostData(&request, ex1, + static_cast<uint32>(strlen(ex1))); + EXPECT_EQ(true, rv); + EXPECT_EQ(GetBodyText(request), "\n\nabcdefg\n\nabcdefg"); +} + +TEST(WebPluginImplTest, PostParserErrorNoBody) { + // Test with headers and no body + const char *ex1 = "Foo:bar\n"; + WebURLRequest request; + request.initialize(); + bool rv = WebPluginImpl::SetPostData(&request, ex1, + static_cast<uint32>(strlen(ex1))); + EXPECT_EQ(true, rv); +} + +TEST(WebPluginImplTest, PostParserErrorEmpty) { + // Test with an empty string + const char *ex1 = ""; + WebURLRequest request; + request.initialize(); + bool rv = WebPluginImpl::SetPostData(&request, ex1, + static_cast<uint32>(strlen(ex1))); + EXPECT_EQ(true, rv); +} + +TEST(WebPluginImplTest, PostParserEmptyName) { + // Test an error case with an empty header name field + const char *ex1 = "foo:bar\n:blat\n\nbody"; + WebURLRequest request; + request.initialize(); + bool rv = WebPluginImpl::SetPostData(&request, ex1, + static_cast<uint32>(strlen(ex1))); + EXPECT_EQ(true, rv); + EXPECT_EQ("bar", GetHeader(request, "foo")); + EXPECT_EQ("body", GetBodyText(request)); +} + +TEST(WebPluginImplTest, PostParserEmptyValue) { + // Test an error case with an empty value field + const char *ex1 = "foo:bar\nbar:\n\nbody"; + WebURLRequest request; + request.initialize(); + bool rv = WebPluginImpl::SetPostData(&request, ex1, + static_cast<uint32>(strlen(ex1))); + EXPECT_EQ(true, rv); + EXPECT_EQ("bar", GetHeader(request, "foo")); + EXPECT_EQ(0U, GetHeader(request, "bar").length()); + EXPECT_EQ("body", GetBodyText(request)); +} + +TEST(WebPluginImplTest, PostParserCRLF) { + // Test an error case with an empty value field + const char *ex1 = "foo: bar\r\nbar:\r\n\r\nbody\r\n\r\nbody2"; + WebURLRequest request; + request.initialize(); + bool rv = WebPluginImpl::SetPostData(&request, ex1, + static_cast<uint32>(strlen(ex1))); + EXPECT_EQ(true, rv); + EXPECT_EQ("bar", GetHeader(request, "foo")); + EXPECT_EQ(0U, GetHeader(request, "bar").length()); + EXPECT_EQ("body\r\n\r\nbody2", GetBodyText(request)); +} + +TEST(WebPluginImplTest, PostParserBodyWithBinaryData) { + // Test a simple case with headers and binary data. + char ex1[33] = "foo: bar\nContent-length: 10\n\n"; + unsigned int binary_data = 0xFFFFFFF0; + memcpy(ex1 + strlen("foo: bar\nContent-length: 10\n\n"), &binary_data, + sizeof(binary_data)); + + WebURLRequest request; + request.initialize(); + bool rv = WebPluginImpl::SetPostData(&request, ex1, + sizeof(ex1)/sizeof(ex1[0])); + EXPECT_EQ(true, rv); + EXPECT_EQ("bar", GetHeader(request, "foo")); + EXPECT_EQ(0U, GetHeader(request, "bar").length()); + EXPECT_EQ(0U, GetHeader(request, "Content-length").length()); + + std::string body = GetBodyText(request); + + EXPECT_EQ(0xF0, (unsigned char)body[0]); + EXPECT_EQ(0xFF, (unsigned char)body[1]); + EXPECT_EQ(0xFF, (unsigned char)body[2]); + EXPECT_EQ(0xFF, (unsigned char)body[3]); +} diff --git a/webkit/glue/plugins/webplugin_page_delegate.h b/webkit/glue/plugins/webplugin_page_delegate.h new file mode 100644 index 0000000..8bc5723 --- /dev/null +++ b/webkit/glue/plugins/webplugin_page_delegate.h @@ -0,0 +1,69 @@ +// Copyright (c) 2009 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. + +#ifndef WEBKIT_GLUE_WEBPLUGIN_PAGE_DELEGATE_ +#define WEBKIT_GLUE_WEBPLUGIN_PAGE_DELEGATE_ + +#include "gfx/native_widget_types.h" + +class GURL; + +namespace WebKit { +class WebCookieJar; +} + +namespace webkit_glue { + +class WebPluginDelegate; +struct WebPluginGeometry; + +// Used by the WebPlugin to communicate back to the containing page. +class WebPluginPageDelegate { + public: + // This method is called to create a WebPluginDelegate implementation when a + // new plugin is instanced. See webkit_glue::CreateWebPluginDelegateHelper + // for a default WebPluginDelegate implementation. + virtual WebPluginDelegate* CreatePluginDelegate( + const GURL& url, + const std::string& mime_type, + std::string* actual_mime_type) = 0; + + // Called when a windowed plugin is created. + // Lets the view delegate create anything it is using to wrap the plugin. + virtual void CreatedPluginWindow( + gfx::PluginWindowHandle handle) = 0; + + // Called when a windowed plugin is closing. + // Lets the view delegate shut down anything it is using to wrap the plugin. + virtual void WillDestroyPluginWindow( + gfx::PluginWindowHandle handle) = 0; + + // Keeps track of the necessary window move for a plugin window that resulted + // from a scroll operation. That way, all plugin windows can be moved at the + // same time as each other and the page. + virtual void DidMovePlugin( + const WebPluginGeometry& move) = 0; + + // Notifies the parent view that a load has begun. + virtual void DidStartLoadingForPlugin() = 0; + + // Notifies the parent view that all loads are finished. + virtual void DidStopLoadingForPlugin() = 0; + + // Asks the browser to show a modal HTML dialog. The dialog is passed the + // given arguments as a JSON string, and returns its result as a JSON string + // through json_retval. + virtual void ShowModalHTMLDialogForPlugin( + const GURL& url, + const gfx::Size& size, + const std::string& json_arguments, + std::string* json_retval) = 0; + + // The WebCookieJar to use for this plugin. + virtual WebKit::WebCookieJar* GetCookieJar() = 0; +}; + +} // namespace webkit_glue + +#endif // WEBKIT_GLUE_WEBPLUGIN_PAGE_DELEGATE_H_ diff --git a/webkit/glue/plugins/webplugininfo.h b/webkit/glue/plugins/webplugininfo.h new file mode 100644 index 0000000..21f34df --- /dev/null +++ b/webkit/glue/plugins/webplugininfo.h @@ -0,0 +1,47 @@ +// 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. + +#ifndef WEBKIT_GLUE_WEBPLUGININFO_H_ +#define WEBKIT_GLUE_WEBPLUGININFO_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/file_path.h" + +// Describes a mime type entry for a plugin. +struct WebPluginMimeType { + // The name of the mime type (e.g., "application/x-shockwave-flash"). + std::string mime_type; + + // A list of all the file extensions for this mime type. + std::vector<std::string> file_extensions; + + // Description of the mime type. + std::wstring description; +}; + +// Describes an available NPAPI plugin. +struct WebPluginInfo { + // The name of the plugin (i.e. Flash). + std::wstring name; + + // The path to the plugin file (DLL/bundle/library). + FilePath path; + + // The version number of the plugin file (may be OS-specific) + std::wstring version; + + // A description of the plugin that we get from its version info. + std::wstring desc; + + // A list of all the mime types that this plugin supports. + std::vector<WebPluginMimeType> mime_types; + + // Whether the plugin is enabled. + bool enabled; +}; + +#endif // WEBKIT_GLUE_WEBPLUGININFO_H_ |