Fixing bug 176079. Provide an API for plugins to control whether popups are enabled or not. Disable popups by default from plugins, but enable/disable popups while handling user input events (mouse click, keydown etc) on the platforms where it's possible (Win32 and Mac), but do that only if the plugin doesn't support the popup enabling/disabling API. r+sr+a=brendan@mozilla.org

This commit is contained in:
jst%mozilla.jstenback.com 2005-06-18 06:06:45 +00:00
Родитель 9edc942571
Коммит 4f8ee0f3ff
12 изменённых файлов: 327 добавлений и 43 удалений

Просмотреть файл

@ -137,7 +137,8 @@ public:
virtual void SetOpenerScriptURL(nsIURI* aURI) = 0;
virtual PopupControlState PushPopupControlState(PopupControlState aState) const = 0;
virtual PopupControlState PushPopupControlState(PopupControlState aState,
PRBool aForce) const = 0;
virtual void PopPopupControlState(PopupControlState state) const = 0;
virtual PopupControlState GetPopupControlState() const = 0;
virtual OpenAllowValue GetOpenAllow(const nsAString &aName) = 0;
@ -205,7 +206,7 @@ public:
: mWindow(aWindow), mOldState(openAbused)
{
if (aWindow) {
mOldState = aWindow->PushPopupControlState(aState);
mOldState = aWindow->PushPopupControlState(aState, PR_FALSE);
}
}

Просмотреть файл

@ -410,9 +410,10 @@ PopPopupControlState(PopupControlState aState)
}
PopupControlState
nsGlobalWindow::PushPopupControlState(PopupControlState aState) const
nsGlobalWindow::PushPopupControlState(PopupControlState aState,
PRBool aForce) const
{
return ::PushPopupControlState(aState, PR_FALSE);
return ::PushPopupControlState(aState, aForce);
}
void

Просмотреть файл

@ -199,7 +199,7 @@ public:
virtual NS_HIDDEN_(void) SetOpenerScriptURL(nsIURI* aURI);
virtual NS_HIDDEN_(PopupControlState) PushPopupControlState(PopupControlState state) const;
virtual NS_HIDDEN_(PopupControlState) PushPopupControlState(PopupControlState state, PRBool aForce) const;
virtual NS_HIDDEN_(void) PopPopupControlState(PopupControlState state) const;
virtual NS_HIDDEN_(PopupControlState) GetPopupControlState() const;
virtual NS_HIDDEN_(OpenAllowValue) GetOpenAllow(const nsAString &aName);

Просмотреть файл

@ -420,6 +420,12 @@ pref("dom.popup_maximum", 20);
pref("dom.popup_allowed_events", "change click dblclick mouseup reset submit");
pref("dom.disable_open_click_delay", 1000);
// Disable popups from plugins by default
// 0 = openAllowed
// 1 = openControlled
// 2 = openAbused
pref("privacy.popups.disable_from_plugins", 2);
pref("dom.event.contextmenu.enabled", true);
pref("javascript.enabled", true);

Просмотреть файл

@ -37,7 +37,7 @@
/*
* npapi.h $Revision: 3.39 $
* npapi.h $Revision: 3.40 $
* Netscape client plug-in API spec
*/
@ -125,7 +125,7 @@
/*----------------------------------------------------------------------*/
#define NP_VERSION_MAJOR 0
#define NP_VERSION_MINOR 15
#define NP_VERSION_MINOR 16
/* The OS/2 version of Netscape uses RC_DATA to define the
@ -673,9 +673,6 @@ void NP_LOADDS NPP_URLNotify(NPP instance, const char* url,
jref NP_LOADDS NPP_GetJavaClass(void);
#endif
NPError NP_LOADDS NPP_GetValue(NPP instance, NPPVariable variable, void *value);
/*
* Uh, shouldn't NPP_SetValue() take an NPPVariable and not an NPNVariable?
*/
NPError NP_LOADDS NPP_SetValue(NPP instance, NPNVariable variable, void *value);
/*
@ -714,6 +711,8 @@ NPError NP_LOADDS NPN_SetValue(NPP instance, NPPVariable variable, void *value);
void NP_LOADDS NPN_InvalidateRect(NPP instance, NPRect *invalidRect);
void NP_LOADDS NPN_InvalidateRegion(NPP instance, NPRegion invalidRegion);
void NP_LOADDS NPN_ForceRedraw(NPP instance);
void NP_LOADDS NPN_PushPopupEnabledState(NPP instance, NPBool enabled);
void NP_LOADDS NPN_PopPopupEnabledState(NPP instance);
#ifdef __cplusplus
} /* end extern "C" */

