diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index e3d3f282200e4..7c225af53d6b3 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -419,6 +419,7 @@ class nsDummyJavaPluginOwner : public nsIPluginInstanceOwner NPError ShowNativeContextMenu(NPMenu* menu, void* event); NPBool ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace); + void SendIdleEvent(); NS_DECL_CYCLE_COLLECTION_CLASS(nsDummyJavaPluginOwner) @@ -563,6 +564,11 @@ nsDummyJavaPluginOwner::SetEventModel(PRInt32 eventModel) return NS_ERROR_NOT_IMPLEMENTED; } +void +nsDummyJavaPluginOwner::SendIdleEvent() +{ +} + /** * An indirect observer object that means we don't have to implement nsIObserver * on nsGlobalWindow, where any script could see it. diff --git a/layout/generic/nsObjectFrame.cpp b/layout/generic/nsObjectFrame.cpp index 0891f6a682997..fbba3bfd22415 100644 --- a/layout/generic/nsObjectFrame.cpp +++ b/layout/generic/nsObjectFrame.cpp @@ -224,9 +224,9 @@ enum { XKeyPress = KeyPress }; static PRLogModuleInfo *nsObjectFrameLM = PR_NewLogModule("nsObjectFrame"); #endif /* PR_LOGGING */ -#define NORMAL_PLUGIN_DELAY 20 -// must avoid audio skipping/delays -#define HIDDEN_PLUGIN_DELAY 125 +#if defined(XP_MACOSX) && !defined(NP_NO_CARBON) +#define MAC_CARBON_PLUGINS +#endif // special class for handeling DOM context menu events because for // some reason it starves other mouse events if implemented on the @@ -257,7 +257,6 @@ class nsPluginDOMContextMenuListener : public nsIDOMContextMenuListener class nsPluginInstanceOwner : public nsIPluginInstanceOwner, public nsIPluginTagInfo, - public nsITimerCallback, public nsIDOMMouseListener, public nsIDOMMouseMotionListener, public nsIDOMKeyListener, @@ -325,11 +324,11 @@ class nsPluginInstanceOwner : public nsIPluginInstanceOwner, void Paint(const nsRect& aDirtyRect, HPS aHPS); #endif - // nsITimerCallback interface - NS_DECL_NSITIMERCALLBACK - +#ifdef MAC_CARBON_PLUGINS void CancelTimer(); - void StartTimer(unsigned int aDelay); + void StartTimer(PRBool isVisible); +#endif + void SendIdleEvent(); // nsIScrollPositionListener interface NS_IMETHOD ScrollPositionWillChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY); @@ -432,7 +431,6 @@ class nsPluginInstanceOwner : public nsIPluginInstanceOwner, nsCString mDocumentBase; char *mTagText; nsCOMPtr mWidget; - nsCOMPtr mPluginTimer; nsCOMPtr mPluginHost; #ifdef XP_MACOSX @@ -452,7 +450,6 @@ class nsPluginInstanceOwner : public nsIPluginInstanceOwner, // If true, destroy the widget on destruction. Used when plugin stop // is being delayed to a safer point in time. PRPackedBool mDestroyWidget; - PRPackedBool mTimerCanceled; PRUint16 mNumCachedAttrs; PRUint16 mNumCachedParams; char **mCachedAttrParamNames; @@ -1368,7 +1365,7 @@ nsObjectFrame::PrintPlugin(nsIRenderingContext& aRenderingContext, window.clipRect.left = 0; window.clipRect.right = 0; // platform specific printing code -#if defined(XP_MACOSX) && !defined(NP_NO_CARBON) +#ifdef MAC_CARBON_PLUGINS nsSize contentSize = GetContentRect().Size(); window.x = 0; window.y = 0; @@ -1932,7 +1929,9 @@ nsObjectFrame::HandleEvent(nsPresContext* aPresContext, #endif if (anEvent->message == NS_DESTROY) { +#ifdef MAC_CARBON_PLUGINS mInstanceOwner->CancelTimer(); +#endif return rv; } @@ -2432,7 +2431,6 @@ nsPluginInstanceOwner::nsPluginInstanceOwner() mCachedAttrParamNames = nsnull; mCachedAttrParamValues = nsnull; mDestroyWidget = PR_FALSE; - mTimerCanceled = PR_TRUE; #ifdef MOZ_COMPOSITED_PLUGINS mLastPoint = nsIntPoint(0,0); @@ -2463,8 +2461,9 @@ nsPluginInstanceOwner::~nsPluginInstanceOwner() PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG, ("nsPluginInstanceOwner %p deleted\n", this)); - // shut off the timer. +#ifdef MAC_CARBON_PLUGINS CancelTimer(); +#endif mObjectFrame = nsnull; @@ -2521,7 +2520,6 @@ NS_IMPL_RELEASE(nsPluginInstanceOwner) NS_INTERFACE_MAP_BEGIN(nsPluginInstanceOwner) NS_INTERFACE_MAP_ENTRY(nsIPluginInstanceOwner) NS_INTERFACE_MAP_ENTRY(nsIPluginTagInfo) - NS_INTERFACE_MAP_ENTRY(nsITimerCallback) NS_INTERFACE_MAP_ENTRY(nsIDOMMouseListener) NS_INTERFACE_MAP_ENTRY(nsIDOMMouseMotionListener) NS_INTERFACE_MAP_ENTRY(nsIDOMKeyListener) @@ -3571,7 +3569,7 @@ nsPluginInstanceOwner::GetEventloopNestingLevel() nsresult nsPluginInstanceOwner::ScrollPositionWillChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY) { -#if defined(XP_MACOSX) && !defined(NP_NO_CARBON) +#ifdef MAC_CARBON_PLUGINS if (GetEventModel() != NPEventModelCarbon) return NS_OK; @@ -3598,7 +3596,7 @@ nsresult nsPluginInstanceOwner::ScrollPositionWillChange(nsIScrollableView* aScr nsresult nsPluginInstanceOwner::ScrollPositionDidChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY) { -#if defined(XP_MACOSX) && !defined(NP_NO_CARBON) +#ifdef MAC_CARBON_PLUGINS if (GetEventModel() != NPEventModelCarbon) return NS_OK; @@ -3617,9 +3615,9 @@ nsresult nsPluginInstanceOwner::ScrollPositionDidChange(nsIScrollableView* aScro pluginWidget->EndDrawPlugin(); } } -#endif - StartTimer(NORMAL_PLUGIN_DELAY); + StartTimer(PR_TRUE); +#endif return NS_OK; } @@ -3679,7 +3677,7 @@ nsresult nsPluginInstanceOwner::KeyUp(nsIDOMEvent* aKeyEvent) nsresult nsPluginInstanceOwner::KeyPress(nsIDOMEvent* aKeyEvent) { -#if defined(XP_MACOSX) && !defined(NP_NO_CARBON) +#ifdef MAC_CARBON_PLUGINS // send KeyPress events only for Mac OS X Carbon event model if (GetEventModel() != NPEventModelCarbon) return aKeyEvent->PreventDefault(); @@ -4634,8 +4632,10 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const nsGUIEvent& anEvent) nsresult nsPluginInstanceOwner::Destroy() { +#ifdef MAC_CARBON_PLUGINS // stop the timer explicitly to reduce reference count. CancelTimer(); +#endif // unregister context menu listener if (mCXMenuListener) { @@ -5361,14 +5361,9 @@ nsPluginInstanceOwner::Renderer::NativeDraw(QWidget * drawable, } #endif -// Here's how we give idle time to plugins. - -NS_IMETHODIMP nsPluginInstanceOwner::Notify(nsITimer* timer) +void nsPluginInstanceOwner::SendIdleEvent() { -#if defined(XP_MACOSX) && !defined(NP_NO_CARBON) - if (GetEventModel() != NPEventModelCarbon) - return NS_OK; - +#ifdef MAC_CARBON_PLUGINS // validate the plugin clipping information by syncing the plugin window info to // reflect the current widget location. This makes sure that everything is updated // correctly in the event of scrolling in the window. @@ -5394,36 +5389,22 @@ NS_IMETHODIMP nsPluginInstanceOwner::Notify(nsITimer* timer) } } #endif - return NS_OK; } -void nsPluginInstanceOwner::StartTimer(unsigned int aDelay) +#ifdef MAC_CARBON_PLUGINS +void nsPluginInstanceOwner::StartTimer(PRBool isVisible) { -#if defined(XP_MACOSX) && !defined(NP_NO_CARBON) if (GetEventModel() != NPEventModelCarbon) return; - if (!mTimerCanceled) - return; - - // start a periodic timer to provide null events to the plugin instance. - if (!mPluginTimer) { - mPluginTimer = do_CreateInstance("@mozilla.org/timer;1"); - } - if (mPluginTimer) { - mTimerCanceled = PR_FALSE; - mPluginTimer->InitWithCallback(this, aDelay, nsITimer::TYPE_REPEATING_SLACK); - } -#endif + mPluginHost->AddIdleTimeTarget(this, isVisible); } void nsPluginInstanceOwner::CancelTimer() { - if (mPluginTimer) { - mPluginTimer->Cancel(); - } - mTimerCanceled = PR_TRUE; + mPluginHost->RemoveIdleTimeTarget(this); } +#endif nsresult nsPluginInstanceOwner::Init(nsPresContext* aPresContext, nsObjectFrame* aFrame, @@ -5596,8 +5577,10 @@ NS_IMETHODIMP nsPluginInstanceOwner::CreateWidget(void) mPluginWindow->type = NPWindowTypeWindow; mPluginWindow->window = GetPluginPort(); +#ifdef MAC_CARBON_PLUGINS // start the idle timer. - StartTimer(NORMAL_PLUGIN_DELAY); + StartTimer(PR_TRUE); +#endif // tell the plugin window about the widget mPluginWindow->SetPluginWidget(mWidget); @@ -5638,7 +5621,7 @@ PRBool nsPluginInstanceOwner::UpdateVisibility() } #endif - // Mac specific code to fix up the port location and clipping region +// Mac specific code to fix up the port location and clipping region #ifdef XP_MACOSX void* nsPluginInstanceOwner::FixUpPluginWindow(PRInt32 inPaintState) @@ -5734,15 +5717,17 @@ void* nsPluginInstanceOwner::FixUpPluginWindow(PRInt32 inPaintState) { mInstance->SetWindow(mPluginWindow); mPluginPortChanged = PR_FALSE; +#ifdef MAC_CARBON_PLUGINS // if the clipRect is of size 0, make the null timer fire less often CancelTimer(); if (mPluginWindow->clipRect.left == mPluginWindow->clipRect.right || mPluginWindow->clipRect.top == mPluginWindow->clipRect.bottom) { - StartTimer(HIDDEN_PLUGIN_DELAY); + StartTimer(PR_FALSE); } else { - StartTimer(NORMAL_PLUGIN_DELAY); + StartTimer(PR_TRUE); } +#endif } else if (mPluginPortChanged) { mInstance->SetWindow(mPluginWindow); mPluginPortChanged = PR_FALSE; diff --git a/modules/plugin/base/public/nsIPluginHost.idl b/modules/plugin/base/public/nsIPluginHost.idl index a4c01b0e85750..cd48f7de373b8 100644 --- a/modules/plugin/base/public/nsIPluginHost.idl +++ b/modules/plugin/base/public/nsIPluginHost.idl @@ -64,7 +64,7 @@ interface nsIPluginStreamListener; [ref] native nsIStreamListenerRef(nsIStreamListener *); [ptr] native nsPluginNativeWindowPtr(nsPluginNativeWindow); -[scriptable, uuid(30C7C529-B05C-4950-B5B8-9AF673E46521)] +[scriptable, uuid(AA13B116-2AFC-4F23-8395-913C0475D173)] interface nsIPluginHost : nsISupports { [noscript] void init(); @@ -285,6 +285,11 @@ interface nsIPluginHost : nsISupports * @return plugin tag object */ [noscript] nsIPluginTag getPluginTagForInstance(in nsIPluginInstance aInstance); + +%{C++ + virtual void AddIdleTimeTarget(nsIPluginInstanceOwner* objectFrame, PRBool isVisible) = 0; + virtual void RemoveIdleTimeTarget(nsIPluginInstanceOwner* objectFrame) = 0; +%} }; %{C++ diff --git a/modules/plugin/base/public/nsIPluginInstanceOwner.idl b/modules/plugin/base/public/nsIPluginInstanceOwner.idl index ad07178bde8be..0f2cb23cf7cf0 100644 --- a/modules/plugin/base/public/nsIPluginInstanceOwner.idl +++ b/modules/plugin/base/public/nsIPluginInstanceOwner.idl @@ -49,7 +49,7 @@ class nsPluginEvent; [ref] native nsIPluginInstanceRef(nsIPluginInstance*); -[uuid(8080E717-7261-4707-B8B4-48250F47055F)] +[uuid(D8776CDC-00DF-4395-A432-2E78EBCC12B6)] interface nsIPluginInstanceOwner : nsISupports { /** @@ -137,4 +137,8 @@ interface nsIPluginInstanceOwner : nsISupports %} void setEventModel(in PRInt32 eventModel); + +%{C++ + virtual void SendIdleEvent() = 0; +%} }; diff --git a/modules/plugin/base/src/nsPluginHost.cpp b/modules/plugin/base/src/nsPluginHost.cpp index 5ec1cd3617e7d..e7ee14d579c99 100644 --- a/modules/plugin/base/src/nsPluginHost.cpp +++ b/modules/plugin/base/src/nsPluginHost.cpp @@ -2448,6 +2448,11 @@ nsPluginHost::nsPluginHost() PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("nsPluginHost::ctor\n")); PR_LogFlush(); #endif + +#ifdef MAC_CARBON_PLUGINS + mVisiblePluginTimer = do_CreateInstance("@mozilla.org/timer;1"); + mHiddenPluginTimer = do_CreateInstance("@mozilla.org/timer;1"); +#endif } nsPluginHost::~nsPluginHost() @@ -2997,7 +3002,7 @@ NS_IMETHODIMP nsPluginHost::InstantiatePluginForChannel(nsIChannel* aChannel, return NewEmbeddedPluginStreamListener(uri, aOwner, nsnull, aListener); } -// Called by nsPluginInstanceOwner (nsObjectFrame.cpp - embedded case) +// Called by nsPluginInstanceOwner NS_IMETHODIMP nsPluginHost::InstantiateEmbeddedPlugin(const char *aMimeType, nsIURI* aURL, nsIPluginInstanceOwner *aOwner) @@ -5888,6 +5893,76 @@ nsresult nsPluginHost::AddUnusedLibrary(PRLibrary * aLibrary) return NS_OK; } +#ifdef MAC_CARBON_PLUGINS +// Flash requires a minimum of 8 events per second to avoid audio skipping. +// Since WebKit uses a hidden plugin event rate of 4 events per second Flash +// uses a Carbon timer for WebKit which fires at 8 events per second. +#define HIDDEN_PLUGIN_DELAY 125 +#define VISIBLE_PLUGIN_DELAY 20 +#endif + +void nsPluginHost::AddIdleTimeTarget(nsIPluginInstanceOwner* objectFrame, PRBool isVisible) +{ +#ifdef MAC_CARBON_PLUGINS + nsTObserverArray *targetArray; + if (isVisible) { + targetArray = &mVisibleTimerTargets; + } else { + targetArray = &mHiddenTimerTargets; + } + + if (targetArray->Contains(objectFrame)) { + return; + } + + targetArray->AppendElement(objectFrame); + if (targetArray->Length() == 1) { + if (isVisible) { + mVisiblePluginTimer->InitWithCallback(this, VISIBLE_PLUGIN_DELAY, nsITimer::TYPE_REPEATING_SLACK); + } else { + mHiddenPluginTimer->InitWithCallback(this, HIDDEN_PLUGIN_DELAY, nsITimer::TYPE_REPEATING_SLACK); + } + } +#endif +} + +void nsPluginHost::RemoveIdleTimeTarget(nsIPluginInstanceOwner* objectFrame) +{ +#ifdef MAC_CARBON_PLUGINS + PRBool visibleRemoved = mVisibleTimerTargets.RemoveElement(objectFrame); + if (visibleRemoved && mVisibleTimerTargets.IsEmpty()) { + mVisiblePluginTimer->Cancel(); + } + + PRBool hiddenRemoved = mHiddenTimerTargets.RemoveElement(objectFrame); + if (hiddenRemoved && mHiddenTimerTargets.IsEmpty()) { + mHiddenPluginTimer->Cancel(); + } + + NS_ASSERTION(!(hiddenRemoved && visibleRemoved), "Plugin instance received visible and hidden idle event notifications"); +#endif +} + +NS_IMETHODIMP nsPluginHost::Notify(nsITimer* timer) +{ +#ifdef MAC_CARBON_PLUGINS + if (timer == mVisiblePluginTimer) { + nsTObserverArray::ForwardIterator iter(mVisibleTimerTargets); + while (iter.HasMore()) { + iter.GetNext()->SendIdleEvent(); + } + return NS_OK; + } else if (timer == mHiddenPluginTimer) { + nsTObserverArray::ForwardIterator iter(mHiddenTimerTargets); + while (iter.HasMore()) { + iter.GetNext()->SendIdleEvent(); + } + return NS_OK; + } +#endif + return NS_ERROR_FAILURE; +} + nsresult nsPluginStreamListenerPeer::ServeStreamAsFile(nsIRequest *request, nsISupports* aContext) { diff --git a/modules/plugin/base/src/nsPluginHost.h b/modules/plugin/base/src/nsPluginHost.h index ca832eb39dbc2..2d3660a12759b 100644 --- a/modules/plugin/base/src/nsPluginHost.h +++ b/modules/plugin/base/src/nsPluginHost.h @@ -58,6 +58,8 @@ #include "nsWeakReference.h" #include "nsThreadUtils.h" #include "nsTArray.h" +#include "nsTObserverArray.h" +#include "nsITimer.h" class nsNPAPIPlugin; class nsIComponentManager; @@ -73,6 +75,10 @@ class nsPluginHost; #define NS_PLUGIN_FLAG_UNWANTED 0x0008 // this is an unwanted plugin #define NS_PLUGIN_FLAG_BLOCKLISTED 0x0010 // this is a blocklisted plugin +#if defined(XP_MACOSX) && !defined(NP_NO_CARBON) +#define MAC_CARBON_PLUGINS +#endif + // A linked-list of plugin information that is used for instantiating plugins // and reflecting plugin information into JavaScript. class nsPluginTag : public nsIPluginTag @@ -184,6 +190,7 @@ class nsPluginInstanceTagList class nsPluginHost : public nsIPluginHost, public nsIObserver, + public nsITimerCallback, public nsSupportsWeakReference { public: @@ -198,6 +205,7 @@ class nsPluginHost : public nsIPluginHost, NS_DECL_ISUPPORTS NS_DECL_NSIPLUGINHOST NS_DECL_NSIOBSERVER + NS_DECL_NSITIMERCALLBACK NS_IMETHOD GetURL(nsISupports* pluginInst, @@ -266,6 +274,9 @@ class nsPluginHost : public nsIPluginHost, static nsresult GetPrompt(nsIPluginInstanceOwner *aOwner, nsIPrompt **aPrompt); + void AddIdleTimeTarget(nsIPluginInstanceOwner* objectFrame, PRBool isVisible); + void RemoveIdleTimeTarget(nsIPluginInstanceOwner* objectFrame); + private: nsresult TrySetUpPluginInstance(const char *aMimeType, nsIURI *aURL, nsIPluginInstanceOwner *aOwner); @@ -373,6 +384,13 @@ class nsPluginHost : public nsIPluginHost, // We need to hold a global ptr to ourselves because we register for // two different CIDs for some reason... static nsPluginHost* sInst; + +#ifdef MAC_CARBON_PLUGINS + nsCOMPtr mVisiblePluginTimer; + nsTObserverArray mVisibleTimerTargets; + nsCOMPtr mHiddenPluginTimer; + nsTObserverArray mHiddenTimerTargets; +#endif }; class NS_STACK_CLASS PluginDestructionGuard : protected PRCList