зеркало из https://github.com/mozilla/pjs.git
Fixing bug 252326. Fixing some popup blocker problems. Making sure only trusted events get mark trusted, and only allow popups while processing trusted (initiated by the user) events. Patch by trev@gtchat.de and jst@mozilla.org, r=bzbarsky@mit.edu, rs=brendan@mozilla.org, bryner@biranryner.com
This commit is contained in:
Родитель
2eeff3edb0
Коммит
63c881aeb2
|
@ -39,7 +39,7 @@
|
|||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsDOMEvent.h"
|
||||
#include "nsIEventStateManager.h"
|
||||
#include "nsEventStateManager.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIPresShell.h"
|
||||
|
@ -68,19 +68,19 @@ static const char* const sEventNames[] = {
|
|||
"popupBlocked", "DOMActivate", "DOMFocusIn", "DOMFocusOut"
|
||||
};
|
||||
|
||||
static char *sPopupAllowedEvents;
|
||||
|
||||
|
||||
nsDOMEvent::nsDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent)
|
||||
{
|
||||
mPresContext = aPresContext;
|
||||
mEventIsTrusted = PR_FALSE;
|
||||
|
||||
if (aEvent) {
|
||||
mEvent = aEvent;
|
||||
mEventIsInternal = PR_FALSE;
|
||||
mEventIsTrusted = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
mEventIsInternal = PR_TRUE;
|
||||
mEventIsTrusted = PR_FALSE;
|
||||
/*
|
||||
A derived class might want to allocate its own type of aEvent
|
||||
(derived from nsEvent). To do this, it should take care to pass
|
||||
|
@ -89,8 +89,8 @@ nsDOMEvent::nsDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent)
|
|||
nsDOMFooEvent::nsDOMFooEvent(..., nsEvent* aEvent)
|
||||
: nsDOMEvent(..., aEvent ? aEvent : new nsFooEvent())
|
||||
|
||||
Then, to override the mEventIsInternal and mEventIsTrusted
|
||||
assignments done by the base ctor, it should do this in its own ctor:
|
||||
Then, to override the mEventIsInternal assignments done by the
|
||||
base ctor, it should do this in its own ctor:
|
||||
|
||||
nsDOMFooEvent::nsDOMFooEvent(..., nsEvent* aEvent)
|
||||
...
|
||||
|
@ -98,11 +98,9 @@ nsDOMEvent::nsDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent)
|
|||
...
|
||||
if (aEvent) {
|
||||
mEventIsInternal = PR_FALSE;
|
||||
mEventIsTrusted = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
mEventIsInternal = PR_TRUE;
|
||||
mEventIsTrusted = PR_FALSE;
|
||||
}
|
||||
...
|
||||
}
|
||||
|
@ -286,7 +284,12 @@ nsDOMEvent::HasOriginalTarget(PRBool* aResult)
|
|||
NS_IMETHODIMP
|
||||
nsDOMEvent::SetTrusted(PRBool aTrusted)
|
||||
{
|
||||
mEventIsTrusted = aTrusted;
|
||||
if (aTrusted) {
|
||||
mEvent->internalAppFlags |= NS_APP_EVENT_FLAG_TRUSTED;
|
||||
} else {
|
||||
mEvent->internalAppFlags &= ~NS_APP_EVENT_FLAG_TRUSTED;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -360,7 +363,7 @@ nsDOMEvent::PreventCapture()
|
|||
NS_IMETHODIMP
|
||||
nsDOMEvent::GetIsTrusted(PRBool *aIsTrusted)
|
||||
{
|
||||
*aIsTrusted = mEventIsTrusted;
|
||||
*aIsTrusted = mEvent->internalAppFlags & NS_APP_EVENT_FLAG_TRUSTED;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -461,7 +464,6 @@ nsDOMEvent::InitEvent(const nsAString& aEventTypeArg, PRBool aCanBubbleArg, PRBo
|
|||
NS_ENSURE_SUCCESS(SetEventType(aEventTypeArg), NS_ERROR_FAILURE);
|
||||
mEvent->flags |= aCanBubbleArg ? NS_EVENT_FLAG_NONE : NS_EVENT_FLAG_CANT_BUBBLE;
|
||||
mEvent->flags |= aCancelableArg ? NS_EVENT_FLAG_NONE : NS_EVENT_FLAG_CANT_CANCEL;
|
||||
mEvent->internalAppFlags |= NS_APP_EVENT_FLAG_NONE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -516,10 +518,10 @@ nsDOMEvent::IsHandled(PRBool* aIsHandled)
|
|||
NS_IMETHODIMP
|
||||
nsDOMEvent::SetHandled(PRBool aHandled)
|
||||
{
|
||||
if(aHandled)
|
||||
if(aHandled)
|
||||
mEvent->internalAppFlags |= NS_APP_EVENT_FLAG_HANDLED;
|
||||
else
|
||||
mEvent->internalAppFlags &= ~NS_APP_EVENT_FLAG_HANDLED;
|
||||
mEvent->internalAppFlags &= ~NS_APP_EVENT_FLAG_HANDLED;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -532,6 +534,204 @@ nsDOMEvent::GetInternalNSEvent(nsEvent** aNSEvent)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// return true if eventName is contained within events, delimited by
|
||||
// spaces
|
||||
static PRBool
|
||||
PopupAllowedForEvent(const char *eventName)
|
||||
{
|
||||
if (!sPopupAllowedEvents) {
|
||||
nsDOMEvent::PopupAllowedEventsChanged();
|
||||
|
||||
if (!sPopupAllowedEvents) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
nsDependentCString events(sPopupAllowedEvents);
|
||||
|
||||
nsAFlatCString::const_iterator start, end;
|
||||
nsAFlatCString::const_iterator startiter(events.BeginReading(start));
|
||||
events.EndReading(end);
|
||||
|
||||
while (startiter != end) {
|
||||
nsAFlatCString::const_iterator enditer(end);
|
||||
|
||||
if (!FindInReadable(nsDependentCString(eventName), startiter, enditer))
|
||||
return PR_FALSE;
|
||||
|
||||
// the match is surrounded by spaces, or at a string boundary
|
||||
if ((startiter == start || *--startiter == ' ') &&
|
||||
(enditer == end || *enditer == ' ')) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// Move on and see if there are other matches. (The delimitation
|
||||
// requirement makes it pointless to begin the next search before
|
||||
// the end of the invalid match just found.)
|
||||
startiter = enditer;
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// static
|
||||
PopupControlState
|
||||
nsDOMEvent::GetEventPopupControlState(nsEvent *aEvent)
|
||||
{
|
||||
// generally if an event handler is running, new windows are disallowed.
|
||||
// check for exceptions:
|
||||
PopupControlState abuse = openAbused;
|
||||
|
||||
switch(aEvent->eventStructType) {
|
||||
case NS_EVENT :
|
||||
// For these following events only allow popups if they're
|
||||
// triggered while handling user input. See
|
||||
// nsPresShell::HandleEventInternal() for details.
|
||||
if (nsEventStateManager::IsHandlingUserInput()) {
|
||||
switch(aEvent->message) {
|
||||
case NS_FORM_SELECTED :
|
||||
if (::PopupAllowedForEvent("select"))
|
||||
abuse = openControlled;
|
||||
case NS_FORM_CHANGE :
|
||||
if (::PopupAllowedForEvent("change"))
|
||||
abuse = openControlled;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NS_GUI_EVENT :
|
||||
// For this following event only allow popups if it's triggered
|
||||
// while handling user input. See
|
||||
// nsPresShell::HandleEventInternal() for details.
|
||||
if (nsEventStateManager::IsHandlingUserInput()) {
|
||||
switch(aEvent->message) {
|
||||
case NS_FORM_INPUT :
|
||||
if (::PopupAllowedForEvent("input"))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NS_INPUT_EVENT :
|
||||
// For this following event only allow popups if it's triggered
|
||||
// while handling user input. See
|
||||
// nsPresShell::HandleEventInternal() for details.
|
||||
if (nsEventStateManager::IsHandlingUserInput()) {
|
||||
switch(aEvent->message) {
|
||||
case NS_FORM_CHANGE :
|
||||
if (::PopupAllowedForEvent("change"))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NS_KEY_EVENT :
|
||||
if (aEvent->internalAppFlags & NS_APP_EVENT_FLAG_TRUSTED) {
|
||||
PRUint32 key = NS_STATIC_CAST(nsKeyEvent *, aEvent)->keyCode;
|
||||
switch(aEvent->message) {
|
||||
case NS_KEY_PRESS :
|
||||
// return key on focused button. see note at NS_MOUSE_LEFT_CLICK.
|
||||
if (key == nsIDOMKeyEvent::DOM_VK_RETURN)
|
||||
abuse = openAllowed;
|
||||
else if (::PopupAllowedForEvent("keypress"))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
case NS_KEY_UP :
|
||||
// space key on focused button. see note at NS_MOUSE_LEFT_CLICK.
|
||||
if (key == nsIDOMKeyEvent::DOM_VK_SPACE)
|
||||
abuse = openAllowed;
|
||||
else if (::PopupAllowedForEvent("keyup"))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
case NS_KEY_DOWN :
|
||||
if (::PopupAllowedForEvent("keydown"))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NS_MOUSE_EVENT :
|
||||
if (aEvent->internalAppFlags & NS_APP_EVENT_FLAG_TRUSTED) {
|
||||
switch(aEvent->message) {
|
||||
case NS_MOUSE_LEFT_BUTTON_UP :
|
||||
if (::PopupAllowedForEvent("mouseup"))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
case NS_MOUSE_LEFT_BUTTON_DOWN :
|
||||
if (::PopupAllowedForEvent("mousedown"))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
case NS_MOUSE_LEFT_CLICK :
|
||||
/* Click events get special treatment because of their
|
||||
historical status as a more legitimate event handler. If
|
||||
click popups are enabled in the prefs, clear the popup
|
||||
status completely. */
|
||||
if (::PopupAllowedForEvent("click"))
|
||||
abuse = openAllowed;
|
||||
break;
|
||||
case NS_MOUSE_LEFT_DOUBLECLICK :
|
||||
if (::PopupAllowedForEvent("dblclick"))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NS_SCRIPT_ERROR_EVENT :
|
||||
switch(aEvent->message) {
|
||||
case NS_SCRIPT_ERROR :
|
||||
// Any error event will allow popups, if enabled in the pref.
|
||||
if (::PopupAllowedForEvent("error"))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NS_FORM_EVENT :
|
||||
// For these following events only allow popups if they're
|
||||
// triggered while handling user input. See
|
||||
// nsPresShell::HandleEventInternal() for details.
|
||||
if (nsEventStateManager::IsHandlingUserInput()) {
|
||||
switch(aEvent->message) {
|
||||
case NS_FORM_SUBMIT :
|
||||
if (::PopupAllowedForEvent("submit"))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
case NS_FORM_RESET :
|
||||
if (::PopupAllowedForEvent("reset"))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return abuse;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
nsDOMEvent::PopupAllowedEventsChanged()
|
||||
{
|
||||
if (sPopupAllowedEvents) {
|
||||
nsMemory::Free(sPopupAllowedEvents);
|
||||
}
|
||||
|
||||
nsAdoptingCString str =
|
||||
nsContentUtils::GetCharPref("dom.popup_allowed_events");
|
||||
|
||||
// We'll want to do this even if str is empty to avoid looking up
|
||||
// this pref all the time if it's not set.
|
||||
sPopupAllowedEvents = ToNewCString(str);
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
nsDOMEvent::Shutdown()
|
||||
{
|
||||
if (sPopupAllowedEvents) {
|
||||
nsMemory::Free(sPopupAllowedEvents);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
const char* nsDOMEvent::GetEventName(PRUint32 aEventType)
|
||||
{
|
||||
switch(aEventType) {
|
||||
|
@ -599,7 +799,7 @@ const char* nsDOMEvent::GetEventName(PRUint32 aEventType)
|
|||
case NS_SCROLL_EVENT:
|
||||
return sEventNames[eDOMEvents_scroll];
|
||||
case NS_TEXT_TEXT:
|
||||
return sEventNames[eDOMEvents_text];
|
||||
return sEventNames[eDOMEvents_text];
|
||||
case NS_XUL_POPUP_SHOWING:
|
||||
return sEventNames[eDOMEvents_popupShowing];
|
||||
case NS_XUL_POPUP_SHOWN:
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "nsIPrivateDOMEvent.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIDOMEventTarget.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsPoint.h"
|
||||
#include "nsGUIEvent.h"
|
||||
|
@ -146,6 +147,12 @@ public:
|
|||
NS_IMETHOD IsHandled(PRBool* aHandled);
|
||||
NS_IMETHOD SetHandled(PRBool aHandled);
|
||||
|
||||
static PopupControlState GetEventPopupControlState(nsEvent *aEvent);
|
||||
|
||||
static void PopupAllowedEventsChanged();
|
||||
|
||||
static void Shutdown();
|
||||
|
||||
protected:
|
||||
|
||||
// Internal helper functions
|
||||
|
@ -161,7 +168,6 @@ protected:
|
|||
nsCOMPtr<nsIDOMEventTarget> mExplicitOriginalTarget;
|
||||
nsCOMPtr<nsIDOMEventTarget> mTmpRealOriginalTarget;
|
||||
PRPackedBool mEventIsInternal;
|
||||
PRPackedBool mEventIsTrusted;
|
||||
|
||||
void* mScriptObject;
|
||||
};
|
||||
|
|
|
@ -49,11 +49,9 @@ nsDOMKeyboardEvent::nsDOMKeyboardEvent(nsPresContext* aPresContext, nsKeyEvent*
|
|||
|
||||
if (aEvent) {
|
||||
mEventIsInternal = PR_FALSE;
|
||||
mEventIsTrusted = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
mEventIsInternal = PR_TRUE;
|
||||
mEventIsTrusted = PR_FALSE;
|
||||
mEvent->time = PR_Now();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,11 +53,9 @@ nsDOMMouseEvent::nsDOMMouseEvent(nsPresContext* aPresContext, nsInputEvent* aEve
|
|||
|
||||
if (aEvent) {
|
||||
mEventIsInternal = PR_FALSE;
|
||||
mEventIsTrusted = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
mEventIsInternal = PR_TRUE;
|
||||
mEventIsTrusted = PR_FALSE;
|
||||
mEvent->time = PR_Now();
|
||||
mEvent->refPoint.x = mEvent->refPoint.y = mEvent->point.x = mEvent->point.y = 0;
|
||||
}
|
||||
|
|
|
@ -47,14 +47,12 @@ nsDOMMutationEvent::nsDOMMutationEvent(nsPresContext* aPresContext, nsMutationEv
|
|||
{
|
||||
if ( aEvent ) {
|
||||
mEventIsInternal = PR_FALSE;
|
||||
mEventIsTrusted = PR_TRUE;
|
||||
nsMutationEvent* mutation = (nsMutationEvent*)aEvent;
|
||||
SetTarget(mutation->mTarget);
|
||||
}
|
||||
else
|
||||
{
|
||||
mEventIsInternal = PR_TRUE;
|
||||
mEventIsTrusted = PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,11 +49,9 @@ nsDOMPopupBlockedEvent::nsDOMPopupBlockedEvent(nsPresContext* aPresContext, nsPo
|
|||
|
||||
if (aEvent) {
|
||||
mEventIsInternal = PR_FALSE;
|
||||
mEventIsTrusted = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
mEventIsInternal = PR_TRUE;
|
||||
mEventIsTrusted = PR_FALSE;
|
||||
mEvent->time = PR_Now();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,11 +48,9 @@ nsDOMTextEvent::nsDOMTextEvent(nsPresContext* aPresContext, nsTextEvent* aEvent)
|
|||
|
||||
if (aEvent) {
|
||||
mEventIsInternal = PR_FALSE;
|
||||
mEventIsTrusted = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
mEventIsInternal = PR_TRUE;
|
||||
mEventIsTrusted = PR_FALSE;
|
||||
mEvent->time = PR_Now();
|
||||
}
|
||||
|
||||
|
|
|
@ -54,15 +54,13 @@
|
|||
#include "nsIFrame.h"
|
||||
|
||||
nsDOMUIEvent::nsDOMUIEvent(nsPresContext* aPresContext, nsGUIEvent* aEvent)
|
||||
: nsDOMEvent(aPresContext, aEvent)
|
||||
: nsDOMEvent(aPresContext, aEvent)
|
||||
{
|
||||
if (aEvent) {
|
||||
mEventIsInternal = PR_FALSE;
|
||||
mEventIsTrusted = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
mEventIsInternal = PR_TRUE;
|
||||
mEventIsTrusted = PR_FALSE;
|
||||
mEvent->time = PR_Now();
|
||||
}
|
||||
|
||||
|
|
|
@ -440,6 +440,8 @@ nsresult nsEventListenerManager::RemoveAllListeners(PRBool aScriptOnly)
|
|||
void nsEventListenerManager::Shutdown()
|
||||
{
|
||||
sAddListenerID = JSVAL_VOID;
|
||||
|
||||
nsDOMEvent::Shutdown();
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(nsEventListenerManager)
|
||||
|
@ -1582,6 +1584,8 @@ nsresult nsEventListenerManager::HandleEvent(nsPresContext* aPresContext,
|
|||
}
|
||||
|
||||
if (NS_SUCCEEDED(ret)) {
|
||||
nsAutoPopupStatePusher popupStatePusher(nsDOMEvent::GetEventPopupControlState(aEvent));
|
||||
|
||||
for (int k = 0; !mListenersRemoved && listeners && k < listeners->Count(); ++k) {
|
||||
nsListenerStruct* ls = NS_STATIC_CAST(nsListenerStruct*, listeners->ElementAt(k));
|
||||
if (ls->mFlags & aFlags && ls->mGroupFlags == currentGroup) {
|
||||
|
|
|
@ -156,6 +156,7 @@ static PRBool sLeftClickOnly = PR_TRUE;
|
|||
static PRBool sKeyCausesActivation = PR_TRUE;
|
||||
static PRUint32 sESMInstanceCount = 0;
|
||||
static PRInt32 sGeneralAccesskeyModifier = -1; // magic value of -1 means uninitialized
|
||||
PRInt32 nsEventStateManager::sUserInputEventDepth = 0;
|
||||
|
||||
enum {
|
||||
MOUSE_SCROLL_N_LINES,
|
||||
|
@ -283,6 +284,8 @@ nsEventStateManager::Init()
|
|||
prefBranch->AddObserver("mousewheel.withshiftkey.numlines", this, PR_TRUE);
|
||||
prefBranch->AddObserver("mousewheel.withshiftkey.sysnumlines", this, PR_TRUE);
|
||||
#endif
|
||||
|
||||
prefBranch->AddObserver("dom.popup_allowed_events", this, PR_TRUE);
|
||||
}
|
||||
|
||||
if (sTextfieldSelectModel == eTextfieldSelect_unset) {
|
||||
|
@ -358,6 +361,8 @@ nsEventStateManager::Shutdown()
|
|||
prefBranch->RemoveObserver("mousewheel.withnokey.numlines", this);
|
||||
prefBranch->RemoveObserver("mousewheel.withnokey.sysnumlines", this);
|
||||
#endif
|
||||
|
||||
prefBranch->RemoveObserver("dom.popup_allowed_events", this);
|
||||
}
|
||||
|
||||
m_haveShutdown = PR_TRUE;
|
||||
|
@ -408,6 +413,8 @@ nsEventStateManager::Observe(nsISupports *aSubject,
|
|||
} else if (data.EqualsLiteral("mousewheel.withnokey.numlines")) {
|
||||
} else if (data.EqualsLiteral("mousewheel.withnokey.sysnumlines")) {
|
||||
#endif
|
||||
} else if (data.EqualsLiteral("dom.popup_allowed_events")) {
|
||||
nsDOMEvent::PopupAllowedEventsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1042,6 +1049,11 @@ nsEventStateManager::HandleAccessKey(nsPresContext* aPresContext,
|
|||
// B) Click on it if the users prefs indicate to do so.
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
nsMouseEvent event(NS_MOUSE_LEFT_CLICK);
|
||||
|
||||
// Propagate trusted state to the new event.
|
||||
event.internalAppFlags |=
|
||||
aEvent->internalAppFlags & NS_APP_EVENT_FLAG_TRUSTED;
|
||||
|
||||
nsCOMPtr<nsIContent> oldTargetContent = mCurrentTargetContent;
|
||||
mCurrentTargetContent = content;
|
||||
content->HandleDOMEvent(mPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
|
||||
|
|
|
@ -146,6 +146,21 @@ public:
|
|||
NS_IMETHOD MoveFocusToCaret(PRBool aCanFocusDoc, PRBool *aIsSelectionWithFocus);
|
||||
NS_IMETHOD MoveCaretToFocus();
|
||||
|
||||
static void StartHandlingUserInput()
|
||||
{
|
||||
++sUserInputEventDepth;
|
||||
}
|
||||
|
||||
static void StopHandlingUserInput()
|
||||
{
|
||||
--sUserInputEventDepth;
|
||||
}
|
||||
|
||||
static PRBool IsHandlingUserInput()
|
||||
{
|
||||
return sUserInputEventDepth > 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class CurrentEventShepherd;
|
||||
|
||||
|
@ -334,6 +349,35 @@ protected:
|
|||
nsCOMPtr<nsITimer> mClickHoldTimer;
|
||||
#endif
|
||||
|
||||
static PRInt32 sUserInputEventDepth;
|
||||
};
|
||||
|
||||
|
||||
class nsAutoHandlingUserInputStatePusher
|
||||
{
|
||||
public:
|
||||
nsAutoHandlingUserInputStatePusher(PRBool aIsHandlingUserInput)
|
||||
: mIsHandlingUserInput(aIsHandlingUserInput)
|
||||
{
|
||||
if (aIsHandlingUserInput) {
|
||||
nsEventStateManager::StartHandlingUserInput();
|
||||
}
|
||||
}
|
||||
|
||||
~nsAutoHandlingUserInputStatePusher()
|
||||
{
|
||||
if (mIsHandlingUserInput) {
|
||||
nsEventStateManager::StopHandlingUserInput();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
PRBool mIsHandlingUserInput;
|
||||
|
||||
private:
|
||||
// Not meant to be implemented.
|
||||
static void* operator new(size_t /*size*/) CPP_THROW_NEW;
|
||||
static void operator delete(void* /*memory*/);
|
||||
};
|
||||
|
||||
#endif // nsEventStateManager_h__
|
||||
|
|
|
@ -130,7 +130,7 @@ include $(topsrcdir)/config/rules.mk
|
|||
INCLUDES += \
|
||||
-I$(srcdir)/../../style/src \
|
||||
-I$(srcdir)/../../../base/src \
|
||||
-I$(srcdir)/../../base/src \
|
||||
-I$(srcdir)/../../../events/src \
|
||||
$(NULL)
|
||||
|
||||
DEFINES += -D_IMPL_NS_LAYOUT
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "nsIDOMEventReceiver.h"
|
||||
#include "nsIHTMLContent.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsEventStateManager.h"
|
||||
#include "nsHTMLAtoms.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsPresContext.h"
|
||||
|
@ -68,6 +69,7 @@
|
|||
#include "nsCategoryManagerUtils.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "nsIDOMWindowInternal.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsRange.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
@ -269,6 +271,10 @@ protected:
|
|||
PRPackedBool mIsSubmitting;
|
||||
/** Whether the submission is to be deferred in case a script triggers it */
|
||||
PRPackedBool mDeferSubmission;
|
||||
/** Keep track of what the popup state was when the submit was initiated */
|
||||
PopupControlState mSubmitPopupState;
|
||||
/** Keep track of whether a submission was user-initiated or not */
|
||||
PRBool mSubmitInitiatedFromUserInput;
|
||||
|
||||
/** The pending submission object */
|
||||
nsCOMPtr<nsIFormSubmission> mPendingSubmission;
|
||||
|
@ -425,6 +431,8 @@ nsHTMLFormElement::nsHTMLFormElement(nsINodeInfo *aNodeInfo)
|
|||
mGeneratingReset(PR_FALSE),
|
||||
mIsSubmitting(PR_FALSE),
|
||||
mDeferSubmission(PR_FALSE),
|
||||
mSubmitPopupState(openAbused),
|
||||
mSubmitInitiatedFromUserInput(PR_FALSE),
|
||||
mPendingSubmission(nsnull),
|
||||
mSubmittingRequest(nsnull)
|
||||
{
|
||||
|
@ -821,7 +829,18 @@ nsHTMLFormElement::DoSubmit(nsPresContext* aPresContext, nsEvent* aEvent)
|
|||
// prepare the submission object
|
||||
//
|
||||
BuildSubmission(aPresContext, submission, aEvent);
|
||||
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window =
|
||||
do_QueryInterface(GetOwnerDoc()->GetScriptGlobalObject());
|
||||
|
||||
if (window) {
|
||||
mSubmitPopupState = window->GetPopupControlState();
|
||||
} else {
|
||||
mSubmitPopupState = openAbused;
|
||||
}
|
||||
|
||||
mSubmitInitiatedFromUserInput = nsEventStateManager::IsHandlingUserInput();
|
||||
|
||||
if(mDeferSubmission) {
|
||||
// we are in an event handler, JS submitted so we have to
|
||||
// defer this submission. let's remember it and return
|
||||
|
@ -918,9 +937,17 @@ nsHTMLFormElement::SubmitSubmission(nsPresContext* aPresContext,
|
|||
// Submit
|
||||
//
|
||||
nsCOMPtr<nsIDocShell> docShell;
|
||||
rv = aFormSubmission->SubmitTo(actionURI, target, this, aPresContext,
|
||||
getter_AddRefs(docShell),
|
||||
getter_AddRefs(mSubmittingRequest));
|
||||
|
||||
{
|
||||
nsAutoPopupStatePusher popupStatePusher(mSubmitPopupState);
|
||||
|
||||
nsAutoHandlingUserInputStatePusher userInpStatePusher(mSubmitInitiatedFromUserInput);
|
||||
|
||||
rv = aFormSubmission->SubmitTo(actionURI, target, this, aPresContext,
|
||||
getter_AddRefs(docShell),
|
||||
getter_AddRefs(mSubmittingRequest));
|
||||
}
|
||||
|
||||
NS_ENSURE_SUBMIT_SUCCESS(rv);
|
||||
|
||||
// Even if the submit succeeds, it's possible for there to be no docshell
|
||||
|
|
|
@ -428,6 +428,9 @@ struct OnLinkClickEvent : public PLEvent {
|
|||
~OnLinkClickEvent();
|
||||
|
||||
void HandleEvent() {
|
||||
nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(mHandler->mScriptGlobal));
|
||||
nsAutoPopupStatePusher popupStatePusher(window, mPopupState);
|
||||
|
||||
mHandler->OnLinkClickSync(mContent, mVerb, mURI,
|
||||
mTargetSpec.get(), mPostDataStream,
|
||||
mHeadersDataStream,
|
||||
|
@ -441,6 +444,7 @@ struct OnLinkClickEvent : public PLEvent {
|
|||
nsCOMPtr<nsIInputStream> mHeadersDataStream;
|
||||
nsCOMPtr<nsIContent> mContent;
|
||||
nsLinkVerb mVerb;
|
||||
PopupControlState mPopupState;
|
||||
};
|
||||
|
||||
static void PR_CALLBACK HandlePLEvent(OnLinkClickEvent* aEvent)
|
||||
|
@ -470,6 +474,10 @@ OnLinkClickEvent::OnLinkClickEvent(nsWebShell* aHandler,
|
|||
mContent = aContent;
|
||||
mVerb = aVerb;
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(mHandler->mScriptGlobal));
|
||||
|
||||
mPopupState = window->GetPopupControlState();
|
||||
|
||||
PL_InitEvent(this, nsnull,
|
||||
(PLHandleEventProc) ::HandlePLEvent,
|
||||
(PLDestroyEventProc) ::DestroyPLEvent);
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
class nsIEventQueue;
|
||||
class nsIController;
|
||||
struct PRThread;
|
||||
struct OnLinkClickEvent;
|
||||
|
||||
typedef enum {
|
||||
eCharsetReloadInit,
|
||||
|
@ -115,6 +116,8 @@ public:
|
|||
|
||||
// NS_IMETHOD SetURL(const PRUnichar* aURL);
|
||||
|
||||
friend struct OnLinkClickEvent;
|
||||
|
||||
protected:
|
||||
// void GetRootWebShellEvenIfChrome(nsIWebShell** aResult);
|
||||
void InitFrameData();
|
||||
|
|
|
@ -48,3 +48,4 @@ EXPORTS=nsPIDOMWindow.h nsPIWindowRoot.h nsIFocusController.h
|
|||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
DEFINES += -D_IMPL_NS_LAYOUT
|
||||
|
|
|
@ -49,6 +49,18 @@
|
|||
#include "nsIURI.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
// Popup control state enum. The values in this enum must go from most
|
||||
// permissive to least permissive so that its safe to push state in
|
||||
// all situations. Pushing popup state onto the stack never makes the
|
||||
// current popup state less permissive (see
|
||||
// GlobalWindowImpl::PushPopupControlState()).
|
||||
enum PopupControlState {
|
||||
openAllowed = 0, // open that window without worries
|
||||
openControlled, // it's a popup, but allow it
|
||||
openAbused, // it's a popup. disallow it, but allow domain override.
|
||||
openOverridden // disallow window open
|
||||
};
|
||||
|
||||
class nsIDocShell;
|
||||
class nsIFocusController;
|
||||
struct nsTimeoutImpl;
|
||||
|
@ -105,6 +117,10 @@ public:
|
|||
|
||||
virtual void SetOpenerScriptURL(nsIURI* aURI) = 0;
|
||||
|
||||
virtual PopupControlState PushPopupControlState(PopupControlState aState) const = 0;
|
||||
virtual void PopPopupControlState(PopupControlState state) const = 0;
|
||||
virtual PopupControlState GetPopupControlState() const = 0;
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIChromeEventHandler> mChromeEventHandler; // strong
|
||||
nsCOMPtr<nsIDOMDocument> mDocument; // strong
|
||||
|
@ -117,4 +133,57 @@ protected:
|
|||
PRBool mIsDocumentLoaded;
|
||||
};
|
||||
|
||||
|
||||
#ifdef _IMPL_NS_LAYOUT
|
||||
PopupControlState
|
||||
PushPopupControlState(PopupControlState aState);
|
||||
|
||||
void
|
||||
PopPopupControlState(PopupControlState aState);
|
||||
#endif
|
||||
|
||||
// Helper chass that helps with pushing and poping popup control
|
||||
// state. Note that this class looks different from within code that's
|
||||
// part of the layout library than it does in code outside the layout
|
||||
// library.
|
||||
class nsAutoPopupStatePusher
|
||||
{
|
||||
public:
|
||||
#ifdef _IMPL_NS_LAYOUT
|
||||
nsAutoPopupStatePusher(PopupControlState aState)
|
||||
: mOldState(::PushPopupControlState(aState))
|
||||
{
|
||||
}
|
||||
|
||||
~nsAutoPopupStatePusher()
|
||||
{
|
||||
PopPopupControlState(mOldState);
|
||||
}
|
||||
#else
|
||||
nsAutoPopupStatePusher(nsPIDOMWindow *aWindow, PopupControlState aState)
|
||||
: mWindow(aWindow), mOldState(openAbused)
|
||||
{
|
||||
if (aWindow) {
|
||||
mOldState = aWindow->PushPopupControlState(aState);
|
||||
}
|
||||
}
|
||||
|
||||
~nsAutoPopupStatePusher()
|
||||
{
|
||||
if (mWindow) {
|
||||
mWindow->PopPopupControlState(mOldState);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
nsPIDOMWindow *mWindow; // WEAK
|
||||
PopupControlState mOldState;
|
||||
|
||||
private:
|
||||
// Not meant to be implemented.
|
||||
static void* operator new(size_t /*size*/) CPP_THROW_NEW;
|
||||
static void operator delete(void* /*memory*/);
|
||||
};
|
||||
|
||||
#endif // nsPIDOMWindow_h__
|
||||
|
|
|
@ -156,11 +156,15 @@
|
|||
// belonging to the back-end like nsIContentPolicy
|
||||
#include "nsIPopupWindowManager.h"
|
||||
|
||||
nsIScriptSecurityManager *GlobalWindowImpl::sSecMan = nsnull;
|
||||
nsIFactory *GlobalWindowImpl::sComputedDOMStyleFactory = nsnull;
|
||||
|
||||
static nsIEntropyCollector *gEntropyCollector = nsnull;
|
||||
static PRInt32 gRefCnt = 0;
|
||||
static PRInt32 gOpenPopupSpamCount = 0;
|
||||
nsIScriptSecurityManager *GlobalWindowImpl::sSecMan = nsnull;
|
||||
nsIFactory *GlobalWindowImpl::sComputedDOMStyleFactory = nsnull;
|
||||
static PopupControlState gPopupControlState = openAbused;
|
||||
static PRInt32 gRunningTimeoutDepth = 0;
|
||||
|
||||
#ifdef DEBUG_jst
|
||||
PRInt32 gTimeoutCnt = 0;
|
||||
#endif
|
||||
|
@ -187,13 +191,6 @@ static const char kDOMSecurityWarningsBundleURL[] = "chrome://communicator/local
|
|||
static const char kCryptoContractID[] = NS_CRYPTO_CONTRACTID;
|
||||
static const char kPkcs11ContractID[] = NS_PKCS11_CONTRACTID;
|
||||
|
||||
// CheckForAbusePoint return values:
|
||||
enum {
|
||||
openAllowed = 0, // open that window without worries
|
||||
openControlled, // it's a popup, but allow it
|
||||
openAbused, // it's a popup. disallow it, but allow domain override.
|
||||
openOverridden // disallow window open
|
||||
};
|
||||
// CheckOpenAllow return values:
|
||||
enum {
|
||||
allowNot = 0, // the window opening was denied
|
||||
|
@ -204,36 +201,6 @@ enum {
|
|||
};
|
||||
|
||||
|
||||
// return true if eventName is contained within events, delimited by spaces
|
||||
static PRBool
|
||||
ContainsEventName(const char *eventName, const nsAFlatCString& events)
|
||||
{
|
||||
nsAFlatCString::const_iterator start, end;
|
||||
events.BeginReading(start);
|
||||
events.EndReading(end);
|
||||
|
||||
nsAFlatCString::const_iterator startiter(start);
|
||||
|
||||
while (startiter != end) {
|
||||
nsAFlatCString::const_iterator enditer(end);
|
||||
|
||||
if (!FindInReadable(nsDependentCString(eventName), startiter, enditer))
|
||||
return PR_FALSE;
|
||||
|
||||
// the match is surrounded by spaces, or at a string boundary
|
||||
if ((startiter == start || *--startiter == ' ') &&
|
||||
(enditer == end || *enditer == ' '))
|
||||
return PR_TRUE;
|
||||
|
||||
/* Move on and see if there are other matches. (The delimitation
|
||||
requirement makes it pointless to begin the next search before
|
||||
the end of the invalid match just found.) */
|
||||
startiter = enditer;
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//*** GlobalWindowImpl: Object Management
|
||||
//*****************************************************************************
|
||||
|
@ -250,7 +217,6 @@ GlobalWindowImpl::GlobalWindowImpl()
|
|||
mTimeoutInsertionPoint(&mTimeouts),
|
||||
mTimeoutPublicIdCounter(1),
|
||||
mTimeoutFiringDepth(0),
|
||||
mLastMouseButtonAction(LL_ZERO),
|
||||
mGlobalObjectOwner(nsnull),
|
||||
mDocShell(nsnull),
|
||||
mCurrentEvent(0)
|
||||
|
@ -422,6 +388,42 @@ GlobalWindowImpl::SetOpenerScriptURL(nsIURI* aURI)
|
|||
mOpenerScriptURL = aURI;
|
||||
}
|
||||
|
||||
PopupControlState
|
||||
PushPopupControlState(PopupControlState aState)
|
||||
{
|
||||
PopupControlState oldState = gPopupControlState;
|
||||
|
||||
if (aState < gPopupControlState) {
|
||||
gPopupControlState = aState;
|
||||
}
|
||||
|
||||
return oldState;
|
||||
}
|
||||
|
||||
void
|
||||
PopPopupControlState(PopupControlState aState)
|
||||
{
|
||||
gPopupControlState = aState;
|
||||
}
|
||||
|
||||
PopupControlState
|
||||
GlobalWindowImpl::PushPopupControlState(PopupControlState aState) const
|
||||
{
|
||||
return ::PushPopupControlState(aState);
|
||||
}
|
||||
|
||||
void
|
||||
GlobalWindowImpl::PopPopupControlState(PopupControlState aState) const
|
||||
{
|
||||
::PopPopupControlState(aState);
|
||||
}
|
||||
|
||||
PopupControlState
|
||||
GlobalWindowImpl::GetPopupControlState() const
|
||||
{
|
||||
return gPopupControlState;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GlobalWindowImpl::SetNewDocument(nsIDOMDocument* aDocument,
|
||||
PRBool aRemoveEventListeners,
|
||||
|
@ -869,11 +871,6 @@ GlobalWindowImpl::HandleDOMEvent(nsPresContext* aPresContext,
|
|||
|
||||
if (aEvent->message == NS_PAGE_UNLOAD) {
|
||||
mIsDocumentLoaded = PR_FALSE;
|
||||
} else if ((aEvent->message >= NS_MOUSE_LEFT_BUTTON_UP &&
|
||||
aEvent->message <= NS_MOUSE_RIGHT_BUTTON_DOWN) ||
|
||||
(aEvent->message >= NS_MOUSE_LEFT_DOUBLECLICK &&
|
||||
aEvent->message <= NS_MOUSE_RIGHT_CLICK)) {
|
||||
mLastMouseButtonAction = PR_Now();
|
||||
}
|
||||
|
||||
// Capturing stage
|
||||
|
@ -2881,10 +2878,17 @@ GlobalWindowImpl::DisableExternalCapture()
|
|||
static
|
||||
PRBool IsPopupBlocked(nsIDOMDocument* aDoc)
|
||||
{
|
||||
PRBool blocked = PR_FALSE;
|
||||
nsCOMPtr<nsIPopupWindowManager> pm =
|
||||
do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
|
||||
|
||||
if (!pm) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool blocked = PR_TRUE;
|
||||
nsCOMPtr<nsIDocument> doc(do_QueryInterface(aDoc));
|
||||
nsCOMPtr<nsIPopupWindowManager> pm(do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID));
|
||||
if (pm && doc) {
|
||||
|
||||
if (doc) {
|
||||
PRUint32 permission = nsIPopupWindowManager::ALLOW_POPUP;
|
||||
pm->TestPermission(doc->GetDocumentURI(), &permission);
|
||||
blocked = (permission == nsIPopupWindowManager::DENY_POPUP);
|
||||
|
@ -2950,7 +2954,7 @@ GlobalWindowImpl::CanSetProperty(const char *aPrefName)
|
|||
* routine to determine whether to allow the new window.
|
||||
* Returns a value from the CheckForAbusePoint enum.
|
||||
*/
|
||||
PRUint32
|
||||
PopupControlState
|
||||
GlobalWindowImpl::CheckForAbusePoint()
|
||||
{
|
||||
nsCOMPtr<nsIDocShellTreeItem> item(do_QueryInterface(mDocShell));
|
||||
|
@ -2963,162 +2967,9 @@ GlobalWindowImpl::CheckForAbusePoint()
|
|||
return openAllowed;
|
||||
}
|
||||
|
||||
PRUint32 abuse = openAllowed; // level of abuse we've detected
|
||||
|
||||
// is the document being loaded or unloaded?
|
||||
if (!mIsDocumentLoaded)
|
||||
abuse = openAbused;
|
||||
|
||||
/* Disallow windows after a user-defined click delay.
|
||||
This is a consideration secondary to document load because
|
||||
of its stronger response (openOverridden). See bug 247017. */
|
||||
if (abuse == openAllowed) {
|
||||
PRInt32 delay = nsContentUtils::GetIntPref("dom.disable_open_click_delay");
|
||||
if (delay != 0) {
|
||||
PRTime now = PR_Now();
|
||||
PRTime ll_delta;
|
||||
PRUint32 delta;
|
||||
LL_SUB(ll_delta, now, mLastMouseButtonAction);
|
||||
LL_L2UI(delta, ll_delta);
|
||||
if (delta/1000 > (PRUint32) delay)
|
||||
abuse = openOverridden;
|
||||
}
|
||||
}
|
||||
|
||||
/* Is a timer running?
|
||||
This is a consideration secondary to the user-defined click delay
|
||||
because that seemed the Right Thing. See bug 197919 comment 45. */
|
||||
if (abuse == openAllowed && mRunningTimeout)
|
||||
abuse = openAbused;
|
||||
|
||||
if (abuse == openAllowed) {
|
||||
// we'll need to know what DOM event is being processed now, if any
|
||||
nsEvent *currentEvent = mCurrentEvent;
|
||||
if (!currentEvent && mDocShell) {
|
||||
/* The DOM window's current event is accurate for events that make it
|
||||
all the way to the window. But it doesn't see events handled directly
|
||||
by a target element. For those, check the EventStateManager. */
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
mDocShell->GetPresShell(getter_AddRefs(presShell));
|
||||
if (presShell) {
|
||||
nsPresContext *presContext = presShell->GetPresContext();
|
||||
if (presContext)
|
||||
presContext->EventStateManager()->GetCurrentEvent(¤tEvent);
|
||||
}
|
||||
}
|
||||
|
||||
// fetch pref string detailing which events are allowed
|
||||
const nsAdoptingCString& eventPref =
|
||||
nsContentUtils::GetCharPref("dom.popup_allowed_events");
|
||||
|
||||
// generally if an event handler is running, new windows are disallowed.
|
||||
// check for exceptions:
|
||||
if (currentEvent) {
|
||||
abuse = openAbused;
|
||||
switch(currentEvent->eventStructType) {
|
||||
case NS_EVENT :
|
||||
switch(currentEvent->message) {
|
||||
case NS_FORM_SELECTED :
|
||||
if (::ContainsEventName("select", eventPref))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
case NS_FORM_CHANGE :
|
||||
if (::ContainsEventName("change", eventPref))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
case NS_RESIZE_EVENT :
|
||||
if (::ContainsEventName("resize", eventPref))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NS_GUI_EVENT :
|
||||
switch(currentEvent->message) {
|
||||
case NS_FORM_INPUT :
|
||||
if (::ContainsEventName("input", eventPref))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NS_INPUT_EVENT :
|
||||
switch(currentEvent->message) {
|
||||
case NS_FORM_CHANGE :
|
||||
if (::ContainsEventName("change", eventPref))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NS_KEY_EVENT : {
|
||||
PRUint32 key = NS_STATIC_CAST(nsKeyEvent *, currentEvent)->keyCode;
|
||||
switch(currentEvent->message) {
|
||||
case NS_KEY_PRESS :
|
||||
// return key on focused button. see note at NS_MOUSE_LEFT_CLICK.
|
||||
if (key == nsIDOMKeyEvent::DOM_VK_RETURN)
|
||||
abuse = openAllowed;
|
||||
else if (::ContainsEventName("keypress", eventPref))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
case NS_KEY_UP :
|
||||
// space key on focused button. see note at NS_MOUSE_LEFT_CLICK.
|
||||
if (key == nsIDOMKeyEvent::DOM_VK_SPACE)
|
||||
abuse = openAllowed;
|
||||
else if (::ContainsEventName("keyup", eventPref))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
case NS_KEY_DOWN :
|
||||
if (::ContainsEventName("keydown", eventPref))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NS_MOUSE_EVENT :
|
||||
switch(currentEvent->message) {
|
||||
case NS_MOUSE_LEFT_BUTTON_UP :
|
||||
if (::ContainsEventName("mouseup", eventPref))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
case NS_MOUSE_LEFT_BUTTON_DOWN :
|
||||
if (::ContainsEventName("mousedown", eventPref))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
case NS_MOUSE_LEFT_CLICK :
|
||||
/* Click events get special treatment because of their
|
||||
historical status as a more legitimate event handler.
|
||||
If click popups are enabled in the prefs, clear the
|
||||
popup status completely. */
|
||||
if (::ContainsEventName("click", eventPref))
|
||||
abuse = openAllowed;
|
||||
break;
|
||||
case NS_MOUSE_LEFT_DOUBLECLICK :
|
||||
if (::ContainsEventName("dblclick", eventPref))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NS_SCRIPT_ERROR_EVENT :
|
||||
switch(currentEvent->message) {
|
||||
case NS_SCRIPT_ERROR :
|
||||
if (::ContainsEventName("error", eventPref))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NS_FORM_EVENT :
|
||||
switch(currentEvent->message) {
|
||||
case NS_FORM_SUBMIT :
|
||||
if (::ContainsEventName("submit", eventPref))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
case NS_FORM_RESET :
|
||||
if (::ContainsEventName("reset", eventPref))
|
||||
abuse = openControlled;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
} // switch
|
||||
} // currentEvent
|
||||
} // abuse == openAllowed
|
||||
// level of abuse we've detected, initialized to the current popup
|
||||
// state
|
||||
PopupControlState abuse = gPopupControlState;
|
||||
|
||||
// limit the number of simultaneously open popups
|
||||
if (abuse == openAbused || abuse == openControlled) {
|
||||
|
@ -3135,7 +2986,7 @@ GlobalWindowImpl::CheckForAbusePoint()
|
|||
or if its target is an extant window.
|
||||
Returns a value from the CheckOpenAllow enum. */
|
||||
PRUint32
|
||||
GlobalWindowImpl::CheckOpenAllow(PRUint32 aAbuseLevel,
|
||||
GlobalWindowImpl::CheckOpenAllow(PopupControlState aAbuseLevel,
|
||||
const nsAString &aName)
|
||||
{
|
||||
PRUint32 allowWindow = allowNoAbuse; // (also used for openControlled)
|
||||
|
@ -3249,7 +3100,7 @@ GlobalWindowImpl::Open(const nsAString& aUrl,
|
|||
{
|
||||
nsresult rv;
|
||||
|
||||
PRUint32 abuseLevel = CheckForAbusePoint();
|
||||
PopupControlState abuseLevel = CheckForAbusePoint();
|
||||
PRUint32 allowReason = CheckOpenAllow(abuseLevel, aName);
|
||||
if (allowReason == allowNot) {
|
||||
FireAbuseEvents(PR_TRUE, PR_FALSE, aUrl, aOptions);
|
||||
|
@ -3311,7 +3162,7 @@ GlobalWindowImpl::Open(nsIDOMWindow **_retval)
|
|||
}
|
||||
}
|
||||
|
||||
PRUint32 abuseLevel = CheckForAbusePoint();
|
||||
PopupControlState abuseLevel = CheckForAbusePoint();
|
||||
PRUint32 allowReason = CheckOpenAllow(abuseLevel, name);
|
||||
if (allowReason == allowNot) {
|
||||
FireAbuseEvents(PR_TRUE, PR_FALSE, url, options);
|
||||
|
@ -4894,6 +4745,23 @@ GlobalWindowImpl::SetTimeoutOrInterval(PRBool aIsInterval, PRInt32 *aReturn)
|
|||
timeout->mWindow = this;
|
||||
NS_ADDREF(timeout->mWindow);
|
||||
|
||||
// No popups from timeouts by default
|
||||
timeout->mPopupState = openAbused;
|
||||
|
||||
if (gRunningTimeoutDepth == 0 && gPopupControlState < openAbused) {
|
||||
// This timeout is *not* set from another timeout and it's set
|
||||
// while popups are enabled. Propagate the state to the timeout if
|
||||
// its delay (interval) is equal to or less than what
|
||||
// "dom.disable_open_click_delay" is set to.
|
||||
|
||||
PRInt32 delay =
|
||||
nsContentUtils::GetIntPref("dom.disable_open_click_delay");
|
||||
|
||||
if (interval <= (delay * PR_MSEC_PER_SEC)) {
|
||||
timeout->mPopupState = gPopupControlState;
|
||||
}
|
||||
}
|
||||
|
||||
InsertTimeoutIntoList(mTimeoutInsertionPoint, timeout);
|
||||
timeout->mPublicId = ++mTimeoutPublicIdCounter;
|
||||
*aReturn = timeout->mPublicId;
|
||||
|
@ -5013,10 +4881,21 @@ GlobalWindowImpl::RunTimeout(nsTimeoutImpl *aTimeout)
|
|||
mRunningTimeout = timeout;
|
||||
timeout->mRunning = PR_TRUE;
|
||||
|
||||
// Push this timeouts popup control state, which should only be
|
||||
// eabled the first time a timeout fires that was created while
|
||||
// popups were enabled and with a delay less than
|
||||
// "dom.disable_open_click_delay".
|
||||
nsAutoPopupStatePusher popupStatePusher(timeout->mPopupState);
|
||||
|
||||
// Clear the timeout's popup state, if any, to prevent interval
|
||||
// timeouts from repeatedly opening poups.
|
||||
timeout->mPopupState = openAbused;
|
||||
|
||||
// Hold on to the timeout in case mExpr or mFunObj releases its
|
||||
// doc.
|
||||
timeout->AddRef();
|
||||
|
||||
++gRunningTimeoutDepth;
|
||||
++mTimeoutFiringDepth;
|
||||
|
||||
if (timeout->mExpr) {
|
||||
|
@ -5047,6 +4926,8 @@ GlobalWindowImpl::RunTimeout(nsTimeoutImpl *aTimeout)
|
|||
}
|
||||
|
||||
--mTimeoutFiringDepth;
|
||||
--gRunningTimeoutDepth;
|
||||
|
||||
mRunningTimeout = last_running_timeout;
|
||||
timeout->mRunning = PR_FALSE;
|
||||
|
||||
|
|
|
@ -192,6 +192,10 @@ public:
|
|||
|
||||
virtual NS_HIDDEN_(void) SetOpenerScriptURL(nsIURI* aURI);
|
||||
|
||||
virtual NS_HIDDEN_(PopupControlState) PushPopupControlState(PopupControlState state) const;
|
||||
virtual NS_HIDDEN_(void) PopPopupControlState(PopupControlState state) const;
|
||||
virtual NS_HIDDEN_(PopupControlState) GetPopupControlState() const;
|
||||
|
||||
// nsIDOMViewCSS
|
||||
NS_DECL_NSIDOMVIEWCSS
|
||||
|
||||
|
@ -246,8 +250,9 @@ protected:
|
|||
nsresult GetScrollInfo(nsIScrollableView** aScrollableView, float* aP2T,
|
||||
float* aT2P);
|
||||
nsresult SecurityCheckURL(const char *aURL);
|
||||
PRUint32 CheckForAbusePoint();
|
||||
PRUint32 CheckOpenAllow(PRUint32 aAbuseLevel, const nsAString &aName);
|
||||
PopupControlState CheckForAbusePoint();
|
||||
PRUint32 CheckOpenAllow(PopupControlState aAbuseLevel,
|
||||
const nsAString &aName);
|
||||
void FireAbuseEvents(PRBool aBlocked, PRBool aWindow,
|
||||
const nsAString &aPopupURL,
|
||||
const nsAString &aPopupWindowFeatures);
|
||||
|
@ -317,7 +322,6 @@ protected:
|
|||
nsTimeoutImpl** mTimeoutInsertionPoint;
|
||||
PRUint32 mTimeoutPublicIdCounter;
|
||||
PRUint32 mTimeoutFiringDepth;
|
||||
PRTime mLastMouseButtonAction;
|
||||
nsString mStatus;
|
||||
nsString mDefaultStatus;
|
||||
|
||||
|
@ -445,6 +449,10 @@ struct nsTimeoutImpl
|
|||
// timeouts
|
||||
nsTimeoutImpl *mNext;
|
||||
|
||||
// The popup state at timeout creation time if not created from
|
||||
// another timeout
|
||||
PopupControlState mPopupState;
|
||||
|
||||
private:
|
||||
// reference count for shared usage
|
||||
PRInt32 mRefCnt;
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
#include <mshtml.h>
|
||||
#include <hlink.h>
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
// A barely documented interface called ITargetFrame from IE
|
||||
// This is needed for targeted Hlink* calls (e.g. HlinkNavigateString) to
|
||||
|
@ -1831,6 +1832,12 @@ END_COM_MAP()
|
|||
nsCOMPtr<nsILinkHandler> lh = do_QueryInterface(webNav);
|
||||
if (lh)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window =
|
||||
do_GetInterface(mDOMWindow);
|
||||
|
||||
nsAutoPopupStatePusher popupStatePusher(window,
|
||||
openAllowed);
|
||||
|
||||
lh->OnLinkClick(nsnull, eLinkVerb_Replace,
|
||||
uri, szTargetFrame ? szTargetFrame : mUseTarget);
|
||||
}
|
||||
|
|
|
@ -76,8 +76,8 @@
|
|||
#include "nsIViewObserver.h"
|
||||
#include "nsContainerFrame.h"
|
||||
#include "nsIDeviceContext.h"
|
||||
#include "nsIEventStateManager.h"
|
||||
#include "nsIDOMEvent.h"
|
||||
#include "nsEventStateManager.h"
|
||||
#include "nsDOMEvent.h"
|
||||
#include "nsGUIEvent.h"
|
||||
#include "nsHTMLParts.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
@ -5899,6 +5899,37 @@ PresShell::HandleEventInternal(nsEvent* aEvent, nsIView *aView,
|
|||
nsresult rv = NS_OK;
|
||||
|
||||
if (!NS_EVENT_NEEDS_FRAME(aEvent) || GetCurrentEventFrame()) {
|
||||
PRBool isHandlingUserInput = PR_FALSE;
|
||||
|
||||
if (aEvent->internalAppFlags & NS_APP_EVENT_FLAG_TRUSTED) {
|
||||
switch (aEvent->message) {
|
||||
case NS_GOTFOCUS:
|
||||
case NS_LOSTFOCUS:
|
||||
case NS_ACTIVATE:
|
||||
case NS_DEACTIVATE:
|
||||
// Treat focus/blur events as user input if they happen while
|
||||
// executing trusted script, or no script at all. If they
|
||||
// happen during execution of non-trusted script, then they
|
||||
// should not be considerd user input.
|
||||
if (!nsContentUtils::IsCallerChrome()) {
|
||||
break;
|
||||
}
|
||||
case NS_MOUSE_LEFT_BUTTON_DOWN:
|
||||
case NS_MOUSE_MIDDLE_BUTTON_DOWN:
|
||||
case NS_MOUSE_RIGHT_BUTTON_DOWN:
|
||||
case NS_MOUSE_LEFT_BUTTON_UP:
|
||||
case NS_MOUSE_RIGHT_BUTTON_UP:
|
||||
case NS_MOUSE_MIDDLE_BUTTON_UP:
|
||||
case NS_KEY_PRESS:
|
||||
case NS_KEY_DOWN:
|
||||
case NS_KEY_UP:
|
||||
isHandlingUserInput = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoHandlingUserInputStatePusher userInpStatePusher(isHandlingUserInput);
|
||||
|
||||
nsAutoPopupStatePusher popupStatePusher(nsDOMEvent::GetEventPopupControlState(aEvent));
|
||||
|
||||
// 1. Give event to event manager for pre event state changes and
|
||||
// generation of synthetic events.
|
||||
|
|
|
@ -2286,6 +2286,8 @@ NS_IMETHODIMP nsPluginInstanceOwner::GetURL(const char *aURL, const char *aTarge
|
|||
}
|
||||
}
|
||||
|
||||
nsAutoPopupStatePusher popupStatePusher(openAllowed);
|
||||
|
||||
rv = lh->OnLinkClick(content, eLinkVerb_Replace,
|
||||
uri, unitarget.get(),
|
||||
postDataStream, headersDataStream);
|
||||
|
|
|
@ -168,6 +168,7 @@ LOCAL_INCLUDES = \
|
|||
-I$(srcdir)/../../style/src \
|
||||
-I$(srcdir)/../../forms/src \
|
||||
-I$(srcdir)/../../../base/src \
|
||||
-I$(srcdir)/../../../../content/events/src \
|
||||
-I$(srcdir) \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
@ -2286,6 +2286,8 @@ NS_IMETHODIMP nsPluginInstanceOwner::GetURL(const char *aURL, const char *aTarge
|
|||
}
|
||||
}
|
||||
|
||||
nsAutoPopupStatePusher popupStatePusher(openAllowed);
|
||||
|
||||
rv = lh->OnLinkClick(content, eLinkVerb_Replace,
|
||||
uri, unitarget.get(),
|
||||
postDataStream, headersDataStream);
|
||||
|
|
|
@ -76,8 +76,8 @@
|
|||
#include "nsIViewObserver.h"
|
||||
#include "nsContainerFrame.h"
|
||||
#include "nsIDeviceContext.h"
|
||||
#include "nsIEventStateManager.h"
|
||||
#include "nsIDOMEvent.h"
|
||||
#include "nsEventStateManager.h"
|
||||
#include "nsDOMEvent.h"
|
||||
#include "nsGUIEvent.h"
|
||||
#include "nsHTMLParts.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
@ -5899,6 +5899,37 @@ PresShell::HandleEventInternal(nsEvent* aEvent, nsIView *aView,
|
|||
nsresult rv = NS_OK;
|
||||
|
||||
if (!NS_EVENT_NEEDS_FRAME(aEvent) || GetCurrentEventFrame()) {
|
||||
PRBool isHandlingUserInput = PR_FALSE;
|
||||
|
||||
if (aEvent->internalAppFlags & NS_APP_EVENT_FLAG_TRUSTED) {
|
||||
switch (aEvent->message) {
|
||||
case NS_GOTFOCUS:
|
||||
case NS_LOSTFOCUS:
|
||||
case NS_ACTIVATE:
|
||||
case NS_DEACTIVATE:
|
||||
// Treat focus/blur events as user input if they happen while
|
||||
// executing trusted script, or no script at all. If they
|
||||
// happen during execution of non-trusted script, then they
|
||||
// should not be considerd user input.
|
||||
if (!nsContentUtils::IsCallerChrome()) {
|
||||
break;
|
||||
}
|
||||
case NS_MOUSE_LEFT_BUTTON_DOWN:
|
||||
case NS_MOUSE_MIDDLE_BUTTON_DOWN:
|
||||
case NS_MOUSE_RIGHT_BUTTON_DOWN:
|
||||
case NS_MOUSE_LEFT_BUTTON_UP:
|
||||
case NS_MOUSE_RIGHT_BUTTON_UP:
|
||||
case NS_MOUSE_MIDDLE_BUTTON_UP:
|
||||
case NS_KEY_PRESS:
|
||||
case NS_KEY_DOWN:
|
||||
case NS_KEY_UP:
|
||||
isHandlingUserInput = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoHandlingUserInputStatePusher userInpStatePusher(isHandlingUserInput);
|
||||
|
||||
nsAutoPopupStatePusher popupStatePusher(nsDOMEvent::GetEventPopupControlState(aEvent));
|
||||
|
||||
// 1. Give event to event manager for pre event state changes and
|
||||
// generation of synthetic events.
|
||||
|
|
|
@ -1772,6 +1772,11 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aS
|
|||
{
|
||||
*aStatus = nsEventStatus_eIgnore;
|
||||
|
||||
// Mark all events coming through here as trusted events, as the
|
||||
// only code that calls this is the widget code that translates OS
|
||||
// events into mozilla events.
|
||||
aEvent->internalAppFlags |= NS_APP_EVENT_FLAG_TRUSTED;
|
||||
|
||||
switch(aEvent->message)
|
||||
{
|
||||
case NS_SIZE:
|
||||
|
|
|
@ -108,8 +108,15 @@ class nsIURI;
|
|||
#define NS_EVENT_CAPTURE_MASK (~(NS_EVENT_FLAG_INIT | NS_EVENT_FLAG_BUBBLE | NS_EVENT_FLAG_NO_CONTENT_DISPATCH))
|
||||
#define NS_EVENT_BUBBLE_MASK (~(NS_EVENT_FLAG_INIT | NS_EVENT_FLAG_CAPTURE | NS_EVENT_FLAG_NO_CONTENT_DISPATCH))
|
||||
|
||||
#define NS_APP_EVENT_FLAG_NONE 0x0000
|
||||
#define NS_APP_EVENT_FLAG_HANDLED 0x0001 // Similar to NS_EVENT_FLAG_NO_DEFAULT, but it allows focus
|
||||
// Flags for internalAppFlags
|
||||
|
||||
#define NS_APP_EVENT_FLAG_NONE 0x00000000
|
||||
|
||||
// Similar to NS_EVENT_FLAG_NO_DEFAULT, but it allows focus
|
||||
#define NS_APP_EVENT_FLAG_HANDLED 0x00000001
|
||||
|
||||
// True if the event came from a trusted source
|
||||
#define NS_APP_EVENT_FLAG_TRUSTED 0x00000002
|
||||
|
||||
#define NS_EVENT_TYPE_NULL 0
|
||||
|
||||
|
@ -344,8 +351,8 @@ struct nsEvent {
|
|||
point(0, 0),
|
||||
refPoint(0, 0),
|
||||
time(0),
|
||||
flags(0),
|
||||
internalAppFlags(0),
|
||||
flags(0),
|
||||
internalAppFlags(NS_APP_EVENT_FLAG_NONE),
|
||||
userType(0)
|
||||
{
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче