/*
	This file is a part of Awesomium, a library that makes it easy for 
	developers to embed web-content in their applications.

	Copyright (C) 2009 Adam J. Simmons

	Project Website:
	<http://princeofcode.com/awesomium.php>

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
	02110-1301 USA
*/

#ifndef __WINDOWLESS_PLUGIN_H__
#define __WINDOWLESS_PLUGIN_H__

	
#include "webkit/glue/webplugin_delegate.h"
#include "webkit/glue/webplugin.h"
#include "webkit/glue/plugins/plugin_instance.h"
#include "webkit/glue/plugins/plugin_lib.h"
#include "webkit/glue/plugins/plugin_stream_url.h"
#include "WebInputEvent.h"
#include "base/iat_patch.h"
#include "base/lazy_instance.h"
#include "base/message_loop.h"
#include "base/timer.h"

class WindowlessPlugin;

// global variable for HandleEventMessageFilterHook()
WindowlessPlugin* g_current_plugin_instance = NULL;

// Helper object for patching the SetCursor API.
base::LazyInstance<iat_patch::IATPatchFunction> g_iat_patch_set_cursor(
    base::LINKER_INITIALIZED);

using namespace webkit_glue;

class WindowlessPlugin : public WebPluginDelegate
{
public:
	webkit_glue::WebPlugin* plugin;
	scoped_refptr<NPAPI::PluginInstance> pluginInstance;
	//gfx::PluginWindowHandle parent_;
	std::string pluginURL;
	NPWindow window;
	bool needsSetWindow;
	gfx::NativeDrawingContext hdc;
#if defined(__APPLE__)
	NP_CGContext npCgContext;
	base::RepeatingTimer<WindowlessPlugin> pluginUpdateTimer;
#endif
	HHOOK handle_event_message_filter_hook_;
	HANDLE handle_event_pump_messages_event_;
  int handle_event_depth_;
	WebCursor current_windowless_cursor_;

	
	WindowlessPlugin(NPAPI::PluginInstance *pluginInstance) : needsSetWindow(false),
		handle_event_message_filter_hook_(NULL),
		handle_event_pump_messages_event_(NULL),
		handle_event_depth_(0), hdc(0)
	{
		this->pluginInstance = pluginInstance;
		pluginInstance->set_use_mozilla_user_agent();
		window.type = NPWindowTypeDrawable;
#if defined(__APPLE__)
		npCgContext.window = 0;
#endif
	}

	~WindowlessPlugin()
	{
		destroyInstance();
#if defined(__APPLE__)
		if(npCgContext.window)
			DisposeWindow(npCgContext.window);
#endif
		
		LOG(INFO) << "A WindowlessPlugin has been destroyed";
	}

	void destroyInstance()
	{
		if(pluginInstance && pluginInstance->npp()->ndata)
		{
			pluginInstance->CloseStreams();
			pluginInstance->NPP_Destroy();
			pluginInstance->set_web_plugin(0);
			pluginInstance->AddRef();
			MessageLoop::current()->ReleaseSoon(FROM_HERE, pluginInstance.get());
			pluginInstance = 0;
		}
	}

	static WindowlessPlugin* Create(const FilePath& path, const std::string& mime_type)
	{
		scoped_refptr<NPAPI::PluginLib> plugin = NPAPI::PluginLib::CreatePluginLib(path);

		if(!plugin.get())
			return 0;

		NPError rv = plugin->NP_Initialize();
		if(rv != NPERR_NO_ERROR)
			return 0;

		scoped_refptr<NPAPI::PluginInstance> instance = plugin->CreateInstance(mime_type);

		LOG(INFO) << "A WindowlessPlugin has been created";

		return new WindowlessPlugin(instance.get());
	}

	// 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)
  bool Initialize(const GURL& url, const std::vector<std::string>& arg_names,const std::vector<std::string>& arg_values, webkit_glue::WebPlugin* plugin, bool load_manually)