Просмотреть файл

@ -37,7 +37,7 @@
/*
* npupp.h $Revision: 3.19 $
* npupp.h $Revision: 3.20 $
* function call mecahnics needed by platform specific glue code.
*/
@ -1585,6 +1585,58 @@ typedef void (* NP_LOADDS NPN_SetExceptionUPP)(NPObject *obj, const NPUTF8 *mess
#endif
/* NPN_PushPopupsEnabledStateUPP */
#if _NPUPP_USE_UPP_
typedef UniversalProcPtr NPN_PushPopupsEnabledStateUPP;
enum {
uppNPN_PushPopupsEnabledStateProcInfo = kThinkCStackBased
| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPBool)))
| RESULT_SIZE(SIZE_CODE(0))
};
#define NewNPN_PushPopupsEnabledStateProc(FUNC) \
(NPN_PushPopupsEnabledStateUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_PushPopupsEnabledStateProcInfo, GetCurrentArchitecture())
#define CallNPN_PushPopupsEnabledStateProc(FUNC, ARG1, ARG2) \
(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_PushPopupsEnabledStateProcInfo, (ARG1), (ARG2))
#else
typedef bool (* NP_LOADDS NPN_PushPopupsEnabledStateUPP)(NPP npp, NPBool enabled);
#define NewNPN_PushPopupsEnabledStateProc(FUNC) \
((NPN_PushPopupsEnabledStateUPP) (FUNC))
#define CallNPN_PushPopupsEnabledStateProc(FUNC, ARG1, ARG2) \
(*(FUNC))((ARG1), (ARG2))
#endif
/* NPN_PopPopupsEnabledState */
#if _NPUPP_USE_UPP_
typedef UniversalProcPtr NPN_PopPopupsEnabledStateUPP;
enum {
uppNPN_PopPopupsEnabledStateProcInfo = kThinkCStackBased
| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
| RESULT_SIZE(SIZE_CODE(0))
};
#define NewNPN_PopPopupsEnabledStateProc(FUNC) \
(NPN_PopPopupsEnabledStateUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_PopPopupsEnabledStateProcInfo, GetCurrentArchitecture())
#define CallNPN_PopPopupsEnabledStateProc(FUNC, ARG1) \
(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_PopPopupsEnabledStateProcInfo, (ARG1))
#else
typedef bool (* NP_LOADDS NPN_PopPopupsEnabledStateUPP)(NPP npp);
#define NewNPN_PopPopupsEnabledStateProc(FUNC) \
((NPN_PopPopupsEnabledStateUPP) (FUNC))
#define CallNPN_PopPopupsEnabledStateProc(FUNC, ARG1) \
(*(FUNC))((ARG1))
#endif
@ -1660,6 +1712,8 @@ typedef struct _NPNetscapeFuncs {
NPN_HasMethodUPP hasmethod;
NPN_ReleaseVariantValueUPP releasevariantvalue;
NPN_SetExceptionUPP setexception;
NPN_PushPopupsEnabledStateUPP pushpopupsenabledstate;
NPN_PopPopupsEnabledStateUPP poppopupsenabledstate;
} NPNetscapeFuncs;
#ifdef XP_MAC

Просмотреть файл

@ -54,6 +54,11 @@ public:
virtual JSObject *GetJSObject(JSContext *cx) = 0;
virtual nsresult GetFormValue(nsAString& aValue) = 0;
virtual void PushPopupsEnabledState(PRBool aEnabled) = 0;
virtual void PopPopupsEnabledState() = 0;
virtual PRUint16 GetPluginAPIVersion() = 0;
};
#endif /* nsIPluginInstanceInternal_h___ */

Просмотреть файл

