diff --git a/mozilla/content/events/src/nsDOMEvent.cpp b/mozilla/content/events/src/nsDOMEvent.cpp index aa57434fab8..c8d461c254f 100644 --- a/mozilla/content/events/src/nsDOMEvent.cpp +++ b/mozilla/content/events/src/nsDOMEvent.cpp @@ -40,7 +40,7 @@ #include "nsCOMPtr.h" #include "nsDOMEvent.h" #include "nsIDOMNode.h" -#include "nsIEventStateManager.h" +#include "nsEventStateManager.h" #include "nsIFrame.h" #include "nsIContent.h" #include "nsIRenderingContext.h" @@ -63,6 +63,8 @@ #include "nsIDOMKeyEvent.h" #include "nsIDOMMutationEvent.h" #include "nsIURI.h" +#include "nsIPrefBranch.h" +#include "nsIPrefService.h" static const char* const sEventNames[] = { "mousedown", "mouseup", "click", "dblclick", "mouseover", @@ -92,6 +94,9 @@ static PRInt32 numAllocFromPool=0; //#define NOISY_EVENT_LEAKS // define NOISY_EVENT_LEAKS to get metrics printed to stdout for all nsDOMEvent allocations #endif +static char *sPopupAllowedEvents; + + // allocate the memory for the object from the recycler, if possible // otherwise, just grab it from the heap. void* @@ -152,11 +157,9 @@ nsDOMEvent::nsDOMEvent(nsIPresContext* aPresContext, nsEvent* aEvent, { mPresContext = aPresContext; - mEventIsTrusted = PR_FALSE; if (aEvent) { mEvent = aEvent; - mEventIsTrusted = PR_TRUE; } else { mEventIsInternal = PR_TRUE; @@ -406,14 +409,18 @@ nsDOMEvent::HasOriginalTarget(PRBool* aResult) NS_IMETHODIMP nsDOMEvent::IsTrustedEvent(PRBool* aResult) { - *aResult = mEventIsTrusted; - return NS_OK; + return GetIsTrusted(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; } @@ -485,7 +492,7 @@ nsDOMEvent::PreventCapture() NS_IMETHODIMP nsDOMEvent::GetIsTrusted(PRBool *aIsTrusted) { - *aIsTrusted = mEventIsTrusted; + *aIsTrusted = mEvent->internalAppFlags & NS_APP_EVENT_FLAG_TRUSTED; return NS_OK; } @@ -1260,7 +1267,7 @@ 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; } @@ -1455,10 +1462,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; } @@ -1471,6 +1478,205 @@ 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; + } + } + 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); + } + + nsCOMPtr prefBranch = + do_GetService(NS_PREFSERVICE_CONTRACTID); + + if (prefBranch) { + prefBranch->GetCharPref("dom.popup_allowed_events", &sPopupAllowedEvents); + } +} + +// static +void +nsDOMEvent::Shutdown() +{ + if (sPopupAllowedEvents) { + nsMemory::Free(sPopupAllowedEvents); + } +} + +// static const char* nsDOMEvent::GetEventName(PRUint32 aEventType) { switch(aEventType) { @@ -1538,7 +1744,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: diff --git a/mozilla/content/events/src/nsDOMEvent.h b/mozilla/content/events/src/nsDOMEvent.h index f9b548519af..f849ea2bc28 100644 --- a/mozilla/content/events/src/nsDOMEvent.h +++ b/mozilla/content/events/src/nsDOMEvent.h @@ -49,6 +49,7 @@ #include "nsIPrivateCompositionEvent.h" #include "nsIPrivateTextEvent.h" #include "nsIPrivateTextRange.h" +#include "nsPIDOMWindow.h" #include "nsIDOMEvent.h" #include "nsCOMPtr.h" #include "nsIDOMEventTarget.h" @@ -217,6 +218,12 @@ public: */ void operator delete(void* aPtr); + static PopupControlState GetEventPopupControlState(nsEvent *aEvent); + + static void PopupAllowedEventsChanged(); + + static void Shutdown(); + protected: nsDOMEvent() {}; // private constructor for pool, not for general use @@ -233,7 +240,7 @@ protected: nsresult GetScrollInfo(nsIScrollableView** aScrollableView, float* aP2T, float* aT2P); nsresult SetEventType(const nsAString& aEventTypeArg); - const char* GetEventName(PRUint32 aEventType); + static const char* GetEventName(PRUint32 aEventType); already_AddRefed GetTargetFromFrame(); void AllocateEvent(const nsAString& aEventType); @@ -247,7 +254,6 @@ protected: nsString* mText; nsCOMPtr mTextRange; PRPackedBool mEventIsInternal; - PRPackedBool mEventIsTrusted; //These are use for internal data for user created events PRInt16 mButton; diff --git a/mozilla/content/events/src/nsEventListenerManager.cpp b/mozilla/content/events/src/nsEventListenerManager.cpp index 747e7166eb2..209f9183417 100644 --- a/mozilla/content/events/src/nsEventListenerManager.cpp +++ b/mozilla/content/events/src/nsEventListenerManager.cpp @@ -429,6 +429,8 @@ nsresult nsEventListenerManager::RemoveAllListeners(PRBool aScriptOnly) void nsEventListenerManager::Shutdown() { sAddListenerID = JSVAL_VOID; + + nsDOMEvent::Shutdown(); } NS_IMPL_ADDREF(nsEventListenerManager) @@ -1509,6 +1511,8 @@ nsresult nsEventListenerManager::HandleEvent(nsIPresContext* 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) { diff --git a/mozilla/content/events/src/nsEventStateManager.cpp b/mozilla/content/events/src/nsEventStateManager.cpp index fff0f92b635..9f31ba83031 100644 --- a/mozilla/content/events/src/nsEventStateManager.cpp +++ b/mozilla/content/events/src/nsEventStateManager.cpp @@ -145,6 +145,8 @@ PRInt8 nsEventStateManager::sTextfieldSelectModel = eTextfieldSelect_unset; PRUint32 nsEventStateManager::mInstanceCount = 0; PRInt32 nsEventStateManager::gGeneralAccesskeyModifier = -1; // magic value of -1 means uninitialized +PRInt32 nsEventStateManager::sUserInputEventDepth = 0; + enum { MOUSE_SCROLL_N_LINES, MOUSE_SCROLL_PAGE, @@ -253,6 +255,8 @@ nsEventStateManager::Init() } mPrefBranch->AddObserver("accessibility.browsewithcaret", this, PR_TRUE); + + mPrefBranch->AddObserver("dom.popup_allowed_events", this, PR_TRUE); } if (nsEventStateManager::sTextfieldSelectModel == eTextfieldSelect_unset) { @@ -309,7 +313,8 @@ nsresult nsEventStateManager::Shutdown() { mPrefBranch->RemoveObserver("accessibility.browsewithcaret", this); - + mPrefBranch->RemoveObserver("dom.popup_allowed_events", this); + mPrefBranch = nsnull; m_haveShutdown = PR_TRUE; @@ -340,9 +345,15 @@ nsEventStateManager::Observe(nsISupports *aSubject, if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) Shutdown(); else if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) { - if (someData && nsDependentString(someData).Equals(NS_LITERAL_STRING("accessibility.browsewithcaret"))) { - PRBool browseWithCaret; - ResetBrowseWithCaret(&browseWithCaret); + if (someData) { + nsDependentString str(someData); + + if (str.Equals(NS_LITERAL_STRING("accessibility.browsewithcaret"))) { + PRBool browseWithCaret; + ResetBrowseWithCaret(&browseWithCaret); + } else if (str.Equals(NS_LITERAL_STRING("dom.popup_allowed_events"))) { + nsDOMEvent::PopupAllowedEventsChanged(); + } } } @@ -975,6 +986,11 @@ nsEventStateManager::HandleAccessKey(nsIPresContext* 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; + content->HandleDOMEvent(mPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status); } diff --git a/mozilla/content/events/src/nsEventStateManager.h b/mozilla/content/events/src/nsEventStateManager.h index 3429103fe9e..ab92335d80e 100644 --- a/mozilla/content/events/src/nsEventStateManager.h +++ b/mozilla/content/events/src/nsEventStateManager.h @@ -162,6 +162,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; @@ -361,6 +376,36 @@ protected: nsCOMPtr 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__ diff --git a/mozilla/content/html/content/src/Makefile.in b/mozilla/content/html/content/src/Makefile.in index cc9f16e01a4..6bccc238dc9 100644 --- a/mozilla/content/html/content/src/Makefile.in +++ b/mozilla/content/html/content/src/Makefile.in @@ -128,7 +128,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 diff --git a/mozilla/content/html/content/src/nsHTMLFormElement.cpp b/mozilla/content/html/content/src/nsHTMLFormElement.cpp index 109296e6ed2..dabef8f2aed 100644 --- a/mozilla/content/html/content/src/nsHTMLFormElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLFormElement.cpp @@ -46,6 +46,7 @@ #include "nsIDOMEventReceiver.h" #include "nsIHTMLContent.h" #include "nsGenericHTMLElement.h" +#include "nsEventStateManager.h" #include "nsHTMLAtoms.h" #include "nsStyleConsts.h" #include "nsIPresContext.h" @@ -69,6 +70,7 @@ #include "nsCategoryManagerUtils.h" #include "nsISimpleEnumerator.h" #include "nsIDOMWindowInternal.h" +#include "nsPIDOMWindow.h" #include "nsRange.h" #include "nsIScriptSecurityManager.h" #include "nsNetUtil.h" @@ -103,6 +105,8 @@ public: mGeneratingReset(PR_FALSE), mIsSubmitting(PR_FALSE), mDeferSubmission(PR_FALSE), + mSubmitPopupState(openAbused), + mSubmitInitiatedFromUserInput(PR_FALSE), mPendingSubmission(nsnull), mSubmittingRequest(nsnull) { @@ -275,6 +279,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 mPendingSubmission; @@ -834,7 +842,18 @@ nsHTMLFormElement::DoSubmit(nsIPresContext* aPresContext, nsEvent* aEvent) // prepare the submission object // BuildSubmission(aPresContext, submission, aEvent); - + + nsCOMPtr window = + do_QueryInterface(nsGenericElement::GetOwnerDocument()->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 @@ -931,9 +950,17 @@ nsHTMLFormElement::SubmitSubmission(nsIPresContext* aPresContext, // Submit // nsCOMPtr 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 diff --git a/mozilla/docshell/base/nsWebShell.cpp b/mozilla/docshell/base/nsWebShell.cpp index d1d5fe9b584..d121de3be32 100644 --- a/mozilla/docshell/base/nsWebShell.cpp +++ b/mozilla/docshell/base/nsWebShell.cpp @@ -428,6 +428,9 @@ struct OnLinkClickEvent : public PLEvent { ~OnLinkClickEvent(); void HandleEvent() { + nsCOMPtr 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 mHeadersDataStream; nsCOMPtr 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 window(do_QueryInterface(mHandler->mScriptGlobal)); + + mPopupState = window->GetPopupControlState(); + PL_InitEvent(this, nsnull, (PLHandleEventProc) ::HandlePLEvent, (PLDestroyEventProc) ::DestroyPLEvent); diff --git a/mozilla/docshell/base/nsWebShell.h b/mozilla/docshell/base/nsWebShell.h index 731902fa9e9..c6c3a870160 100644 --- a/mozilla/docshell/base/nsWebShell.h +++ b/mozilla/docshell/base/nsWebShell.h @@ -36,6 +36,7 @@ class nsIEventQueue; class nsIController; struct PRThread; +struct OnLinkClickEvent; typedef enum { eCharsetReloadInit, @@ -99,6 +100,8 @@ public: // NS_IMETHOD SetURL(const PRUnichar* aURL); + friend struct OnLinkClickEvent; + protected: // void GetRootWebShellEvenIfChrome(nsIWebShell** aResult); void InitFrameData(); diff --git a/mozilla/dom/public/base/nsPIDOMWindow.h b/mozilla/dom/public/base/nsPIDOMWindow.h index 146406ab5b9..26688715720 100644 --- a/mozilla/dom/public/base/nsPIDOMWindow.h +++ b/mozilla/dom/public/base/nsPIDOMWindow.h @@ -46,6 +46,19 @@ #include "nsIDOMXULCommandDispatcher.h" #include "nsIDocument.h" #include "nsIDOMElement.h" +#include "nsCOMPtr.h" + +// Popup control state enum. The values in this enum must go from most +// permissive to least permissive so that it's 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 nsIDOMWindowInternal; @@ -96,6 +109,65 @@ public: NS_IMETHOD SetPopupSpamWindow(PRBool aPopup) = 0; NS_IMETHOD SetOpenerScriptURL(nsIURI* aURI) = 0; + + virtual PopupControlState PushPopupControlState(PopupControlState aState) const = 0; + virtual void PopPopupControlState(PopupControlState state) const = 0; + virtual PopupControlState GetPopupControlState() const = 0; +}; + + +#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: +#ifndef _IMPL_NS_LAYOUT + nsCOMPtr mWindow; +#endif + PopupControlState mOldState; + +private: + // Hide so that this class can only be stack-allocated + static void* operator new(size_t /*size*/) CPP_THROW_NEW { return nsnull; } + static void operator delete(void* /*memory*/) {} }; #endif // nsPIDOMWindow_h__ diff --git a/mozilla/dom/src/base/Makefile.in b/mozilla/dom/src/base/Makefile.in index 3fc991508bd..9f05c98493c 100644 --- a/mozilla/dom/src/base/Makefile.in +++ b/mozilla/dom/src/base/Makefile.in @@ -93,3 +93,5 @@ FORCE_STATIC_LIB = 1 LOCAL_INCLUDES = -I$(srcdir)/../events include $(topsrcdir)/config/rules.mk + +DEFINES += -D_IMPL_NS_LAYOUT diff --git a/mozilla/dom/src/base/nsGlobalWindow.cpp b/mozilla/dom/src/base/nsGlobalWindow.cpp index 5df38749909..de62175241e 100644 --- a/mozilla/dom/src/base/nsGlobalWindow.cpp +++ b/mozilla/dom/src/base/nsGlobalWindow.cpp @@ -161,6 +161,8 @@ static nsIEntropyCollector *gEntropyCollector = nsnull; static nsIPrefBranch *gPrefBranch = nsnull; static PRInt32 gRefCnt = 0; static PRInt32 gOpenPopupSpamCount = 0; +static PopupControlState gPopupControlState = openAbused; +static PRInt32 gRunningTimeoutDepth = 0; nsIXPConnect *GlobalWindowImpl::sXPConnect = nsnull; nsIScriptSecurityManager *GlobalWindowImpl::sSecMan = nsnull; nsIFactory *GlobalWindowImpl::sComputedDOMStyleFactory = nsnull; @@ -190,13 +192,6 @@ static const char kDOMSecurityWarningsBundleURL[] = "chrome://global/locale/dom/ 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 @@ -206,36 +201,6 @@ enum { allowWhitelisted // allowed: it's whitelisted or popup blocking is disabled }; -// 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 //***************************************************************************** @@ -254,7 +219,6 @@ GlobalWindowImpl::GlobalWindowImpl() mIsClosed(PR_FALSE), mOpenerWasCleared(PR_FALSE), mIsPopupSpam(PR_FALSE), - mLastMouseButtonAction(LL_ZERO), mGlobalObjectOwner(nsnull), mDocShell(nsnull), mCurrentEvent(0), @@ -441,6 +405,42 @@ GlobalWindowImpl::SetOpenerScriptURL(nsIURI* aURI) return NS_OK; } +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, @@ -890,11 +890,6 @@ GlobalWindowImpl::HandleDOMEvent(nsIPresContext* 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 @@ -2981,10 +2976,18 @@ GlobalWindowImpl::DisableExternalCapture() static PRBool IsPopupBlocked(nsIDOMDocument* aDoc) { - PRBool blocked = PR_FALSE; + nsCOMPtr pm = + do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID); + + if (!pm) { + return PR_FALSE; + } + nsCOMPtr doc(do_QueryInterface(aDoc)); - nsCOMPtr pm(do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID)); - if (pm && doc) { + + PRBool blocked = PR_TRUE; + + if (doc) { PRUint32 permission = nsIPopupWindowManager::ALLOW_POPUP; pm->TestPermission(doc->GetDocumentURI(), &permission); blocked = (permission == nsIPopupWindowManager::DENY_POPUP); @@ -3050,7 +3053,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 item(do_QueryInterface(mDocShell)); @@ -3066,166 +3069,9 @@ GlobalWindowImpl::CheckForAbusePoint() if (!gPrefBranch) 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 = 0; - gPrefBranch->GetIntPref("dom.disable_open_click_delay", &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 presShell; - mDocShell->GetPresShell(getter_AddRefs(presShell)); - if (presShell) { - nsCOMPtr presContext; - presShell->GetPresContext(getter_AddRefs(presContext)); - if (presContext) - presContext->EventStateManager()->GetCurrentEvent(¤tEvent); - } - } - - // fetch pref string detailing which events are allowed - nsXPIDLCString eventPref; - gPrefBranch->GetCharPref("dom.popup_allowed_events", - getter_Copies(eventPref)); - nsCAutoString eventPrefStr(eventPref); - - // 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) { @@ -3243,7 +3089,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) @@ -3357,7 +3203,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); @@ -3422,7 +3268,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); @@ -5053,6 +4899,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 (in ms). + + PRInt32 delay = 0; + gPrefBranch->GetIntPref("dom.disable_open_click_delay", &delay); + + if (interval <= delay) { + timeout->mPopupState = gPopupControlState; + } + } + InsertTimeoutIntoList(mTimeoutInsertionPoint, timeout); timeout->mPublicId = ++mTimeoutPublicIdCounter; *aReturn = timeout->mPublicId; @@ -5172,10 +5035,21 @@ GlobalWindowImpl::RunTimeout(nsTimeoutImpl *aTimeout) mRunningTimeout = timeout; timeout->mRunning = PR_TRUE; + // Push this timeout's 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) { @@ -5207,6 +5081,8 @@ GlobalWindowImpl::RunTimeout(nsTimeoutImpl *aTimeout) } --mTimeoutFiringDepth; + --gRunningTimeoutDepth; + mRunningTimeout = last_running_timeout; timeout->mRunning = PR_FALSE; diff --git a/mozilla/dom/src/base/nsGlobalWindow.h b/mozilla/dom/src/base/nsGlobalWindow.h index d831d7e736b..8b52ee49ad0 100644 --- a/mozilla/dom/src/base/nsGlobalWindow.h +++ b/mozilla/dom/src/base/nsGlobalWindow.h @@ -201,6 +201,10 @@ public: NS_IMETHOD SetFrameElementInternal(nsIDOMElement* aFrameElement); NS_IMETHOD 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 @@ -249,8 +253,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); @@ -318,7 +323,6 @@ protected: PRPackedBool mIsClosed; PRPackedBool mOpenerWasCleared; PRPackedBool mIsPopupSpam; - PRTime mLastMouseButtonAction; nsString mStatus; nsString mDefaultStatus; @@ -451,6 +455,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; diff --git a/mozilla/embedding/browser/activex/src/plugin/XPCDocument.cpp b/mozilla/embedding/browser/activex/src/plugin/XPCDocument.cpp index abeae2535a4..f55e9241bc6 100644 --- a/mozilla/embedding/browser/activex/src/plugin/XPCDocument.cpp +++ b/mozilla/embedding/browser/activex/src/plugin/XPCDocument.cpp @@ -125,6 +125,7 @@ public: #include "nsIScriptGlobalObject.h" #include "nsIScriptContext.h" #include "nsIPrincipal.h" +#include "nsPIDOMWindow.h" #include "XPConnect.h" #include "XPCBrowser.h" @@ -1833,6 +1834,12 @@ END_COM_MAP() nsCOMPtr lh = do_QueryInterface(webNav); if (lh) { + nsCOMPtr window = + do_GetInterface(mDOMWindow); + + nsAutoPopupStatePusher popupStatePusher(window, + openAllowed); + lh->OnLinkClick(nsnull, eLinkVerb_Replace, uri, szTargetFrame ? szTargetFrame : mUseTarget); } diff --git a/mozilla/layout/html/base/src/Makefile.in b/mozilla/layout/html/base/src/Makefile.in index 87160d64a74..64e5aa3c96c 100644 --- a/mozilla/layout/html/base/src/Makefile.in +++ b/mozilla/layout/html/base/src/Makefile.in @@ -152,6 +152,7 @@ LOCAL_INCLUDES = \ -I$(srcdir)/../../style/src \ -I$(srcdir)/../../forms/src \ -I$(srcdir)/../../../base/src \ + -I$(srcdir)/../../../../content/events/src \ -I$(srcdir) \ $(NULL) diff --git a/mozilla/layout/html/base/src/nsObjectFrame.cpp b/mozilla/layout/html/base/src/nsObjectFrame.cpp index cf88199a097..ba92effa281 100644 --- a/mozilla/layout/html/base/src/nsObjectFrame.cpp +++ b/mozilla/layout/html/base/src/nsObjectFrame.cpp @@ -2653,6 +2653,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); diff --git a/mozilla/layout/html/base/src/nsPresShell.cpp b/mozilla/layout/html/base/src/nsPresShell.cpp index f9d140beacb..1faf7215cfb 100644 --- a/mozilla/layout/html/base/src/nsPresShell.cpp +++ b/mozilla/layout/html/base/src/nsPresShell.cpp @@ -40,6 +40,7 @@ #define PL_ARENA_CONST_ALIGN_MASK 3 #include "nsIPresShell.h" #include "nsIPresContext.h" +#include "nsContentUtils.h" #include "nsIContent.h" #include "nsIDocument.h" #include "nsIDOMXULDocument.h" @@ -64,8 +65,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 "nsISelection.h" @@ -6009,6 +6010,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. diff --git a/mozilla/modules/libpref/src/init/all.js b/mozilla/modules/libpref/src/init/all.js index e5a65034496..e45430558fd 100644 --- a/mozilla/modules/libpref/src/init/all.js +++ b/mozilla/modules/libpref/src/init/all.js @@ -414,6 +414,7 @@ pref("dom.allow_scripts_to_close_windows", false); pref("dom.disable_open_during_load", false); pref("dom.popup_maximum", 20); pref("dom.popup_allowed_events", "change click dblclick mouseup reset submit"); +pref("dom.disable_open_click_delay", 1000); pref("dom.event.contextmenu.enabled", true); diff --git a/mozilla/view/src/nsViewManager.cpp b/mozilla/view/src/nsViewManager.cpp index abdab7df36f..baa12a821eb 100644 --- a/mozilla/view/src/nsViewManager.cpp +++ b/mozilla/view/src/nsViewManager.cpp @@ -1816,6 +1816,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: diff --git a/mozilla/widget/public/nsGUIEvent.h b/mozilla/widget/public/nsGUIEvent.h index 5a1cb03f63f..ed54baec252 100644 --- a/mozilla/widget/public/nsGUIEvent.h +++ b/mozilla/widget/public/nsGUIEvent.h @@ -106,8 +106,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 @@ -335,8 +342,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) { }