diff --git a/dom/events/Event.cpp b/dom/events/Event.cpp index 0d5f8d8f2..5554ab5de 100644 --- a/dom/events/Event.cpp +++ b/dom/events/Event.cpp @@ -522,6 +522,14 @@ Event::PreventDefaultInternal(bool aCalledByDefaultHandler) if (!mEvent->mFlags.mCancelable) { return; } + if (mEvent->mFlags.mInPassiveListener) { +#if DEBUG + // XXX: There should be a warning here, but we don't have the string. + // https://hg.mozilla.org/mozilla-central/rev/cda76e80a47c + fprintf(stderr, "** PreventDefaultInternal called on Passive Listener\n"); +#endif + return; + } mEvent->mFlags.mDefaultPrevented = true; diff --git a/dom/events/EventListenerManager.cpp b/dom/events/EventListenerManager.cpp index f9559ee97..a818f677d 100644 --- a/dom/events/EventListenerManager.cpp +++ b/dom/events/EventListenerManager.cpp @@ -250,7 +250,7 @@ EventListenerManager::AddEventListenerInternal( listener = &mListeners.ElementAt(i); // mListener == aListenerHolder is the last one, since it can be a bit slow. if (listener->mListenerIsHandler == aHandler && - listener->mFlags == aFlags && + listener->mFlags.EqualsForAddition(aFlags) && EVENT_TYPE_EQUALS(listener, aEventMessage, aTypeAtom, aTypeString, aAllEvents) && listener->mListener == aListenerHolder) { @@ -409,7 +409,7 @@ EventListenerManager::AddEventListenerInternal( } } - if (IsApzAwareEvent(aTypeAtom)) { + if (IsApzAwareListener(listener)) { nsCOMPtr node = do_QueryInterface(mTarget); if (node) { node->SetMayHaveApzAwareListeners(); @@ -545,7 +545,7 @@ EventListenerManager::RemoveEventListenerInternal( aAllEvents)) { ++typeCount; if (listener->mListener == aListenerHolder && - listener->mFlags.EqualsIgnoringTrustness(aFlags)) { + listener->mFlags.EqualsForRemoval(aFlags)) { RefPtr kungFuDeathGrip(this); mListeners.RemoveElementAt(i); --count; @@ -1152,9 +1152,11 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext, } } + aEvent->mFlags.mInPassiveListener = listener->mFlags.mPassive; if (NS_FAILED(HandleEventSubType(listener, *aDOMEvent, aCurrentTarget))) { aEvent->mFlags.mExceptionHasBeenRisen = true; } + aEvent->mFlags.mInPassiveListener = false; if (needsEndEventMarker) { timelines->AddMarkerForDocShell( @@ -1205,9 +1207,12 @@ EventListenerManager::AddEventListener( bool aWantsUntrusted) { EventListenerFlags flags; - flags.mCapture = - aOptions.IsBoolean() ? aOptions.GetAsBoolean() - : aOptions.GetAsAddEventListenerOptions().mCapture; + if (aOptions.IsBoolean()) { + flags.mCapture = aOptions.GetAsBoolean(); + } else { + flags.mCapture = aOptions.GetAsAddEventListenerOptions().mCapture; + flags.mPassive = aOptions.GetAsAddEventListenerOptions().mPassive; + } flags.mAllowUntrustedEvents = aWantsUntrusted; return AddEventListenerByType(aListenerHolder, aType, flags); } @@ -1542,13 +1547,19 @@ EventListenerManager::HasApzAwareListeners() uint32_t count = mListeners.Length(); for (uint32_t i = 0; i < count; ++i) { Listener* listener = &mListeners.ElementAt(i); - if (IsApzAwareEvent(listener->mTypeAtom)) { + if (IsApzAwareListener(listener)) { return true; } } return false; } +bool +EventListenerManager::IsApzAwareListener(Listener* aListener) +{ + return !aListener->mFlags.mPassive && IsApzAwareEvent(aListener->mTypeAtom); +} + bool EventListenerManager::IsApzAwareEvent(nsIAtom* aEvent) { diff --git a/dom/events/EventListenerManager.h b/dom/events/EventListenerManager.h index d0653f128..6587e41d5 100644 --- a/dom/events/EventListenerManager.h +++ b/dom/events/EventListenerManager.h @@ -58,31 +58,32 @@ public: // If mAllowUntrustedEvents is true, the listener is listening to the // untrusted events too. bool mAllowUntrustedEvents : 1; + // If mPassive is true, the listener will not be calling preventDefault on the + // event. (If it does call preventDefault, we should ignore it). + bool mPassive : 1; EventListenerFlags() : mListenerIsJSListener(false), - mCapture(false), mInSystemGroup(false), mAllowUntrustedEvents(false) + mCapture(false), mInSystemGroup(false), mAllowUntrustedEvents(false), + mPassive(false) { } - bool Equals(const EventListenerFlags& aOther) const + bool EqualsForAddition(const EventListenerFlags& aOther) const { return (mCapture == aOther.mCapture && mInSystemGroup == aOther.mInSystemGroup && mListenerIsJSListener == aOther.mListenerIsJSListener && mAllowUntrustedEvents == aOther.mAllowUntrustedEvents); + // Don't compare mPassive } - bool EqualsIgnoringTrustness(const EventListenerFlags& aOther) const + bool EqualsForRemoval(const EventListenerFlags& aOther) const { return (mCapture == aOther.mCapture && mInSystemGroup == aOther.mInSystemGroup && mListenerIsJSListener == aOther.mListenerIsJSListener); - } - - bool operator==(const EventListenerFlags& aOther) const - { - return Equals(aOther); + // Don't compare mAllowUntrustedEvents or mPassive } }; @@ -444,7 +445,7 @@ public: dom::EventTarget* GetTarget() { return mTarget; } bool HasApzAwareListeners(); - + bool IsApzAwareListener(Listener* aListener); bool IsApzAwareEvent(nsIAtom* aEvent); protected: diff --git a/dom/webidl/EventTarget.webidl b/dom/webidl/EventTarget.webidl index dce46ad99..1e50effb3 100644 --- a/dom/webidl/EventTarget.webidl +++ b/dom/webidl/EventTarget.webidl @@ -16,7 +16,8 @@ dictionary EventListenerOptions { }; dictionary AddEventListenerOptions : EventListenerOptions { - // boolean passive = false; + boolean passive = false; + // XXX: this is bug 1287706 and follow-on 1367372 // boolean once = false; }; diff --git a/widget/BasicEvents.h b/widget/BasicEvents.h index 1446e11ab..166a52229 100644 --- a/widget/BasicEvents.h +++ b/widget/BasicEvents.h @@ -115,6 +115,9 @@ public: // perform its associated action. This is currently only relevant for // wheel and touch events. bool mHandledByAPZ : 1; + // True if the event is currently being handled by an event listener that + // was registered as a passive listener. + bool mInPassiveListener: 1; // If the event is being handled in target phase, returns true. inline bool InTargetPhase() const