@ -365,6 +365,8 @@ enum nsPluginReason {
(nsMajorVersion(suppliedV) == nsMajorVersion(requiredV) \
&& nsMinorVersion(suppliedV) >= nsMinorVersion(requiredV))
#define NP_POPUP_API_VERSION 16
////////////////////////////////////////////////////////////////////////////////
// Classes
////////////////////////////////////////////////////////////////////////////////

Просмотреть файл

@ -169,6 +169,12 @@ PR_BEGIN_EXTERN_C
static void NP_EXPORT
_forceredraw(NPP npp);
static void NP_EXPORT
_pushpopupsenabledstate(NPP npp, NPBool enabled);
static void NP_EXPORT
_poppopupsenabledstate(NPP npp);
static const char* NP_EXPORT
_useragent(NPP npp);
@ -375,6 +381,12 @@ ns4xPlugin::CheckClassInitialized(void)
CALLBACKS.setexception =
NewNPN_SetExceptionProc(FP2TV(_setexception));
CALLBACKS.pushpopupsenabledstate =
NewNPN_PushPopupsEnabledStateProc(FP2TV(_pushpopupsenabledstate));
CALLBACKS.poppopupsenabledstate =
NewNPN_PopPopupsEnabledStateProc(FP2TV(_poppopupsenabledstate));
initialized = TRUE;
NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,("NPN callbacks initialized\n"));
@ -1858,27 +1870,16 @@ _getvalue(NPP npp, NPNVariable variable, void *result)
}
case NPNVDOMWindow: {
ns4xPluginInstance *inst = (ns4xPluginInstance *) npp->ndata;
ns4xPluginInstance *inst = (ns4xPluginInstance *)npp->ndata;
NS_ENSURE_TRUE(inst, NPERR_GENERIC_ERROR);
nsCOMPtr<nsIPluginInstancePeer> pip;
inst->GetPeer(getter_AddRefs(pip));
nsCOMPtr<nsPIPluginInstancePeer> pp (do_QueryInterface(pip));
if (pp) {
nsCOMPtr<nsIPluginInstanceOwner> owner;
pp->GetOwner(getter_AddRefs(owner));
if (owner) {
nsCOMPtr<nsIDocument> doc;
owner->GetDocument(getter_AddRefs(doc));
if (doc) {
nsCOMPtr<nsIDOMWindow> domWindow =
do_QueryInterface(doc->GetScriptGlobalObject());
if (domWindow) {
NS_ADDREF(*(nsIDOMWindow**)result = domWindow.get());
return NPERR_NO_ERROR;
}
}
}
nsIDOMWindow *domWindow = inst->GetDOMWindow().get();
if (domWindow) {
// Pass over ownership of domWindow to the caller.
(*(nsIDOMWindow**)result) = domWindow;
return NPERR_NO_ERROR;
}
return NPERR_GENERIC_ERROR;
}
@ -2076,5 +2077,24 @@ _getJavaPeer(NPP npp)
#endif /* OJI */
void NP_EXPORT
_pushpopupsenabledstate(NPP npp, NPBool enabled)
{
ns4xPluginInstance *inst = (ns4xPluginInstance *)npp->ndata;
if (!inst)
return;
inst->PushPopupsEnabledState(enabled);
}
void NP_EXPORT
_poppopupsenabledstate(NPP npp)
{
ns4xPluginInstance *inst = (ns4xPluginInstance *)npp->ndata;
if (!inst)
return;
inst->PopPopupsEnabledState();
}
NPP NPPStack::sCurrentNPP = nsnull;

Просмотреть файл

@ -49,6 +49,12 @@
#include "nsPluginSafety.h"
#include "nsPluginLogging.h"
#include "nsPIPluginInstancePeer.h"
#include "nsIDOMWindow.h"
#include "nsPIDOMWindow.h"
#include "nsIDocument.h"
#include "nsIScriptGlobalObject.h"
#include "nsJSNPRuntime.h"
#ifdef XP_OS2
@ -877,6 +883,16 @@ NS_IMETHODIMP ns4xPluginInstance::Stop(void)
NPError error;
// Make sure the plugin didn't leave popups enabled.
if (mPopupStates.Count() > 0) {
nsCOMPtr<nsIDOMWindow> window = GetDOMWindow();
nsCOMPtr<nsPIDOMWindow> piwindow = do_QueryInterface(window);
if (piwindow) {
piwindow->PopPopupControlState(openAbused);
}
}
#if defined(MOZ_WIDGET_GTK) || defined (MOZ_WIDGET_GTK2)
if (mXtBin) {
gtk_widget_destroy(mXtBin);
@ -927,6 +943,39 @@ NS_IMETHODIMP ns4xPluginInstance::Stop(void)
return NS_OK;
}
already_AddRefed<nsIDOMWindow>
ns4xPluginInstance::GetDOMWindow()
{
nsCOMPtr<nsPIPluginInstancePeer> pp (do_QueryInterface(mPeer));
if (!pp) {
return nsnull;
}
nsCOMPtr<nsIPluginInstanceOwner> owner;
pp->GetOwner(getter_AddRefs(owner));
if (!owner) {
return nsnull;
}
nsCOMPtr<nsIDocument> doc;
owner->GetDocument(getter_AddRefs(doc));
if (!doc) {
return nsnull;
}
nsIScriptGlobalObject *sgo = doc->GetScriptGlobalObject();
if (!sgo) {
return nsnull;
}
nsIDOMWindow *window;
CallQueryInterface(sgo, &window);
return window;
}
////////////////////////////////////////////////////////////////////////
nsresult ns4xPluginInstance::InitializePlugin(nsIPluginInstancePeer* peer)
@ -1564,3 +1613,54 @@ ns4xPluginInstance::GetFormValue(nsAString& aValue)
return NS_OK;
}
void
ns4xPluginInstance::PushPopupsEnabledState(PRBool aEnabled)
{
nsCOMPtr<nsIDOMWindow> window = GetDOMWindow();
nsCOMPtr<nsPIDOMWindow> piwindow = do_QueryInterface(window);
if (!piwindow)
return;
PopupControlState oldState =
piwindow->PushPopupControlState(aEnabled ? openAllowed : openAbused,
PR_TRUE);
if (!mPopupStates.AppendElement(NS_INT32_TO_PTR(oldState))) {
// Appending to our state stack failed, push what we just popped.
piwindow->PopPopupControlState(oldState);
}
}
void
ns4xPluginInstance::PopPopupsEnabledState()
{
PRInt32 last = mPopupStates.Count() - 1;
if (last < 0) {
// Nothing to pop.
return;
}
nsCOMPtr<nsIDOMWindow> window = GetDOMWindow();
nsCOMPtr<nsPIDOMWindow> piwindow = do_QueryInterface(window);
if (!piwindow)
return;
PopupControlState oldState =
(PopupControlState)NS_PTR_TO_INT32(mPopupStates[last]);
piwindow->PopPopupControlState(oldState);
mPopupStates.RemoveElementAt(last);
}
PRUint16
ns4xPluginInstance::GetPluginAPIVersion()
{
return fCallbacks->version;
}

