// Copyright (c) 2012 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. // TODO: Need to deal with NPAPI's NPSavedData. // I haven't seen plugins use it yet. #ifndef CONTENT_CHILD_NPAPI_PLUGIN_INSTANCE_H_ #define CONTENT_CHILD_NPAPI_PLUGIN_INSTANCE_H_ #include <map> #include <stack> #include <string> #include <vector> #include "base/basictypes.h" #include "base/files/file_path.h" #include "base/memory/ref_counted.h" #include "third_party/npapi/bindings/npapi.h" #include "third_party/npapi/bindings/nphostapi.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/point.h" #include "ui/gfx/rect.h" #include "url/gurl.h" namespace base { class MessageLoop; } namespace content { class PluginLib; class PluginHost; class PluginStream; class PluginStreamUrl; class WebPlugin; class WebPluginResourceClient; #if defined(OS_MACOSX) class ScopedCurrentPluginEvent; #endif // A PluginInstance is an active, running instance of a Plugin. // A single plugin may have many PluginInstances. class PluginInstance : public base::RefCountedThreadSafe<PluginInstance> { public: // Create a new instance of a plugin. The PluginInstance // will hold a reference to the plugin. PluginInstance(PluginLib* plugin, const std::string &mime_type); // Activates the instance by calling NPP_New. // This should be called after our instance is all // setup from the host side and we are ready to receive // requests from the plugin. We must not call any // functions on the plugin instance until start has // been called. // // url: The instance URL. // param_names: the list of names of attributes passed via the // element. // param_values: the list of values corresponding to param_names // param_count: number of attributes // load_manually: 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) // bool Start(const GURL& url, char** const param_names, char** const param_values, int param_count, bool load_manually); // NPAPI's instance identifier for this instance NPP npp() { return npp_; } // Get/Set for the instance's window handle. gfx::PluginWindowHandle window_handle() const { return window_handle_; } void set_window_handle(gfx::PluginWindowHandle value) { window_handle_ = value; } // Get/Set whether this instance is in Windowless mode. // Default is false. bool windowless() { return windowless_; } void set_windowless(bool value) { windowless_ = value; } // Get/Set whether this instance is transparent. This only applies to // windowless plugins. Transparent plugins require that webkit paint the // background. // Default is true for all plugins other than Flash. For Flash, we default to // opaque since it always tells us if it's transparent during NPP_New. bool transparent() { return transparent_; } void set_transparent(bool value) { transparent_ = value; } // Get/Set the WebPlugin associated with this instance WebPlugin* webplugin() { return webplugin_; } void set_web_plugin(WebPlugin* webplugin) { webplugin_ = webplugin; } // Get the mimeType for this plugin stream const std::string &mime_type() { return mime_type_; } PluginLib* plugin_lib() { return plugin_.get(); } #if defined(OS_MACOSX) // Get/Set the Mac NPAPI drawing and event models NPDrawingModel drawing_model() { return drawing_model_; } void set_drawing_model(NPDrawingModel value) { drawing_model_ = value; } NPEventModel event_model() { return event_model_; } void set_event_model(NPEventModel value) { event_model_ = value; } // Updates the instance's tracking of the location of the plugin location // relative to the upper left of the screen. void set_plugin_origin(const gfx::Point& origin) { plugin_origin_ = origin; } // Updates the instance's tracking of the frame of the containing window // relative to the upper left of the screen. void set_window_frame(const gfx::Rect& frame) { containing_window_frame_ = frame; } #endif // Creates a stream for sending an URL. If notify_id is non-zero, it will // send a notification to the plugin when the stream is complete; otherwise it // will not. Set object_url to true if the load is for the object tag's url, // or false if it's for a url that the plugin fetched through // NPN_GetUrl[Notify]. PluginStreamUrl* CreateStream(unsigned long resource_id, const GURL& url, const std::string& mime_type, int notify_id); // For each instance, we track all streams. When the // instance closes, all remaining streams are also // closed. All streams associated with this instance // should call AddStream so that they can be cleaned // up when the instance shuts down. void AddStream(PluginStream* stream); // This is called when a stream is closed. We remove the stream from the // list, which releases the reference maintained to the stream. void RemoveStream(PluginStream* stream); // Closes all open streams on this instance. void CloseStreams(); // Returns the WebPluginResourceClient object for a stream that has become // seekable. WebPluginResourceClient* GetRangeRequest(int id); // Have the plugin create its script object. NPObject* GetPluginScriptableObject(); // Returns the form value of this instance. bool GetFormValue(base::string16* value); // WebViewDelegate methods that we implement. This is for handling // callbacks during getURLNotify. void DidFinishLoadWithReason(const GURL& url, NPReason reason, int notify_id); // If true, send the Mozilla user agent instead of Chrome's to the plugin. bool use_mozilla_user_agent() { return use_mozilla_user_agent_; } void set_use_mozilla_user_agent() { use_mozilla_user_agent_ = true; } // If the plugin instance is backed by a texture, return its ID in the // compositor's namespace. Otherwise return 0. Returns 0 by default. unsigned GetBackingTextureId(); // Helper that implements NPN_PluginThreadAsyncCall semantics void PluginThreadAsyncCall(void (*func)(void *), void* userData); uint32 ScheduleTimer(uint32 interval, NPBool repeat, void (*func)(NPP id, uint32 timer_id)); void UnscheduleTimer(uint32 timer_id); bool ConvertPoint(double source_x, double source_y, NPCoordinateSpace source_space, double* dest_x, double* dest_y, NPCoordinateSpace dest_space); NPError PopUpContextMenu(NPMenu* menu); // // NPAPI methods for calling the Plugin Instance // NPError NPP_New(unsigned short, short, char *[], char *[]); NPError NPP_SetWindow(NPWindow*); NPError NPP_NewStream(NPMIMEType, NPStream*, NPBool, unsigned short*); NPError NPP_DestroyStream(NPStream*, NPReason); int NPP_WriteReady(NPStream*); int NPP_Write(NPStream*, int, int, void*); void NPP_StreamAsFile(NPStream*, const char*); void NPP_URLNotify(const char*, NPReason, void*); NPError NPP_GetValue(NPPVariable, void*); NPError NPP_SetValue(NPNVariable, void*); short NPP_HandleEvent(void*); void NPP_Destroy(); bool NPP_Print(NPPrint* platform_print); void NPP_URLRedirectNotify(const char* url, int32_t status, void* notify_data); void SendJavaScriptStream(const GURL& url, const std::string& result, bool success, int notify_id); void DidReceiveManualResponse(const GURL& url, const std::string& mime_type, const std::string& headers, uint32 expected_length, uint32 last_modified); void DidReceiveManualData(const char* buffer, int length); void DidFinishManualLoading(); void DidManualLoadFail(); void PushPopupsEnabledState(bool enabled); void PopPopupsEnabledState(); bool popups_allowed() const { return popups_enabled_stack_.empty() ? false : popups_enabled_stack_.top(); } // Initiates byte range reads for plugins. void RequestRead(NPStream* stream, NPByteRange* range_list); // Handles GetURL/GetURLNotify/PostURL/PostURLNotify requests initiated // by plugins. void RequestURL(const char* url, const char* method, const char* target, const char* buf, unsigned int len, bool notify, void* notify_data); // Handles NPN_URLRedirectResponse calls issued by plugins in response to // HTTP URL redirect notifications. void URLRedirectResponse(bool allow, void* notify_data); bool handles_url_redirects() const { return handles_url_redirects_; } private: friend class base::RefCountedThreadSafe<PluginInstance>; #if defined(OS_MACOSX) friend class ScopedCurrentPluginEvent; // Sets the event that the plugin is currently handling. The object is not // owned or copied, so the caller must call this again with NULL before the // event pointer becomes invalid. Clients use ScopedCurrentPluginEvent rather // than calling this directly. void set_currently_handled_event(NPCocoaEvent* event) { currently_handled_event_ = event; } #endif ~PluginInstance(); void OnPluginThreadAsyncCall(void (*func)(void *), void* userData); void OnTimerCall(void (*func)(NPP id, uint32 timer_id), NPP id, uint32 timer_id); bool IsValidStream(const NPStream* stream); void GetNotifyData(int notify_id, bool* notify, void** notify_data); // This is a hack to get the real player plugin to work with chrome // The real player plugin dll(nppl3260) when loaded by firefox is loaded via // the NS COM API which is analogous to win32 COM. So the NPAPI functions in // the plugin are invoked via an interface by firefox. The plugin instance // handle which is passed to every NPAPI method is owned by the real player // plugin, i.e. it expects the ndata member to point to a structure which // it knows about. Eventually it dereferences this structure and compares // a member variable at offset 0x24(Version 6.0.11.2888) /2D (Version // 6.0.11.3088) with 0 and on failing this check, takes a different code // path which causes a crash. Safari and Opera work with version 6.0.11.2888 // by chance as their ndata structure contains a 0 at the location which real // player checks:(. They crash with version 6.0.11.3088 as well. The // following member just adds a 96 byte padding to our PluginInstance class // which is passed in the ndata member. This magic number works correctly on // Vista with UAC on or off :(. // NOTE: Please dont change the ordering of the member variables // New members should be added after this padding array. // TODO(iyengar) : Disassemble the Realplayer ndata structure and look into // the possiblity of conforming to it (http://b/issue?id=936667). We // could also log a bug with Real, which would save the effort. uint8 zero_padding_[96]; scoped_refptr<PluginLib> plugin_; NPP npp_; scoped_refptr<PluginHost> host_; NPPluginFuncs* npp_functions_; std::vector<scoped_refptr<PluginStream> > open_streams_; gfx::PluginWindowHandle window_handle_; bool windowless_; bool transparent_; WebPlugin* webplugin_; std::string mime_type_; GURL get_url_; intptr_t get_notify_data_; bool use_mozilla_user_agent_; #if defined(OS_MACOSX) NPDrawingModel drawing_model_; NPEventModel event_model_; gfx::Point plugin_origin_; gfx::Rect containing_window_frame_; NPCocoaEvent* currently_handled_event_; // weak #endif base::MessageLoop* message_loop_; scoped_refptr<PluginStreamUrl> plugin_data_stream_; // This flag if true indicates that the plugin data would be passed from // webkit. if false indicates that the plugin should download the data. bool load_manually_; // Stack indicating if popups are to be enabled for the outgoing // NPN_GetURL/NPN_GetURLNotify calls. std::stack<bool> popups_enabled_stack_; // True if in CloseStreams(). bool in_close_streams_; // List of files created for the current plugin instance. File names are // added to the list every time the NPP_StreamAsFile function is called. std::vector<base::FilePath> files_created_; // Next unusued timer id. uint32 next_timer_id_; // Map of timer id to settings for timer. struct TimerInfo { uint32 interval; bool repeat; }; typedef std::map<uint32, TimerInfo> TimerMap; TimerMap timers_; // Tracks pending GET/POST requests so that the plugin-given data doesn't // cross process boundaries to an untrusted process. typedef std::map<int, void*> PendingRequestMap; PendingRequestMap pending_requests_; int next_notify_id_; // Used to track pending range requests so that when WebPlugin replies to us // we can match the reply to the stream. typedef std::map<int, scoped_refptr<PluginStream> > PendingRangeRequestMap; PendingRangeRequestMap pending_range_requests_; int next_range_request_id_; // The plugin handles the NPAPI URL redirect notification API. // See here https://wiki.mozilla.org/NPAPI:HTTPRedirectHandling bool handles_url_redirects_; DISALLOW_COPY_AND_ASSIGN(PluginInstance); }; #if defined(OS_MACOSX) // Helper to simplify correct usage of set_currently_handled_event. // Instantiating will set |instance|'s currently handled to |event| for the // lifetime of the object, then NULL when it goes out of scope. class ScopedCurrentPluginEvent { public: ScopedCurrentPluginEvent(PluginInstance* instance, NPCocoaEvent* event); ~ScopedCurrentPluginEvent(); private: scoped_refptr<PluginInstance> instance_; DISALLOW_COPY_AND_ASSIGN(ScopedCurrentPluginEvent); }; #endif } // namespace content #endif // CONTENT_CHILD_NPAPI_PLUGIN_INSTANCE_H_