	{
		this->plugin = plugin;
		pluginInstance->set_web_plugin(plugin);
		
    // copied from webkit\glue\plugins\webplugin_delegate_impl_win.cc ::
    //
    // Windowless plugins can set cursors by calling the SetCursor API. This
    // works because the thread inputs of the browser UI thread and the plugin
    // thread are attached. We intercept the SetCursor API for windowless
    // plugins and remember the cursor being set. This is shipped over to the
    // browser in the HandleEvent call, which ensures that the cursor does not
    // change when a windowless plugin instance changes the cursor
    // in a background tab.
    if (!g_iat_patch_set_cursor.Pointer()->is_patched())
    {
      FilePath pluginPath = pluginInstance->plugin_lib()->plugin_info().path;

      g_iat_patch_set_cursor.Pointer()->Patch(
          pluginPath.value().c_str(), "user32.dll", "SetCursor",
          SetCursorPatch);
    }

    /**
		* We need to enforce that the Flash plugin is always initialized with a 'wmode' of 'opaque' or 'transparent'
		* because those are the two windowless modes Flash accepts. We do this by copying the passed parameters into
		* our own structure, modifying/appending the wmode, and passing the result to PluginInstance::Start.
		*/

		char** keys = new char*[arg_values.size()+1];
		char** vals = new char*[arg_values.size()+1];
		int argc = 0;

		bool hasNoWMode = true;

		for(int i = 0;; i++)
		{
			if(i == arg_values.size())
			{
				if(hasNoWMode)
				{
					keys[i] = "wmode";
					vals[i] = "opaque";
					argc++;
				}
				else
				{
					keys[i] = vals[i] = "";
					argc++;
				}
				break;
			}
			else
			{
				keys[i] = (char*) arg_names[i].data();
				vals[i] = (char*) arg_values[i].data();
				argc++;

			}

			if(strcmp(keys[i], "wmode") == 0)
			{
				if(strcmp(vals[i], "opaque") != 0 && strcmp(vals[i], "transparent") != 0)
					vals[i] = "opaque";

				hasNoWMode = false;
			}
		}

	//	for(int i = 0; i < arg_values.size()+1; i++)
		//	printf("init %s : %s\n", keys[i], vals[i]);
		
		pluginInstance->set_windowless(true);
#if defined(_WIN32)
		pluginInstance->set_window_handle(0);
#endif
		plugin->SetWindow(NULL);

		//mgdesign remove:
		//NPAPI::PluginInstance* oldInstance = NPAPI::PluginInstance::SetInitializingInstance(pluginInstance);
//		bool startResult = pluginInstance->Start(url, keys, vals, argc+1, load_manually);
		bool startResult = pluginInstance->Start(url, keys, vals, argc, load_manually);

		//mgdesign, remove: NPAPI::PluginInstance::SetInitializingInstance(oldInstance);
		pluginURL = url.spec();
		
		delete[] keys;
		delete[] vals;

		if(!startResult)
			LOG(WARNING) << "Failed to start the plugin instance of a WindowlessPlugin, loaded with URL: " << url.spec();
		
#if defined(__APPLE__)
		if(startResult)
			pluginUpdateTimer.Start(base::TimeDelta::FromMilliseconds(5), this, &WindowlessPlugin::updatePlugin);
#endif

		return startResult;
	}

	// 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.
	void PluginDestroyed()
	{
		Awesomium::WebCore::Get().purgePluginMessages();
		delete this;
	}

	// http://crbug.com/16114
	// Enforces providing a valid device context in NPWindow, so that NPP_SetWindow
	// is never called with NPNWindoTypeDrawable and NPWindow set to NULL.
	// Doing so allows removing NPP_SetWindow call during painting a windowless
	// plugin, which otherwise could trigger layout change while painting by
	// invoking NPN_Evaluate. Which would cause bad, bad crashes. Bad crashes.
	// TODO(dglazkov): If this approach doesn't produce regressions, move class to
	// webplugin_delegate_impl.h and implement for other platforms.
	/* mgdesign : hack
	class DrawableContextEnforcer {
		
	 public:
		explicit DrawableContextEnforcer(NPWindow* window)
				: window_(window),
					disposable_dc_(window && !window->window) {
			// If NPWindow is NULL, create a device context with monochrome 1x1 surface
			// and stuff it to NPWindow.
			if (disposable_dc_)
				window_->window = CreateCompatibleDC(NULL);
		}

		~DrawableContextEnforcer() {
			if (!disposable_dc_)
				return;

			DeleteDC(static_cast<HDC>(window_->window));
			window_->window = NULL;
		}

	 private:
		NPWindow* window_;
		bool disposable_dc_;
	};
	*/