Просмотреть файл

@ -49,6 +49,7 @@
#endif /* HPUX11 */
#include "nsCOMPtr.h"
#include "nsVoidArray.h"
#include "nsIPlugin.h"
#include "nsIPluginInstance.h"
#include "nsIPluginInstancePeer.h"
@ -71,6 +72,7 @@
////////////////////////////////////////////////////////////////////////
class ns4xPluginStreamListener;
class nsIDOMWindow;
struct nsInstanceStream
{
@ -132,6 +134,11 @@ public:
virtual nsresult GetFormValue(nsAString& aValue);
virtual void PushPopupsEnabledState(PRBool aEnabled);
virtual void PopPopupsEnabledState();
virtual PRUint16 GetPluginAPIVersion();
////////////////////////////////////////////////////////////////////////
// ns4xPluginInstance-specific methods
@ -174,7 +181,9 @@ public:
{
return mPeer;
}
already_AddRefed<nsIDOMWindow> GetDOMWindow();
protected:
nsresult InitializePlugin(nsIPluginInstancePeer* peer);
@ -223,6 +232,8 @@ protected:
public:
PRLibrary* fLibrary;
nsInstanceStream *mStreams;
nsVoidArray mPopupStates;
};
#endif // ns4xPluginInstance_h__

Просмотреть файл

