mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1236979 part 3: If there are no listeners for a transition or animation event, check listeners again using a webkit-prefixed event name. r=smaug
This commit is contained in:
parent
52a8a877db
commit
d3dfd167cf
@ -19,7 +19,9 @@
|
||||
#include "mozilla/HalSensor.h"
|
||||
#include "mozilla/InternalMutationEvent.h"
|
||||
#include "mozilla/JSEventHandler.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
@ -95,6 +97,46 @@ MutationBitForEventType(EventMessage aEventType)
|
||||
|
||||
uint32_t EventListenerManager::sMainThreadCreatedCount = 0;
|
||||
|
||||
static bool
|
||||
IsWebkitPrefixSupportEnabled()
|
||||
{
|
||||
static bool sIsWebkitPrefixSupportEnabled;
|
||||
static bool sIsPrefCached = false;
|
||||
|
||||
if (!sIsPrefCached) {
|
||||
sIsPrefCached = true;
|
||||
Preferences::AddBoolVarCache(&sIsWebkitPrefixSupportEnabled,
|
||||
"layout.css.prefixes.webkit");
|
||||
}
|
||||
|
||||
return sIsWebkitPrefixSupportEnabled;
|
||||
}
|
||||
|
||||
// If the given EventMessage has a legacy version that we support, then this
|
||||
// function returns that legacy version. Otherwise, this function simply
|
||||
// returns the passed-in EventMessage.
|
||||
EventMessage
|
||||
GetLegacyEventMessage(EventMessage aEventMessage)
|
||||
{
|
||||
if (IsWebkitPrefixSupportEnabled()) {
|
||||
// webkit-prefixed legacy events:
|
||||
if (aEventMessage == eTransitionEnd) {
|
||||
return eWebkitTransitionEnd;
|
||||
}
|
||||
if (aEventMessage == eAnimationStart) {
|
||||
return eWebkitAnimationStart;
|
||||
}
|
||||
if (aEventMessage == eAnimationEnd) {
|
||||
return eWebkitAnimationEnd;
|
||||
}
|
||||
if (aEventMessage == eAnimationIteration) {
|
||||
return eWebkitAnimationIteration;
|
||||
}
|
||||
}
|
||||
|
||||
return aEventMessage;
|
||||
}
|
||||
|
||||
EventListenerManagerBase::EventListenerManagerBase()
|
||||
: mNoListenerForEvent(eVoidEvent)
|
||||
, mMayHavePaintEventListener(false)
|
||||
@ -603,9 +645,15 @@ EventListenerManager::RemoveEventListenerInternal(
|
||||
}
|
||||
|
||||
bool
|
||||
EventListenerManager::ListenerCanHandle(Listener* aListener,
|
||||
WidgetEvent* aEvent)
|
||||
EventListenerManager::ListenerCanHandle(const Listener* aListener,
|
||||
const WidgetEvent* aEvent,
|
||||
EventMessage aEventMessage) const
|
||||
|
||||
{
|
||||
MOZ_ASSERT(aEventMessage == aEvent->mMessage ||
|
||||
aEventMessage == GetLegacyEventMessage(aEvent->mMessage),
|
||||
"aEvent and aEventMessage should agree, modulo legacyness");
|
||||
|
||||
// This is slightly different from EVENT_TYPE_EQUALS in that it returns
|
||||
// true even when aEvent->mMessage == eUnidentifiedEvent and
|
||||
// aListener=>mEventMessage != eUnidentifiedEvent as long as the atoms are
|
||||
@ -620,7 +668,7 @@ EventListenerManager::ListenerCanHandle(Listener* aListener,
|
||||
return aListener->mTypeString.Equals(aEvent->typeString);
|
||||
}
|
||||
MOZ_ASSERT(mIsMainThreadELM);
|
||||
return aListener->mEventMessage == aEvent->mMessage;
|
||||
return aListener->mEventMessage == aEventMessage;
|
||||
}
|
||||
|
||||
void
|
||||
@ -1104,77 +1152,107 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
|
||||
aEvent->mFlags.mDefaultPrevented = true;
|
||||
}
|
||||
|
||||
nsAutoTObserverArray<Listener, 2>::EndLimitedIterator iter(mListeners);
|
||||
Maybe<nsAutoPopupStatePusher> popupStatePusher;
|
||||
if (mIsMainThreadELM) {
|
||||
popupStatePusher.emplace(Event::GetEventPopupControlState(aEvent, *aDOMEvent));
|
||||
}
|
||||
|
||||
bool hasListener = false;
|
||||
while (iter.HasMore()) {
|
||||
if (aEvent->mFlags.mImmediatePropagationStopped) {
|
||||
break;
|
||||
}
|
||||
Listener* listener = &iter.GetNext();
|
||||
// Check that the phase is same in event and event listener.
|
||||
// Handle only trusted events, except when listener permits untrusted events.
|
||||
if (ListenerCanHandle(listener, aEvent)) {
|
||||
hasListener = true;
|
||||
if (listener->IsListening(aEvent) &&
|
||||
(aEvent->mFlags.mIsTrusted ||
|
||||
listener->mFlags.mAllowUntrustedEvents)) {
|
||||
if (!*aDOMEvent) {
|
||||
// This is tiny bit slow, but happens only once per event.
|
||||
nsCOMPtr<EventTarget> et =
|
||||
do_QueryInterface(aEvent->originalTarget);
|
||||
RefPtr<Event> event = EventDispatcher::CreateEvent(et, aPresContext,
|
||||
bool usingLegacyMessage = false;
|
||||
EventMessage eventMessage = aEvent->mMessage;
|
||||
|
||||
while (true) {
|
||||
nsAutoTObserverArray<Listener, 2>::EndLimitedIterator iter(mListeners);
|
||||
Maybe<EventMessageAutoOverride> legacyAutoOverride;
|
||||
while (iter.HasMore()) {
|
||||
if (aEvent->mFlags.mImmediatePropagationStopped) {
|
||||
break;
|
||||
}
|
||||
Listener* listener = &iter.GetNext();
|
||||
// Check that the phase is same in event and event listener.
|
||||
// Handle only trusted events, except when listener permits untrusted events.
|
||||
if (ListenerCanHandle(listener, aEvent, eventMessage)) {
|
||||
hasListener = true;
|
||||
if (listener->IsListening(aEvent) &&
|
||||
(aEvent->mFlags.mIsTrusted ||
|
||||
listener->mFlags.mAllowUntrustedEvents)) {
|
||||
if (!*aDOMEvent) {
|
||||
// This is tiny bit slow, but happens only once per event.
|
||||
nsCOMPtr<EventTarget> et =
|
||||
do_QueryInterface(aEvent->originalTarget);
|
||||
RefPtr<Event> event = EventDispatcher::CreateEvent(et, aPresContext,
|
||||
aEvent,
|
||||
EmptyString());
|
||||
event.forget(aDOMEvent);
|
||||
}
|
||||
if (*aDOMEvent) {
|
||||
if (!aEvent->currentTarget) {
|
||||
aEvent->currentTarget = aCurrentTarget->GetTargetForDOMEvent();
|
||||
if (!aEvent->currentTarget) {
|
||||
break;
|
||||
}
|
||||
event.forget(aDOMEvent);
|
||||
}
|
||||
|
||||
// Maybe add a marker to the docshell's timeline, but only
|
||||
// bother with all the logic if some docshell is recording.
|
||||
nsDocShell* docShell;
|
||||
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
|
||||
bool needsEndEventMarker = false;
|
||||
|
||||
if (mIsMainThreadELM &&
|
||||
listener->mListenerType != Listener::eNativeListener) {
|
||||
nsCOMPtr<nsIDocShell> docShellComPtr = GetDocShellForTarget();
|
||||
if (docShellComPtr) {
|
||||
docShell = static_cast<nsDocShell*>(docShellComPtr.get());
|
||||
if (timelines && timelines->HasConsumer(docShell)) {
|
||||
needsEndEventMarker = true;
|
||||
nsAutoString typeStr;
|
||||
(*aDOMEvent)->GetType(typeStr);
|
||||
uint16_t phase;
|
||||
(*aDOMEvent)->GetEventPhase(&phase);
|
||||
timelines->AddMarkerForDocShell(docShell, Move(
|
||||
MakeUnique<EventTimelineMarker>(
|
||||
typeStr, phase, MarkerTracingType::START)));
|
||||
if (*aDOMEvent) {
|
||||
if (!aEvent->currentTarget) {
|
||||
aEvent->currentTarget = aCurrentTarget->GetTargetForDOMEvent();
|
||||
if (!aEvent->currentTarget) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (usingLegacyMessage && !legacyAutoOverride) {
|
||||
// Override the aDOMEvent's event-message (its .type) until we
|
||||
// finish traversing listeners (when legacyAutoOverride destructs)
|
||||
legacyAutoOverride.emplace(*aDOMEvent, eventMessage);
|
||||
}
|
||||
|
||||
if (NS_FAILED(HandleEventSubType(listener, *aDOMEvent, aCurrentTarget))) {
|
||||
aEvent->mFlags.mExceptionHasBeenRisen = true;
|
||||
}
|
||||
// Maybe add a marker to the docshell's timeline, but only
|
||||
// bother with all the logic if some docshell is recording.
|
||||
nsDocShell* docShell;
|
||||
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
|
||||
bool needsEndEventMarker = false;
|
||||
|
||||
if (needsEndEventMarker) {
|
||||
timelines->AddMarkerForDocShell(
|
||||
docShell, "DOMEvent", MarkerTracingType::END);
|
||||
if (mIsMainThreadELM &&
|
||||
listener->mListenerType != Listener::eNativeListener) {
|
||||
nsCOMPtr<nsIDocShell> docShellComPtr = GetDocShellForTarget();
|
||||
if (docShellComPtr) {
|
||||
docShell = static_cast<nsDocShell*>(docShellComPtr.get());
|
||||
if (timelines && timelines->HasConsumer(docShell)) {
|
||||
needsEndEventMarker = true;
|
||||
nsAutoString typeStr;
|
||||
(*aDOMEvent)->GetType(typeStr);
|
||||
uint16_t phase;
|
||||
(*aDOMEvent)->GetEventPhase(&phase);
|
||||
timelines->AddMarkerForDocShell(docShell, Move(
|
||||
MakeUnique<EventTimelineMarker>(
|
||||
typeStr, phase, MarkerTracingType::START)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_FAILED(HandleEventSubType(listener, *aDOMEvent, aCurrentTarget))) {
|
||||
aEvent->mFlags.mExceptionHasBeenRisen = true;
|
||||
}
|
||||
|
||||
if (needsEndEventMarker) {
|
||||
timelines->AddMarkerForDocShell(
|
||||
docShell, "DOMEvent", MarkerTracingType::END);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't find any matching listeners, and our event has a legacy
|
||||
// version, we'll now switch to looking for that legacy version and we'll
|
||||
// recheck our listeners.
|
||||
if (hasListener || usingLegacyMessage) {
|
||||
// (No need to recheck listeners, because we already found a match, or we
|
||||
// already rechecked them.)
|
||||
break;
|
||||
}
|
||||
EventMessage legacyEventMessage = GetLegacyEventMessage(eventMessage);
|
||||
if (legacyEventMessage == eventMessage) {
|
||||
break; // There's no legacy version of our event; no need to recheck.
|
||||
}
|
||||
MOZ_ASSERT(GetLegacyEventMessage(legacyEventMessage) == legacyEventMessage,
|
||||
"Legacy event messages should not themselves have legacy versions");
|
||||
|
||||
// Recheck our listeners, using the legacy event message we just looked up:
|
||||
eventMessage = legacyEventMessage;
|
||||
usingLegacyMessage = true;
|
||||
}
|
||||
|
||||
aEvent->currentTarget = nullptr;
|
||||
|
@ -571,7 +571,9 @@ protected:
|
||||
nsPIDOMWindowInner* GetInnerWindowForTarget();
|
||||
already_AddRefed<nsPIDOMWindowInner> GetTargetAsInnerWindow() const;
|
||||
|
||||
bool ListenerCanHandle(Listener* aListener, WidgetEvent* aEvent);
|
||||
bool ListenerCanHandle(const Listener* aListener,
|
||||
const WidgetEvent* aEvent,
|
||||
EventMessage aEventMessage) const;
|
||||
|
||||
// BE AWARE, a lot of instances of EventListenerManager will be created.
|
||||
// Therefor, we need to keep this class compact. When you add integer
|
||||
|
Loading…
Reference in New Issue
Block a user