diff --git a/mozilla/content/events/src/nsDOMEvent.cpp b/mozilla/content/events/src/nsDOMEvent.cpp index cece0917832..06c0c8872b9 100644 --- a/mozilla/content/events/src/nsDOMEvent.cpp +++ b/mozilla/content/events/src/nsDOMEvent.cpp @@ -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: diff --git a/mozilla/content/events/src/nsDOMEvent.h b/mozilla/content/events/src/nsDOMEvent.h index cad93a0653a..3d6b59b9e95 100644 --- a/mozilla/content/events/src/nsDOMEvent.h +++ b/mozilla/content/events/src/nsDOMEvent.h @@ -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 mExplicitOriginalTarget; nsCOMPtr mTmpRealOriginalTarget; PRPackedBool mEventIsInternal; - PRPackedBool mEventIsTrusted; void* mScriptObject; }; diff --git a/mozilla/content/events/src/nsDOMKeyboardEvent.cpp b/mozilla/content/events/src/nsDOMKeyboardEvent.cpp index 0c1ec2e2862..965ad726907 100644 --- a/mozilla/content/events/src/nsDOMKeyboardEvent.cpp +++ b/mozilla/content/events/src/nsDOMKeyboardEvent.cpp @@ -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(); } } diff --git a/mozilla/content/events/src/nsDOMMouseEvent.cpp b/mozilla/content/events/src/nsDOMMouseEvent.cpp index ab63144982c..6190b23a55f 100644 --- a/mozilla/content/events/src/nsDOMMouseEvent.cpp +++ b/mozilla/content/events/src/nsDOMMouseEvent.cpp @@ -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; } diff --git a/mozilla/content/events/src/nsDOMMutationEvent.cpp b/mozilla/content/events/src/nsDOMMutationEvent.cpp index 9dd247679c6..3512b3c389a 100644 --- a/mozilla/content/events/src/nsDOMMutationEvent.cpp +++ b/mozilla/content/events/src/nsDOMMutationEvent.cpp @@ -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; } } diff --git a/mozilla/content/events/src/nsDOMPopupBlockedEvent.cpp b/mozilla/content/events/src/nsDOMPopupBlockedEvent.cpp index af401ab4f78..d9e7349bbfe 100644 --- a/mozilla/content/events/src/nsDOMPopupBlockedEvent.cpp +++ b/mozilla/content/events/src/nsDOMPopupBlockedEvent.cpp @@ -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(); } } diff --git a/mozilla/content/events/src/nsDOMTextEvent.cpp b/mozilla/content/events/src/nsDOMTextEvent.cpp index a6d301e80e5..468946416d5 100644 --- a/mozilla/content/events/src/nsDOMTextEvent.cpp +++ b/mozilla/content/events/src/nsDOMTextEvent.cpp @@ -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(); } diff --git a/mozilla/content/events/src/nsDOMUIEvent.cpp b/mozilla/content/events/src/nsDOMUIEvent.cpp index 027fce08e41..c50a43ef974 100644 --- a/mozilla/content/events/src/nsDOMUIEvent.cpp +++ b/mozilla/content/events/src/nsDOMUIEvent.cpp @@ -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(); } diff --git a/mozilla/content/events/src/nsEventListenerManager.cpp b/mozilla/content/events/src/nsEventListenerManager.cpp index 6b4d79474c6..a09570952ed 100644 --- a/mozilla/content/events/src/nsEventListenerManager.cpp +++ b/mozilla/content/events/src/nsEventListenerManager.cpp @@ -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) { diff --git a/mozilla/content/events/src/nsEventStateManager.cpp b/mozilla/content/events/src/nsEventStateManager.cpp index a101aca26d5..2ca21a54772 100644 --- a/mozilla/content/events/src/nsEventStateManager.cpp +++ b/mozilla/content/events/src/nsEventStateManager.cpp @@ -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 oldTargetContent = mCurrentTargetContent; mCurrentTargetContent = content; 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 8f7d44da736..162098b582b 100644 --- a/mozilla/content/events/src/nsEventStateManager.h +++ b/mozilla/content/events/src/nsEventStateManager.h @@ -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 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 d031e908d0e..77e8b124630 100644 --- a/mozilla/content/html/content/src/Makefile.in +++ b/mozilla/content/html/content/src/Makefile.in @@ -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 diff --git a/mozilla/content/html/content/src/nsHTMLFormElement.cpp b/mozilla/content/html/content/src/nsHTMLFormElement.cpp index 60fb9da2f54..2721eb51d18 100644 --- a/mozilla/content/html/content/src/nsHTMLFormElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLFormElement.cpp @@ -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 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 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 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 ae754636d40..043486105b6 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 80e5a9a4322..1caabb8aae5 100644 --- a/mozilla/docshell/base/nsWebShell.h +++ b/mozilla/docshell/base/nsWebShell.h @@ -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(); diff --git a/mozilla/dom/public/base/Makefile.in b/mozilla/dom/public/base/Makefile.in index 7901061019d..0f2e433af14 100644 --- a/mozilla/dom/public/base/Makefile.in +++ b/mozilla/dom/public/base/Makefile.in @@ -48,3 +48,4 @@ EXPORTS=nsPIDOMWindow.h nsPIWindowRoot.h nsIFocusController.h include $(topsrcdir)/config/rules.mk +DEFINES += -D_IMPL_NS_LAYOUT diff --git a/mozilla/dom/public/base/nsPIDOMWindow.h b/mozilla/dom/public/base/nsPIDOMWindow.h index 666d89e7769..6d860bce30e 100644 --- a/mozilla/dom/public/base/nsPIDOMWindow.h +++ b/mozilla/dom/public/base/nsPIDOMWindow.h @@ -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 mChromeEventHandler; // strong nsCOMPtr 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__ diff --git a/mozilla/dom/src/base/nsGlobalWindow.cpp b/mozilla/dom/src/base/nsGlobalWindow.cpp index 4f3c2822593..cc3fbb773d6 100644 --- a/mozilla/dom/src/base/nsGlobalWindow.cpp +++ b/mozilla/dom/src/base/nsGlobalWindow.cpp @@ -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 pm = + do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID); + + if (!pm) { + return PR_FALSE; + } + + PRBool blocked = PR_TRUE; nsCOMPtr doc(do_QueryInterface(aDoc)); - nsCOMPtr 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 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 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; diff --git a/mozilla/dom/src/base/nsGlobalWindow.h b/mozilla/dom/src/base/nsGlobalWindow.h index 5a5bc37a264..ae3e64d778f 100644 --- a/mozilla/dom/src/base/nsGlobalWindow.h +++ b/mozilla/dom/src/base/nsGlobalWindow.h @@ -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; diff --git a/mozilla/embedding/browser/activex/src/plugin/XPCDocument.cpp b/mozilla/embedding/browser/activex/src/plugin/XPCDocument.cpp index 1b926f94e59..a3204a7d31f 100644 --- a/mozilla/embedding/browser/activex/src/plugin/XPCDocument.cpp +++ b/mozilla/embedding/browser/activex/src/plugin/XPCDocument.cpp @@ -40,6 +40,7 @@ #include #include +#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 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/base/nsPresShell.cpp b/mozilla/layout/base/nsPresShell.cpp index c5b364e9de3..1c2645ca397 100644 --- a/mozilla/layout/base/nsPresShell.cpp +++ b/mozilla/layout/base/nsPresShell.cpp @@ -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. diff --git a/mozilla/layout/generic/nsObjectFrame.cpp b/mozilla/layout/generic/nsObjectFrame.cpp index 59e082201df..76002cf11dc 100644 --- a/mozilla/layout/generic/nsObjectFrame.cpp +++ b/mozilla/layout/generic/nsObjectFrame.cpp @@ -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); diff --git a/mozilla/layout/html/base/src/Makefile.in b/mozilla/layout/html/base/src/Makefile.in index 940d9191c19..30dd834283d 100644 --- a/mozilla/layout/html/base/src/Makefile.in +++ b/mozilla/layout/html/base/src/Makefile.in @@ -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) diff --git a/mozilla/layout/html/base/src/nsObjectFrame.cpp b/mozilla/layout/html/base/src/nsObjectFrame.cpp index 59e082201df..76002cf11dc 100644 --- a/mozilla/layout/html/base/src/nsObjectFrame.cpp +++ b/mozilla/layout/html/base/src/nsObjectFrame.cpp @@ -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); diff --git a/mozilla/layout/html/base/src/nsPresShell.cpp b/mozilla/layout/html/base/src/nsPresShell.cpp index c5b364e9de3..1c2645ca397 100644 --- a/mozilla/layout/html/base/src/nsPresShell.cpp +++ b/mozilla/layout/html/base/src/nsPresShell.cpp @@ -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. diff --git a/mozilla/view/src/nsViewManager.cpp b/mozilla/view/src/nsViewManager.cpp index 69e2d8d5765..1cb3d693a9c 100644 --- a/mozilla/view/src/nsViewManager.cpp +++ b/mozilla/view/src/nsViewManager.cpp @@ -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: diff --git a/mozilla/widget/public/nsGUIEvent.h b/mozilla/widget/public/nsGUIEvent.h index 97ae32be08c..bb53927e9c5 100644 --- a/mozilla/widget/public/nsGUIEvent.h +++ b/mozilla/widget/public/nsGUIEvent.h @@ -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) { }