@ -54,6 +54,7 @@
#include "nsIEventQueueService.h"
#include "nsIPluginInstancePeer.h"
#include "nsIPluginInstanceInternal.h"
#include "nsPluginSafety.h"
#include "nsPluginNativeWindow.h"
@ -134,7 +135,7 @@ private:
public:
// locals
WNDPROC GetWindowProc();
nsresult GetEventService(nsCOMPtr<nsIEventQueueService> &aEventService);
nsIEventQueueService *GetEventService();
PluginWindowEvent * GetPluginWindowEvent(HWND aWnd, UINT aMsg, WPARAM aWParam, LPARAM aLParam);
private:
@ -158,10 +159,11 @@ static PRBool ProcessFlashMessageDelayed(nsPluginNativeWindowWin * aWin,
return PR_FALSE; // no need to delay
// do stuff
nsCOMPtr<nsIEventQueueService> eventService;
if (NS_SUCCEEDED(aWin->GetEventService(eventService))) {
nsIEventQueueService *eventService = aWin->GetEventService();
if (eventService) {
nsCOMPtr<nsIEventQueue> eventQueue;
eventService->GetThreadEventQueue(PR_GetCurrentThread(), getter_AddRefs(eventQueue));
eventService->GetThreadEventQueue(PR_GetCurrentThread(),
getter_AddRefs(eventQueue));
if (eventQueue) {
PluginWindowEvent *pwe = aWin->GetPluginWindowEvent(hWnd, msg, wParam, lParam);
if (pwe) {
@ -173,6 +175,28 @@ static PRBool ProcessFlashMessageDelayed(nsPluginNativeWindowWin * aWin,
return PR_FALSE;
}
PR_STATIC_CALLBACK(void*)
DelayedPopupsEnabledEvent_Handle(PLEvent *event)
{
nsIPluginInstanceInternal *instInternal =
(nsIPluginInstanceInternal *)event->owner;
instInternal->PushPopupsEnabledState();
return nsnull;
}
PR_STATIC_CALLBACK(void)
DelayedPopupsEnabledEvent_Destroy(PLEvent *event)
{
nsIPluginInstanceInternal *instInternal =
(nsIPluginInstanceInternal *)event->owner;
NS_RELEASE(instInternal);
delete event;
}
/**
* New plugin window procedure
*/
@ -220,7 +244,7 @@ static LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM
}
}
PRBool enablePopups = PR_FALSE;
// Activate/deactivate mouse capture on the plugin widget
// here, before we pass the Windows event to the plugin
@ -237,8 +261,11 @@ static LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM
widget->CaptureMouse(PR_TRUE);
break;
}
case WM_MBUTTONUP:
case WM_LBUTTONUP:
enablePopups = PR_TRUE;
// fall through
case WM_MBUTTONUP:
case WM_RBUTTONUP: {
nsCOMPtr<nsIWidget> widget;
win->GetPluginWidget(getter_AddRefs(widget));
@ -246,8 +273,18 @@ static LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM
widget->CaptureMouse(PR_FALSE);
break;
}
}
case WM_KEYDOWN:
// Ignore repeating keydown messages...
if ((lParam & 0x40000000) != 0) {
break;
}
// fall through
case WM_KEYUP:
enablePopups = PR_TRUE;
break;
}
// Macromedia Flash plugin may flood the message queue with some special messages
// (WM_USER+1) causing 100% CPU consumption and GUI freeze, see mozilla bug 132759;
@ -259,9 +296,21 @@ static LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM
LRESULT res = TRUE;
nsCOMPtr<nsIPluginInstanceInternal> instInternal;
nsCOMPtr<nsIPluginInstance> inst;
win->GetPluginInstance(inst);
if (enablePopups) {
nsCOMPtr<nsIPluginInstanceInternal> tmp = do_QueryInterface(inst);
if (tmp && !nsVersionOK(tmp->GetPluginAPIVersion(),
NP_POPUP_API_VERSION)) {
tmp.swap(instInternal);
instInternal->PushPopupsEnabledState();
}
}
sInMessageDispatch = PR_TRUE;
NS_TRY_SAFE_CALL_RETURN(res,
@ -270,6 +319,44 @@ static LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM
sInMessageDispatch = PR_FALSE;
if (instInternal) {
// Popups are enabled (were enabled before the call to
// CallWindowProc()). Some plugins (at least the flash player)
// post messages from their key handlers etc that delay the actual
// processing, so we need to delay the disabling of popups so that
// popups remain enabled when the flash player ends up processing
// the actual key handlers. We do this by posting an event that
// does the disabling, this way our disabling will happen after
// the handlers in the plugin are done.
// Note that it's not fatal if any of this fails (which won't
// happen unless we're out of memory anyways) since the plugin
// code will pop any popup state pushed by this plugin on
// destruction.
nsIEventQueueService *eventService = win->GetEventService();
if (eventService) {
nsCOMPtr<nsIEventQueue> eventQueue;
eventService->GetThreadEventQueue(PR_GetCurrentThread(),
getter_AddRefs(eventQueue));
if (eventQueue) {
PLEvent *event = new PLEvent;
if (event) {
nsIPluginInstanceInternal *eventInst = instInternal;
// Make the event own the plugin instance.
NS_ADDREF(eventInst);
PL_InitEvent(event, eventInst, DelayedPopupsEnabledEvent_Handle,
DelayedPopupsEnabledEvent_Destroy);
eventQueue->PostEvent(event);
}
}
}
}
return res;
}
@ -349,15 +436,13 @@ PluginWindowEvent_Destroy(PLEvent* self)
event->Clear();
}
nsresult nsPluginNativeWindowWin::GetEventService(nsCOMPtr<nsIEventQueueService> &aEventService)
nsIEventQueueService *nsPluginNativeWindowWin::GetEventService()
{
if (!mEventService) {
mEventService = do_GetService(kEventQueueServiceCID);
if (!mEventService)
return NS_ERROR_FAILURE;
}
aEventService = mEventService;
return NS_OK;
return mEventService;
}
PluginWindowEvent*