	// 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.
	void UpdateGeometry(const gfx::Rect& window_rect, const gfx::Rect& clip_rect)
	{
		window.x = window_rect.x();
		window.y = window_rect.y();
		window.width = window_rect.width();
		window.height = window_rect.height();
		window.clipRect.left = clip_rect.x();
		window.clipRect.top = clip_rect.y();
		window.clipRect.right = clip_rect.x() + clip_rect.width();
		window.clipRect.bottom = clip_rect.y() + clip_rect.height();

		// mgdesign: sans doute pas nécessaire
		//DrawableContextEnforcer enforcer(&window);

		needsSetWindow = true;

#if defined(_WIN32)
		WINDOWPOS win_pos = {0};
		win_pos.x = window_rect.x();
		win_pos.y = window_rect.y();
		win_pos.cx = window_rect.width();
		win_pos.cy = window_rect.height();

		NPEvent pos_changed_event;
		pos_changed_event.event = WM_WINDOWPOSCHANGED;
		pos_changed_event.wParam = 0;
		pos_changed_event.lParam = PtrToUlong(&win_pos);

		pluginInstance->NPP_HandleEvent(&pos_changed_event);
#elif defined(__APPLE__)
		if(npCgContext.window)
			return;
		
		Rect bounds;
		bounds.top = window.y;
		bounds.left = window.x;
		bounds.bottom = window.y + window.height;
		bounds.right = window.x + window.width;
		
		CreateNewWindow(kDocumentWindowClass, 0, &bounds, &npCgContext.window);
#endif
	}

	// Tells the plugin to paint the damaged rect.  The HDC is only used for
	// windowless plugins.
	void Paint(WebKit::WebCanvas* canvas,  const gfx::Rect& rect)
	{
		// mgdesign, add this line from test_shell::webplugin_delegate_impl_win.cc
		hdc = canvas->beginPlatformPaint();

#if defined(_WIN32)
		window.window = (void*)hdc;
#elif defined(__APPLE__)
		CGContextSaveGState(hdc);
		CGContextTranslateCTM(hdc, window.x, window.y);
		npCgContext.context = hdc;
		//npCgContext.window = 0;
		
		/*Rect bounds;
		bounds.top = window.y;
		bounds.left = window.x;
		bounds.bottom = window.y + window.height;
		bounds.right = window.x + window.width;*/
		
		//CreateNewWindow(kDocumentWindowClass, 0, &bounds, &cgCtxt.window);
		
		window.window = (void*)&npCgContext;
#endif

		if(needsSetWindow)
		{
			pluginInstance->NPP_SetWindow(&window);
			needsSetWindow = false;
		}
		
#if defined(_WIN32)
		RECT damage_rect_win;
		damage_rect_win.left   = rect.x();  // + window_rect_.x();
		damage_rect_win.top    = rect.y();  // + window_rect_.y();
		damage_rect_win.right  = damage_rect_win.left + rect.width();
		damage_rect_win.bottom = damage_rect_win.top + rect.height();

		NPEvent paint_event;
		paint_event.event = WM_PAINT;
		// NOTE: NPAPI is not 64bit safe.  It puts pointers into 32bit values.
		paint_event.wParam = PtrToUlong(hdc);
		paint_event.lParam = PtrToUlong(&damage_rect_win);
		pluginInstance->NPP_HandleEvent(&paint_event);
		
#elif defined(__APPLE__)
		
		EventRecord event;
		event.what = updateEvt;
		event.message = (long unsigned int)hdc;
		event.when = TickCount();
		event.where.h = 0;
		event.where.v = 0;
		event.modifiers = 0;
		
		//NPEvent paint_event;
		pluginInstance->NPP_HandleEvent(&event);
		
		CGContextRestoreGState(hdc);
#endif

		//mgdesign, add this line from test_shell::webplugin_delegate_impl_win.cc
		canvas->endPlatformPaint();
	}

