#399: passive event listener support M1266066

This commit is contained in:
Cameron Kaiser 2017-12-17 20:18:13 -08:00
parent fbde989ca7
commit 034fda860a
5 changed files with 41 additions and 17 deletions

View File

@ -522,6 +522,14 @@ Event::PreventDefaultInternal(bool aCalledByDefaultHandler)
if (!mEvent->mFlags.mCancelable) { if (!mEvent->mFlags.mCancelable) {
return; 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; mEvent->mFlags.mDefaultPrevented = true;

View File

@ -250,7 +250,7 @@ EventListenerManager::AddEventListenerInternal(
listener = &mListeners.ElementAt(i); listener = &mListeners.ElementAt(i);
// mListener == aListenerHolder is the last one, since it can be a bit slow. // mListener == aListenerHolder is the last one, since it can be a bit slow.
if (listener->mListenerIsHandler == aHandler && if (listener->mListenerIsHandler == aHandler &&
listener->mFlags == aFlags && listener->mFlags.EqualsForAddition(aFlags) &&
EVENT_TYPE_EQUALS(listener, aEventMessage, aTypeAtom, aTypeString, EVENT_TYPE_EQUALS(listener, aEventMessage, aTypeAtom, aTypeString,
aAllEvents) && aAllEvents) &&
listener->mListener == aListenerHolder) { listener->mListener == aListenerHolder) {
@ -409,7 +409,7 @@ EventListenerManager::AddEventListenerInternal(
} }
} }
if (IsApzAwareEvent(aTypeAtom)) { if (IsApzAwareListener(listener)) {
nsCOMPtr<nsINode> node = do_QueryInterface(mTarget); nsCOMPtr<nsINode> node = do_QueryInterface(mTarget);
if (node) { if (node) {
node->SetMayHaveApzAwareListeners(); node->SetMayHaveApzAwareListeners();
@ -545,7 +545,7 @@ EventListenerManager::RemoveEventListenerInternal(
aAllEvents)) { aAllEvents)) {
++typeCount; ++typeCount;
if (listener->mListener == aListenerHolder && if (listener->mListener == aListenerHolder &&
listener->mFlags.EqualsIgnoringTrustness(aFlags)) { listener->mFlags.EqualsForRemoval(aFlags)) {
RefPtr<EventListenerManager> kungFuDeathGrip(this); RefPtr<EventListenerManager> kungFuDeathGrip(this);
mListeners.RemoveElementAt(i); mListeners.RemoveElementAt(i);
--count; --count;
@ -1152,9 +1152,11 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
} }
} }
aEvent->mFlags.mInPassiveListener = listener->mFlags.mPassive;
if (NS_FAILED(HandleEventSubType(listener, *aDOMEvent, aCurrentTarget))) { if (NS_FAILED(HandleEventSubType(listener, *aDOMEvent, aCurrentTarget))) {
aEvent->mFlags.mExceptionHasBeenRisen = true; aEvent->mFlags.mExceptionHasBeenRisen = true;
} }
aEvent->mFlags.mInPassiveListener = false;
if (needsEndEventMarker) { if (needsEndEventMarker) {
timelines->AddMarkerForDocShell( timelines->AddMarkerForDocShell(
@ -1205,9 +1207,12 @@ EventListenerManager::AddEventListener(
bool aWantsUntrusted) bool aWantsUntrusted)
{ {
EventListenerFlags flags; EventListenerFlags flags;
flags.mCapture = if (aOptions.IsBoolean()) {
aOptions.IsBoolean() ? aOptions.GetAsBoolean() flags.mCapture = aOptions.GetAsBoolean();
: aOptions.GetAsAddEventListenerOptions().mCapture; } else {
flags.mCapture = aOptions.GetAsAddEventListenerOptions().mCapture;
flags.mPassive = aOptions.GetAsAddEventListenerOptions().mPassive;
}
flags.mAllowUntrustedEvents = aWantsUntrusted; flags.mAllowUntrustedEvents = aWantsUntrusted;
return AddEventListenerByType(aListenerHolder, aType, flags); return AddEventListenerByType(aListenerHolder, aType, flags);
} }
@ -1542,13 +1547,19 @@ EventListenerManager::HasApzAwareListeners()
uint32_t count = mListeners.Length(); uint32_t count = mListeners.Length();
for (uint32_t i = 0; i < count; ++i) { for (uint32_t i = 0; i < count; ++i) {
Listener* listener = &mListeners.ElementAt(i); Listener* listener = &mListeners.ElementAt(i);
if (IsApzAwareEvent(listener->mTypeAtom)) { if (IsApzAwareListener(listener)) {
return true; return true;
} }
} }
return false; return false;
} }
bool
EventListenerManager::IsApzAwareListener(Listener* aListener)
{
return !aListener->mFlags.mPassive && IsApzAwareEvent(aListener->mTypeAtom);
}
bool bool
EventListenerManager::IsApzAwareEvent(nsIAtom* aEvent) EventListenerManager::IsApzAwareEvent(nsIAtom* aEvent)
{ {

View File

@ -58,31 +58,32 @@ public:
// If mAllowUntrustedEvents is true, the listener is listening to the // If mAllowUntrustedEvents is true, the listener is listening to the
// untrusted events too. // untrusted events too.
bool mAllowUntrustedEvents : 1; 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() : EventListenerFlags() :
mListenerIsJSListener(false), 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 && return (mCapture == aOther.mCapture &&
mInSystemGroup == aOther.mInSystemGroup && mInSystemGroup == aOther.mInSystemGroup &&
mListenerIsJSListener == aOther.mListenerIsJSListener && mListenerIsJSListener == aOther.mListenerIsJSListener &&
mAllowUntrustedEvents == aOther.mAllowUntrustedEvents); mAllowUntrustedEvents == aOther.mAllowUntrustedEvents);
// Don't compare mPassive
} }
bool EqualsIgnoringTrustness(const EventListenerFlags& aOther) const bool EqualsForRemoval(const EventListenerFlags& aOther) const
{ {
return (mCapture == aOther.mCapture && return (mCapture == aOther.mCapture &&
mInSystemGroup == aOther.mInSystemGroup && mInSystemGroup == aOther.mInSystemGroup &&
mListenerIsJSListener == aOther.mListenerIsJSListener); mListenerIsJSListener == aOther.mListenerIsJSListener);
} // Don't compare mAllowUntrustedEvents or mPassive
bool operator==(const EventListenerFlags& aOther) const
{
return Equals(aOther);
} }
}; };
@ -444,7 +445,7 @@ public:
dom::EventTarget* GetTarget() { return mTarget; } dom::EventTarget* GetTarget() { return mTarget; }
bool HasApzAwareListeners(); bool HasApzAwareListeners();
bool IsApzAwareListener(Listener* aListener);
bool IsApzAwareEvent(nsIAtom* aEvent); bool IsApzAwareEvent(nsIAtom* aEvent);
protected: protected:

View File

@ -16,7 +16,8 @@ dictionary EventListenerOptions {
}; };
dictionary AddEventListenerOptions : EventListenerOptions { dictionary AddEventListenerOptions : EventListenerOptions {
// boolean passive = false; boolean passive = false;
// XXX: this is bug 1287706 and follow-on 1367372
// boolean once = false; // boolean once = false;
}; };

View File

@ -115,6 +115,9 @@ public:
// perform its associated action. This is currently only relevant for // perform its associated action. This is currently only relevant for
// wheel and touch events. // wheel and touch events.
bool mHandledByAPZ : 1; 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. // If the event is being handled in target phase, returns true.
inline bool InTargetPhase() const inline bool InTargetPhase() const