// 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_