	// Tells the plugin to print itself.
	void Print(gfx::NativeDrawingContext hdc)
	{
		// Disabling the call to NPP_Print as it causes a crash in
		// flash in some cases. In any case this does not work as expected
		// as the EMF meta file dc passed in needs to be created with the
		// the plugin window dc as its sibling dc and the window rect
		// in .01 mm units.
	#if 0
		NPPrint npprint;
		npprint.mode = NP_EMBED;
		npprint.print.embedPrint.platformPrint = reinterpret_cast<void*>(hdc);
		npprint.print.embedPrint.window = window_;
		instance()->NPP_Print(&npprint);
	#endif
	}

	// Informs the plugin that it now has focus.
	void SetFocus()
	{
#if defined(_WIN32)
		NPEvent focusEvent;
		focusEvent.event = WM_SETFOCUS;
		focusEvent.wParam = 0;
		focusEvent.lParam = 0;

		pluginInstance->NPP_HandleEvent(&focusEvent);
#endif
	}

	// For windowless plugins, gives them a user event like mouse/keyboard.
	// Returns whether the event was handled.
	bool HandleEvent(NPEvent* event, WebCursor* cursor)
	{
		return pluginInstance->NPP_HandleEvent(event) != 0;
	}

	// Gets the NPObject associated with the plugin for scripting.
	NPObject* GetPluginScriptableObject()
	{
		return pluginInstance->GetPluginScriptableObject();
	}

	// Receives notification about a resource load that the plugin initiated
	// for a frame.
  void DidFinishLoadWithReason(const GURL& url, NPReason reason, int notify_id)
	{
		pluginInstance->DidFinishLoadWithReason(url, reason, notify_id);
	}
  
	// Returns the process id of the process that is running the plugin.
	int GetProcessId()
	{
#if defined(_WIN32)
		return ::GetCurrentProcessId();
#else
		return getpid();
#endif
	}

	// The result of the script execution is returned via this function.
  void SendJavaScriptStream(const GURL& url, const std::string& result,bool success,int notify_id)
	{
		pluginInstance->SendJavaScriptStream(url, result, success, notify_id);
	}

	// Receives notification about data being available. 
	void DidReceiveManualResponse(const GURL& url, const std::string& mime_type, const std::string& headers, uint32 expected_length, uint32 last_modified)
	{
		pluginInstance->DidReceiveManualResponse(url, mime_type, headers, expected_length, last_modified);
	}

	// Receives the data.
	void DidReceiveManualData(const char* buffer, int length)
	{
		pluginInstance->DidReceiveManualData(buffer, length);
	}

	// Indicates end of data load.
	void DidFinishManualLoading()
	{
		pluginInstance->DidFinishManualLoading();
	}

	// Indicates a failure in data receipt.
	void DidManualLoadFail()
	{
		pluginInstance->DidManualLoadFail();
	}

	// Only Supported when the plugin is the default plugin.
	void InstallMissingPlugin() {
	
		//mgdesign
	/*	NPEvent evt;
		evt.event = PluginInstallerImpl::kInstallMissingPluginMessage;
		evt.lParam = 0;
		evt.wParam = 0;
		pluginInstance->NPP_HandleEvent(&evt);	
	*/
	}

 // Creates a WebPluginResourceClient instance and returns the same.
	//mgdesign, chrome v5:
	//WebPluginResourceClient* CreateResourceClient(unsigned long resource_id, const GURL& url,   int notify_id)
	//mgdesign, chrome v4:
	WebPluginResourceClient* CreateResourceClient(int resource_id, const GURL& url,   int notify_id)
	{
		/*
		if(stream)
		{
			NPAPI::PluginStream* plugin_stream = reinterpret_cast<NPAPI::PluginStream*>(stream);
			plugin_stream->CancelRequest();

			return plugin_stream->AsResourceClient();
		}

		if(notify_needed)
      pluginInstance->SetURLLoadData(GURL(url), notify_data);

		return pluginInstance->CreateStream(resource_id, url, "", notify_needed, (void*)notify_data);
		*/
		return pluginInstance->CreateStream(resource_id, url, "", notify_id);

	}

	// Notifies the delegate about a Get/Post URL request getting routed
	void URLRequestRouted(const std::string&url, bool notify_needed, intptr_t notify_data)
	{
		//mgdesign
		//if(notify_needed)
		//	pluginInstance->SetURLLoadData(GURL(url.c_str()), notify_data);
	}


 // mgdesign ---------------------------------------------------------------------------
 // add gestion des events sur le Flash; from test_shell:weplugin_delegate_impl.win.cc

	static bool NPEventFromWebMouseEvent(const WebMouseEvent& event,NPEvent *np_event) {
		np_event->lParam = static_cast<uint32>(MAKELPARAM(event.windowX,event.windowY));
		np_event->wParam = 0;

		if (event.modifiers & WebInputEvent::ControlKey)
			np_event->wParam |= MK_CONTROL;
		if (event.modifiers & WebInputEvent::ShiftKey)
			np_event->wParam |= MK_SHIFT;
		if (event.modifiers & WebInputEvent::LeftButtonDown)
			np_event->wParam |= MK_LBUTTON;
		if (event.modifiers & WebInputEvent::MiddleButtonDown)
			np_event->wParam |= MK_MBUTTON;
		if (event.modifiers & WebInputEvent::RightButtonDown)
			np_event->wParam |= MK_RBUTTON;

		switch (event.type) {
			case WebInputEvent::MouseMove:
			case WebInputEvent::MouseLeave:
			case WebInputEvent::MouseEnter:
				np_event->event = WM_MOUSEMOVE;
				return true;
			case WebInputEvent::MouseDown:
				switch (event.button) {
					case WebMouseEvent::ButtonLeft:
						np_event->event = WM_LBUTTONDOWN;
						break;
					case WebMouseEvent::ButtonMiddle:
						np_event->event = WM_MBUTTONDOWN;
						break;
					case WebMouseEvent::ButtonRight:
						np_event->event = WM_RBUTTONDOWN;
						break;
				}
				return true;
			case WebInputEvent::MouseUp:
				switch (event.button) {
					case WebMouseEvent::ButtonLeft:
						np_event->event = WM_LBUTTONUP;
						break;
					case WebMouseEvent::ButtonMiddle:
						np_event->event = WM_MBUTTONUP;
						break;
					case WebMouseEvent::ButtonRight:
						np_event->event = WM_RBUTTONUP;
						break;
				}
				return true;
			default:
				NOTREACHED();
				return false;
		}
	}

	static bool NPEventFromWebKeyboardEvent(const WebKeyboardEvent& event,NPEvent *np_event) {
		np_event->wParam = event.windowsKeyCode;

		switch (event.type) {
			case WebInputEvent::KeyDown:
				np_event->event = WM_KEYDOWN;
				np_event->lParam = 0;
				return true;
			case WebInputEvent::KeyUp:
				np_event->event = WM_KEYUP;
				np_event->lParam = 0x8000;
				return true;
			default:
				NOTREACHED();
				return false;
		}
	}

	static bool NPEventFromWebInputEvent(const WebInputEvent& event,NPEvent* np_event) {
		switch (event.type) {
			case WebInputEvent::MouseMove:
			case WebInputEvent::MouseLeave:
			case WebInputEvent::MouseEnter:
			case WebInputEvent::MouseDown:
			case WebInputEvent::MouseUp:
				if (event.size < sizeof(WebMouseEvent)) {
					NOTREACHED();
					return false;
				}
				return NPEventFromWebMouseEvent(
						*static_cast<const WebMouseEvent*>(&event), np_event);
			case WebInputEvent::KeyDown:
			case WebInputEvent::KeyUp:
				if (event.size < sizeof(WebKeyboardEvent)) {
					NOTREACHED();
					return false;
				}
				return NPEventFromWebKeyboardEvent(
						*static_cast<const WebKeyboardEvent*>(&event), np_event);
			default:
				return false;
		}
	}

	bool ShouldTrackEventForModalLoops(NPEvent* event) {
		if (event->event == WM_RBUTTONDOWN)
			return true;
		return false;
	}


	void OnModalLoopEntered() {
		//DCHECK(handle_event_pump_messages_event_ != NULL);
		SetEvent(handle_event_pump_messages_event_);

		MessageLoop::current()->SetNestableTasksAllowed(true);

		UnhookWindowsHookEx(handle_event_message_filter_hook_);
		handle_event_message_filter_hook_ = NULL;
	}


	static LRESULT CALLBACK HandleEventMessageFilterHook(int code, WPARAM wParam, LPARAM lParam) 
	{
		
		if (g_current_plugin_instance) {
			g_current_plugin_instance->OnModalLoopEntered();
		} else {
			NOTREACHED();
		}
		return CallNextHookEx(NULL, code, wParam, lParam);
	}

	bool HandleInputEvent(const WebKit::WebInputEvent &event,WebKit::WebCursorInfo *cursor_info) 
	{


		DCHECK(cursor_info != NULL);

		NPEvent np_event;
		if (!NPEventFromWebInputEvent(event, &np_event)) return false;

		// A windowless plugin can enter a modal loop in a NPP_HandleEvent call.
		// For e.g. Flash puts up a context menu when we right click on the
		// windowless plugin area. We detect this by setting up a message filter
		// hook pror to calling NPP_HandleEvent on the plugin and unhook on
		// return from NPP_HandleEvent. If the plugin does enter a modal loop
		// in that context we unhook on receiving the first notification in
		// the message filter hook.
		if (ShouldTrackEventForModalLoops(&np_event)) 
			handle_event_message_filter_hook_ =  SetWindowsHookEx(WH_MSGFILTER, HandleEventMessageFilterHook, NULL,  GetCurrentThreadId());

		bool old_task_reentrancy_state = MessageLoop::current()->NestableTasksAllowed();


		// Maintain a local/global stack for the g_current_plugin_instance variable
		// as this may be a nested invocation.
//		WebPluginDelegateImpl* last_plugin_instance = g_current_plugin_instance;
		WindowlessPlugin* last_plugin_instance = g_current_plugin_instance;

		g_current_plugin_instance = this;

		handle_event_depth_++;

		bool ret = pluginInstance->NPP_HandleEvent(&np_event) != 0;

		if (np_event.event == WM_MOUSEMOVE) {
			// Snag a reference to the current cursor ASAP in case the plugin modified
			// it. There is a nasty race condition here with the multiprocess browser
			// as someone might be setting the cursor in the main process as well.
			current_windowless_cursor_.GetCursorInfo(cursor_info);
		}

		handle_event_depth_--;

		g_current_plugin_instance = last_plugin_instance;

		MessageLoop::current()->SetNestableTasksAllowed(old_task_reentrancy_state);

		// We could have multiple NPP_HandleEvent calls nested together in case
		// the plugin enters a modal loop. Reset the pump messages event when
		// the outermost NPP_HandleEvent call unwinds.
		if (handle_event_depth_ == 0) {
			ResetEvent(handle_event_pump_messages_event_);
		}

		return ret;
	}

	void updatePlugin()
	{
#if defined(__APPLE__)
		static EventRecord event;
		event.what = nullEvent;
		event.message = 0;
		event.when = TickCount();
		event.where.h = 0;
		event.where.v = 0;
		event.modifiers = 0;
		
		pluginInstance->NPP_HandleEvent(&event);
		
		event.when = TickCount();
		pluginInstance->NPP_HandleEvent(&event);
		
		event.when = TickCount();
		pluginInstance->NPP_HandleEvent(&event);
		
		event.when = TickCount();
		pluginInstance->NPP_HandleEvent(&event);
#endif
	}

	//mgdesign, chrome v5:
	//WebPluginResourceClient* CreateSeekableResourceClient(  unsigned long resource_id, int range_request_id)
	//mgdesign, chrome v4:
  WebPluginResourceClient* CreateSeekableResourceClient(  int resource_id, int range_request_id)
	{
		return NULL;
	}

  static HCURSOR WINAPI SetCursorPatch(HCURSOR cursor)
  {
    // The windowless flash plugin periodically calls SetCursor in a wndproc
    // instantiated on the plugin thread. This causes annoying cursor flicker
    // when the mouse is moved on a foreground tab, with a windowless plugin
    // instance in a background tab. We just ignore the call here.
    if (!g_current_plugin_instance)
      return GetCursor();

    // It is ok to pass NULL here to GetCursor as we are not looking for cursor
    // types defined by Webkit.
    HCURSOR previous_cursor =
        g_current_plugin_instance->current_windowless_cursor_.GetCursor(NULL);

    g_current_plugin_instance->current_windowless_cursor_.InitFromExternalCursor(
        cursor);
    return previous_cursor;
  }

};



#endif
