summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dom/archivereader/ArchiveRequest.cpp2
-rw-r--r--dom/archivereader/ArchiveRequest.h3
-rw-r--r--dom/base/Attr.cpp2
-rw-r--r--dom/base/Attr.h2
-rw-r--r--dom/base/Element.cpp7
-rw-r--r--dom/base/Element.h2
-rw-r--r--dom/base/FragmentOrElement.cpp2
-rw-r--r--dom/base/nsDocument.cpp2
-rw-r--r--dom/base/nsDocument.h2
-rw-r--r--dom/base/nsGenConImageContent.cpp4
-rw-r--r--dom/base/nsGlobalWindow.cpp7
-rw-r--r--dom/base/nsIContent.h2
-rw-r--r--dom/base/nsINode.cpp2
-rw-r--r--dom/base/nsInProcessTabChildGlobal.cpp4
-rw-r--r--dom/base/nsInProcessTabChildGlobal.h4
-rw-r--r--dom/base/nsWindowRoot.cpp2
-rw-r--r--dom/events/DOMEventTargetHelper.cpp2
-rw-r--r--dom/events/DOMEventTargetHelper.h4
-rw-r--r--dom/events/EventDispatcher.cpp256
-rw-r--r--dom/events/EventDispatcher.h24
-rw-r--r--dom/events/test/mochitest.ini1
-rw-r--r--dom/events/test/test_bug1305458.html50
-rw-r--r--dom/html/HTMLAnchorElement.cpp4
-rw-r--r--dom/html/HTMLAnchorElement.h3
-rw-r--r--dom/html/HTMLAreaElement.cpp4
-rw-r--r--dom/html/HTMLAreaElement.h3
-rw-r--r--dom/html/HTMLButtonElement.cpp4
-rw-r--r--dom/html/HTMLButtonElement.h3
-rw-r--r--dom/html/HTMLCanvasElement.cpp4
-rw-r--r--dom/html/HTMLCanvasElement.h3
-rw-r--r--dom/html/HTMLFieldSetElement.cpp4
-rw-r--r--dom/html/HTMLFieldSetElement.h3
-rw-r--r--dom/html/HTMLFormElement.cpp4
-rw-r--r--dom/html/HTMLFormElement.h3
-rw-r--r--dom/html/HTMLImageElement.cpp4
-rw-r--r--dom/html/HTMLImageElement.h3
-rw-r--r--dom/html/HTMLInputElement.cpp90
-rw-r--r--dom/html/HTMLInputElement.h4
-rw-r--r--dom/html/HTMLLinkElement.cpp4
-rw-r--r--dom/html/HTMLLinkElement.h3
-rw-r--r--dom/html/HTMLMenuItemElement.cpp4
-rw-r--r--dom/html/HTMLMenuItemElement.h3
-rw-r--r--dom/html/HTMLOptGroupElement.cpp4
-rw-r--r--dom/html/HTMLOptGroupElement.h3
-rw-r--r--dom/html/HTMLSelectElement.cpp4
-rw-r--r--dom/html/HTMLSelectElement.h3
-rw-r--r--dom/html/HTMLTextAreaElement.cpp17
-rw-r--r--dom/html/HTMLTextAreaElement.h4
-rw-r--r--dom/html/nsGenericHTMLElement.cpp21
-rw-r--r--dom/html/nsGenericHTMLElement.h9
-rw-r--r--dom/indexedDB/IDBFileHandle.cpp2
-rw-r--r--dom/indexedDB/IDBFileHandle.h2
-rw-r--r--dom/indexedDB/IDBFileRequest.cpp2
-rw-r--r--dom/indexedDB/IDBFileRequest.h2
-rw-r--r--dom/indexedDB/IDBRequest.cpp2
-rw-r--r--dom/indexedDB/IDBRequest.h2
-rw-r--r--dom/indexedDB/IDBTransaction.cpp2
-rw-r--r--dom/indexedDB/IDBTransaction.h2
-rw-r--r--dom/interfaces/events/nsIDOMEventTarget.idl15
-rw-r--r--dom/ipc/TabChild.h2
-rw-r--r--dom/mathml/nsMathMLElement.cpp6
-rw-r--r--dom/mathml/nsMathMLElement.h2
-rw-r--r--dom/svg/SVGAElement.cpp6
-rw-r--r--dom/svg/SVGAElement.h3
-rw-r--r--dom/svg/SVGSVGElement.cpp4
-rw-r--r--dom/svg/SVGSVGElement.h3
-rw-r--r--dom/workers/SharedWorker.cpp4
-rw-r--r--dom/workers/SharedWorker.h2
-rw-r--r--dom/xul/nsXULElement.cpp124
-rw-r--r--dom/xul/nsXULElement.h10
70 files changed, 547 insertions, 258 deletions
diff --git a/dom/archivereader/ArchiveRequest.cpp b/dom/archivereader/ArchiveRequest.cpp
index ec1686804..c4b19f56b 100644
--- a/dom/archivereader/ArchiveRequest.cpp
+++ b/dom/archivereader/ArchiveRequest.cpp
@@ -69,7 +69,7 @@ ArchiveRequest::~ArchiveRequest()
}
nsresult
-ArchiveRequest::PreHandleEvent(EventChainPreVisitor& aVisitor)
+ArchiveRequest::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = true;
aVisitor.mParentTarget = nullptr;
diff --git a/dom/archivereader/ArchiveRequest.h b/dom/archivereader/ArchiveRequest.h
index 3988f1aa1..3081a3e42 100644
--- a/dom/archivereader/ArchiveRequest.h
+++ b/dom/archivereader/ArchiveRequest.h
@@ -38,7 +38,8 @@ public:
ArchiveReader* aReader);
// nsIDOMEventTarget
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
public:
// This is called by the DOMArchiveRequestEvent
diff --git a/dom/base/Attr.cpp b/dom/base/Attr.cpp
index 71b559392..df05ef5cb 100644
--- a/dom/base/Attr.cpp
+++ b/dom/base/Attr.cpp
@@ -344,7 +344,7 @@ Attr::RemoveChildAt(uint32_t aIndex, bool aNotify)
}
nsresult
-Attr::PreHandleEvent(EventChainPreVisitor& aVisitor)
+Attr::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = true;
return NS_OK;
diff --git a/dom/base/Attr.h b/dom/base/Attr.h
index 3f80030d2..39ac8b195 100644
--- a/dom/base/Attr.h
+++ b/dom/base/Attr.h
@@ -54,7 +54,7 @@ public:
// nsIDOMAttr interface
NS_DECL_NSIDOMATTR
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
// nsIAttribute interface
void SetMap(nsDOMAttributeMap *aMap) override;
diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp
index c8467e036..5a92853ae 100644
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -3129,7 +3129,7 @@ Element::CheckHandleEventForLinksPrecondition(EventChainVisitor& aVisitor,
}
nsresult
-Element::PreHandleEventForLinks(EventChainPreVisitor& aVisitor)
+Element::GetEventTargetParentForLinks(EventChainPreVisitor& aVisitor)
{
// Optimisation: return early if this event doesn't interest us.
// IMPORTANT: this switch and the switch below it must be kept in sync!
@@ -3151,8 +3151,9 @@ Element::PreHandleEventForLinks(EventChainPreVisitor& aVisitor)
nsresult rv = NS_OK;
- // We do the status bar updates in PreHandleEvent so that the status bar gets
- // updated even if the event is consumed before we have a chance to set it.
+ // We do the status bar updates in GetEventTargetParent so that the status bar
+ // gets updated even if the event is consumed before we have a chance to set
+ // it.
switch (aVisitor.mEvent->mMessage) {
// Set the status bar similarly for mouseover and focus
case eMouseOver:
diff --git a/dom/base/Element.h b/dom/base/Element.h
index 782004703..0104d795c 100644
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -1400,7 +1400,7 @@ protected:
/**
* Handle status bar updates before they can be cancelled.
*/
- nsresult PreHandleEventForLinks(EventChainPreVisitor& aVisitor);
+ nsresult GetEventTargetParentForLinks(EventChainPreVisitor& aVisitor);
/**
* Handle default actions for link event if the event isn't consumed yet.
diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp
index 526c3c9d4..ca00a49a5 100644
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -718,7 +718,7 @@ FindChromeAccessOnlySubtreeOwner(nsIContent* aContent)
}
nsresult
-nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
+nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
//FIXME! Document how this event retargeting works, Bug 329124.
aVisitor.mCanHandle = true;
diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
index b05bf827b..45c80ca7f 100644
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -7712,7 +7712,7 @@ nsDocument::GetExistingListenerManager() const
}
nsresult
-nsDocument::PreHandleEvent(EventChainPreVisitor& aVisitor)
+nsDocument::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = true;
// FIXME! This is a hack to make middle mouse paste working also in Editor.
diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h
index 90e511dcb..79b7f18f4 100644
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -810,7 +810,7 @@ public:
NS_DECL_NSIDOMDOCUMENTXBL
// nsIDOMEventTarget
- virtual nsresult PreHandleEvent(
+ virtual nsresult GetEventTargetParent(
mozilla::EventChainPreVisitor& aVisitor) override;
virtual mozilla::EventListenerManager*
GetOrCreateListenerManager() override;
diff --git a/dom/base/nsGenConImageContent.cpp b/dom/base/nsGenConImageContent.cpp
index e1b1f5a17..af3b186bd 100644
--- a/dom/base/nsGenConImageContent.cpp
+++ b/dom/base/nsGenConImageContent.cpp
@@ -46,7 +46,7 @@ public:
virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
virtual EventStates IntrinsicState() const override;
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override
+ virtual nsresult GetEventTargetParent(EventChainPreVisitor& aVisitor) override
{
MOZ_ASSERT(IsInNativeAnonymousSubtree());
if (aVisitor.mEvent->mMessage == eLoad ||
@@ -54,7 +54,7 @@ public:
// Don't propagate the events to the parent.
return NS_OK;
}
- return nsXMLElement::PreHandleEvent(aVisitor);
+ return nsXMLElement::GetEventTargetParent(aVisitor);
}
private:
diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp
index c965d5b97..802b44f38 100644
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -3577,9 +3577,10 @@ nsGlobalWindow::WillHandleEvent(EventChainPostVisitor& aVisitor)
}
nsresult
-nsGlobalWindow::PreHandleEvent(EventChainPreVisitor& aVisitor)
+nsGlobalWindow::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
- NS_PRECONDITION(IsInnerWindow(), "PreHandleEvent is used on outer window!?");
+ NS_PRECONDITION(IsInnerWindow(),
+ "GetEventTargetParent is used on outer window!?");
EventMessage msg = aVisitor.mEvent->mMessage;
aVisitor.mCanHandle = true;
@@ -3812,7 +3813,7 @@ nsGlobalWindow::PostHandleEvent(EventChainPostVisitor& aVisitor)
} else if (aVisitor.mEvent->mMessage == eLoad &&
aVisitor.mEvent->IsTrusted()) {
// This is page load event since load events don't propagate to |window|.
- // @see nsDocument::PreHandleEvent.
+ // @see nsDocument::GetEventTargetParent.
mIsDocumentLoaded = true;
nsCOMPtr<Element> element = GetOuterWindow()->GetFrameElementInternal();
diff --git a/dom/base/nsIContent.h b/dom/base/nsIContent.h
index dcdc632b4..e179d6ebc 100644
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -947,7 +947,7 @@ public:
// Overloaded from nsINode
virtual already_AddRefed<nsIURI> GetBaseURI(bool aTryUseXHRDocBaseURI = false) const override;
- virtual nsresult PreHandleEvent(
+ virtual nsresult GetEventTargetParent(
mozilla::EventChainPreVisitor& aVisitor) override;
virtual bool IsPurple() = 0;
diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp
index 212110b72..0b56f519d 100644
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -1243,7 +1243,7 @@ nsINode::RemoveEventListener(const nsAString& aType,
NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsINode)
nsresult
-nsINode::PreHandleEvent(EventChainPreVisitor& aVisitor)
+nsINode::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
// This is only here so that we can use the NS_DECL_NSIDOMTARGET macro
NS_ABORT();
diff --git a/dom/base/nsInProcessTabChildGlobal.cpp b/dom/base/nsInProcessTabChildGlobal.cpp
index 10ccf4aec..547bb8d36 100644
--- a/dom/base/nsInProcessTabChildGlobal.cpp
+++ b/dom/base/nsInProcessTabChildGlobal.cpp
@@ -97,7 +97,7 @@ nsInProcessTabChildGlobal::nsInProcessTabChildGlobal(nsIDocShell* aShell,
mozilla::HoldJSObjects(this);
// If owner corresponds to an <iframe mozbrowser> or <iframe mozapp>, we'll
- // have to tweak our PreHandleEvent implementation.
+ // GetEventTargetParent implementation.
nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwner);
if (browserFrame) {
mIsBrowserOrAppFrame = browserFrame->GetReallyIsBrowserOrApp();
@@ -251,7 +251,7 @@ nsInProcessTabChildGlobal::GetOwnerContent()
}
nsresult
-nsInProcessTabChildGlobal::PreHandleEvent(EventChainPreVisitor& aVisitor)
+nsInProcessTabChildGlobal::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mForceContentDispatch = true;
aVisitor.mCanHandle = true;
diff --git a/dom/base/nsInProcessTabChildGlobal.h b/dom/base/nsInProcessTabChildGlobal.h
index e7dd9cb5a..55ffc5965 100644
--- a/dom/base/nsInProcessTabChildGlobal.h
+++ b/dom/base/nsInProcessTabChildGlobal.h
@@ -96,7 +96,7 @@ public:
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal) override;
- virtual nsresult PreHandleEvent(
+ virtual nsresult GetEventTargetParent(
mozilla::EventChainPreVisitor& aVisitor) override;
NS_IMETHOD AddEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
@@ -168,7 +168,7 @@ protected:
// Is this the message manager for an in-process <iframe mozbrowser> or
// <iframe mozapp>? This affects where events get sent, so it affects
- // PreHandleEvent.
+ // GetEventTargetParent.
bool mIsBrowserOrAppFrame;
bool mPreventEventsEscaping;
diff --git a/dom/base/nsWindowRoot.cpp b/dom/base/nsWindowRoot.cpp
index b839a0ee5..b629ab86f 100644
--- a/dom/base/nsWindowRoot.cpp
+++ b/dom/base/nsWindowRoot.cpp
@@ -180,7 +180,7 @@ nsWindowRoot::GetContextForEventHandlers(nsresult* aRv)
}
nsresult
-nsWindowRoot::PreHandleEvent(EventChainPreVisitor& aVisitor)
+nsWindowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = true;
aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119
diff --git a/dom/events/DOMEventTargetHelper.cpp b/dom/events/DOMEventTargetHelper.cpp
index dd9a01d8d..ee03463ef 100644
--- a/dom/events/DOMEventTargetHelper.cpp
+++ b/dom/events/DOMEventTargetHelper.cpp
@@ -328,7 +328,7 @@ DOMEventTargetHelper::GetEventHandler(nsIAtom* aType,
}
nsresult
-DOMEventTargetHelper::PreHandleEvent(EventChainPreVisitor& aVisitor)
+DOMEventTargetHelper::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = true;
aVisitor.mParentTarget = nullptr;
diff --git a/dom/events/DOMEventTargetHelper.h b/dom/events/DOMEventTargetHelper.h
index c5a0611c9..b14f05428 100644
--- a/dom/events/DOMEventTargetHelper.h
+++ b/dom/events/DOMEventTargetHelper.h
@@ -248,10 +248,10 @@ NS_DEFINE_STATIC_IID_ACCESSOR(DOMEventTargetHelper,
/* Use this macro to declare functions that forward the behavior of this
* interface to another object.
- * This macro doesn't forward PreHandleEvent because sometimes subclasses
+ * This macro doesn't forward GetEventTargetParent because sometimes subclasses
* want to override it.
*/
-#define NS_FORWARD_NSIDOMEVENTTARGET_NOPREHANDLEEVENT(_to) \
+#define NS_FORWARD_NSIDOMEVENTTARGET_NOGETEVENTTARGETPARENT(_to) \
NS_IMETHOD AddEventListener(const nsAString & type, nsIDOMEventListener *listener, bool useCapture, bool wantsUntrusted, uint8_t _argc) { \
return _to AddEventListener(type, listener, useCapture, wantsUntrusted, _argc); \
} \
diff --git a/dom/events/EventDispatcher.cpp b/dom/events/EventDispatcher.cpp
index 1d4dfd7d9..740e611e4 100644
--- a/dom/events/EventDispatcher.cpp
+++ b/dom/events/EventDispatcher.cpp
@@ -130,13 +130,6 @@ static bool IsEventTargetChrome(EventTarget* aEventTarget,
return isChrome;
}
-
-#define NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH (1 << 0)
-#define NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT (1 << 1)
-#define NS_TARGET_CHAIN_MAY_HAVE_MANAGER (1 << 2)
-#define NS_TARGET_CHAIN_CHECKED_IF_CHROME (1 << 3)
-#define NS_TARGET_CHAIN_IS_CHROME_CONTENT (1 << 4)
-
// EventTargetChainItem represents a single item in the event target chain.
class EventTargetChainItem
{
@@ -144,8 +137,7 @@ private:
explicit EventTargetChainItem(EventTarget* aTarget);
public:
EventTargetChainItem()
- : mFlags(0)
- , mItemFlags(0)
+ : mItemFlags(0)
{
}
@@ -153,7 +145,8 @@ public:
EventTarget* aTarget,
EventTargetChainItem* aChild = nullptr)
{
- MOZ_ASSERT(!aChild || &aChain.ElementAt(aChain.Length() - 1) == aChild);
+ // The last item which can handle the event must be aChild.
+ MOZ_ASSERT(GetLastCanHandleEventTarget(aChain) == aChild);
return new (aChain.AppendElement()) EventTargetChainItem(aTarget);
}
@@ -165,6 +158,38 @@ public:
aChain.RemoveElementAt(lastIndex);
}
+ static EventTargetChainItem* GetFirstCanHandleEventTarget(
+ nsTArray<EventTargetChainItem>& aChain)
+ {
+ return &aChain[GetFirstCanHandleEventTargetIdx(aChain)];
+ }
+
+ static uint32_t GetFirstCanHandleEventTargetIdx(nsTArray<EventTargetChainItem>& aChain)
+ {
+ // aChain[i].PreHandleEventOnly() = true only when the target element wants
+ // PreHandleEvent and set mCanHandle=false. So we find the first element
+ // which can handle the event.
+ for (uint32_t i = 0; i < aChain.Length(); ++i) {
+ if (!aChain[i].PreHandleEventOnly()) {
+ return i;
+ }
+ }
+ MOZ_ASSERT(false);
+ return 0;
+ }
+
+ static EventTargetChainItem* GetLastCanHandleEventTarget(
+ nsTArray<EventTargetChainItem>& aChain)
+ {
+ // Fine the last item which can handle the event.
+ for (int32_t i = aChain.Length() - 1; i >= 0; --i) {
+ if (!aChain[i].PreHandleEventOnly()) {
+ return &aChain[i];
+ }
+ }
+ return nullptr;
+ }
+
bool IsValid()
{
NS_WARNING_ASSERTION(!!(mTarget), "Event target is not valid!");
@@ -183,44 +208,52 @@ public:
void SetForceContentDispatch(bool aForce)
{
- if (aForce) {
- mFlags |= NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH;
- } else {
- mFlags &= ~NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH;
- }
+ mFlags.mForceContentDispatch = aForce;
}
bool ForceContentDispatch()
{
- return !!(mFlags & NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH);
+ return mFlags.mForceContentDispatch;
}
void SetWantsWillHandleEvent(bool aWants)
{
- if (aWants) {
- mFlags |= NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT;
- } else {
- mFlags &= ~NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT;
- }
+ mFlags.mWantsWillHandleEvent = aWants;
}
bool WantsWillHandleEvent()
{
- return !!(mFlags & NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT);
+ return mFlags.mWantsWillHandleEvent;
+ }
+
+ void SetWantsPreHandleEvent(bool aWants)
+ {
+ mFlags.mWantsPreHandleEvent = aWants;
+ }
+
+ bool WantsPreHandleEvent()
+ {
+ return mFlags.mWantsPreHandleEvent;
+ }
+
+ void SetPreHandleEventOnly(bool aWants)
+ {
+ mFlags.mPreHandleEventOnly = aWants;
+ }
+
+ bool PreHandleEventOnly()
+ {
+ return mFlags.mPreHandleEventOnly;
}
void SetMayHaveListenerManager(bool aMayHave)
{
- if (aMayHave) {
- mFlags |= NS_TARGET_CHAIN_MAY_HAVE_MANAGER;
- } else {
- mFlags &= ~NS_TARGET_CHAIN_MAY_HAVE_MANAGER;
- }
+ mFlags.mMayHaveManager = aMayHave;
}
bool MayHaveListenerManager()
{
- return !!(mFlags & NS_TARGET_CHAIN_MAY_HAVE_MANAGER);
+ return mFlags.mMayHaveManager;
}
EventTarget* CurrentTarget()
@@ -240,10 +273,15 @@ public:
ELMCreationDetector& aCd);
/**
- * Resets aVisitor object and calls PreHandleEvent.
+ * Resets aVisitor object and calls GetEventTargetParent.
* Copies mItemFlags and mItemData to the current EventTargetChainItem.
*/
- void PreHandleEvent(EventChainPreVisitor& aVisitor);
+ void GetEventTargetParent(EventChainPreVisitor& aVisitor);
+
+ /**
+ * Calls PreHandleEvent for those items which called SetWantsPreHandleEvent.
+ */
+ void PreHandleEvent(EventChainVisitor& aVisitor);
/**
* If the current item in the event target chain has an event listener
@@ -288,7 +326,34 @@ public:
private:
nsCOMPtr<EventTarget> mTarget;
- uint16_t mFlags;
+
+ class EventTargetChainFlags
+ {
+ public:
+ explicit EventTargetChainFlags()
+ {
+ SetRawFlags(0);
+ }
+ // Cached flags for each EventTargetChainItem which are set when calling
+ // GetEventTargetParent to create event target chain. They are used to
+ // manage or speedup event dispatching.
+ bool mForceContentDispatch : 1;
+ bool mWantsWillHandleEvent : 1;
+ bool mMayHaveManager : 1;
+ bool mChechedIfChrome : 1;
+ bool mIsChromeContent : 1;
+ bool mWantsPreHandleEvent : 1;
+ bool mPreHandleEventOnly : 1;
+ private:
+ typedef uint32_t RawFlags;
+ void SetRawFlags(RawFlags aRawFlags)
+ {
+ static_assert(sizeof(EventTargetChainFlags) <= sizeof(RawFlags),
+ "EventTargetChainFlags must not be bigger than the RawFlags");
+ memcpy(this, &aRawFlags, sizeof(EventTargetChainFlags));
+ }
+ } mFlags;
+
uint16_t mItemFlags;
nsCOMPtr<nsISupports> mItemData;
// Event retargeting must happen whenever mNewTarget is non-null.
@@ -298,37 +363,49 @@ private:
bool IsCurrentTargetChrome()
{
- if (!(mFlags & NS_TARGET_CHAIN_CHECKED_IF_CHROME)) {
- mFlags |= NS_TARGET_CHAIN_CHECKED_IF_CHROME;
+ if (!mFlags.mChechedIfChrome) {
+ mFlags.mChechedIfChrome = true;
if (IsEventTargetChrome(mTarget)) {
- mFlags |= NS_TARGET_CHAIN_IS_CHROME_CONTENT;
+ mFlags.mIsChromeContent = true;
}
}
- return !!(mFlags & NS_TARGET_CHAIN_IS_CHROME_CONTENT);
+ return mFlags.mIsChromeContent;
}
};
EventTargetChainItem::EventTargetChainItem(EventTarget* aTarget)
: mTarget(aTarget)
- , mFlags(0)
, mItemFlags(0)
{
MOZ_ASSERT(!aTarget || mTarget == aTarget->GetTargetForEventTargetChain());
}
void
-EventTargetChainItem::PreHandleEvent(EventChainPreVisitor& aVisitor)
+EventTargetChainItem::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.Reset();
- Unused << mTarget->PreHandleEvent(aVisitor);
+ Unused << mTarget->GetEventTargetParent(aVisitor);
SetForceContentDispatch(aVisitor.mForceContentDispatch);
SetWantsWillHandleEvent(aVisitor.mWantsWillHandleEvent);
SetMayHaveListenerManager(aVisitor.mMayHaveListenerManager);
+ SetWantsPreHandleEvent(aVisitor.mWantsPreHandleEvent);
+ SetPreHandleEventOnly(aVisitor.mWantsPreHandleEvent && !aVisitor.mCanHandle);
mItemFlags = aVisitor.mItemFlags;
mItemData = aVisitor.mItemData;
}
void
+EventTargetChainItem::PreHandleEvent(EventChainVisitor& aVisitor)
+{
+ if (!WantsPreHandleEvent()) {
+ return;
+ }
+ aVisitor.mItemFlags = mItemFlags;
+ aVisitor.mItemData = mItemData;
+ Unused << mTarget->PreHandleEvent(aVisitor);
+}
+
+void
EventTargetChainItem::PostHandleEvent(EventChainPostVisitor& aVisitor)
{
aVisitor.mItemFlags = mItemFlags;
@@ -346,12 +423,17 @@ EventTargetChainItem::HandleEventTargetChain(
// Save the target so that it can be restored later.
nsCOMPtr<EventTarget> firstTarget = aVisitor.mEvent->mTarget;
uint32_t chainLength = aChain.Length();
+ uint32_t firstCanHandleEventTargetIdx =
+ EventTargetChainItem::GetFirstCanHandleEventTargetIdx(aChain);
// Capture
aVisitor.mEvent->mFlags.mInCapturePhase = true;
aVisitor.mEvent->mFlags.mInBubblingPhase = false;
- for (uint32_t i = chainLength - 1; i > 0; --i) {
+ for (uint32_t i = chainLength - 1; i > firstCanHandleEventTargetIdx; --i) {
EventTargetChainItem& item = aChain[i];
+ if (item.PreHandleEventOnly()) {
+ continue;
+ }
if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
item.ForceContentDispatch()) &&
!aVisitor.mEvent->PropagationStopped()) {
@@ -373,7 +455,7 @@ EventTargetChainItem::HandleEventTargetChain(
// Target
aVisitor.mEvent->mFlags.mInBubblingPhase = true;
- EventTargetChainItem& targetItem = aChain[0];
+ EventTargetChainItem& targetItem = aChain[firstCanHandleEventTargetIdx];
if (!aVisitor.mEvent->PropagationStopped() &&
(!aVisitor.mEvent->mFlags.mNoContentDispatch ||
targetItem.ForceContentDispatch())) {
@@ -385,8 +467,11 @@ EventTargetChainItem::HandleEventTargetChain(
// Bubble
aVisitor.mEvent->mFlags.mInCapturePhase = false;
- for (uint32_t i = 1; i < chainLength; ++i) {
+ for (uint32_t i = firstCanHandleEventTargetIdx + 1; i < chainLength; ++i) {
EventTargetChainItem& item = aChain[i];
+ if (item.PreHandleEventOnly()) {
+ continue;
+ }
EventTarget* newTarget = item.GetNewTarget();
if (newTarget) {
// Item is at anonymous boundary. Need to retarget for the current item
@@ -471,6 +556,28 @@ EventTargetChainItemForChromeTarget(nsTArray<EventTargetChainItem>& aChain,
return etci;
}
+/* static */ EventTargetChainItem*
+MayRetargetToChromeIfCanNotHandleEvent(
+ nsTArray<EventTargetChainItem>& aChain, EventChainPreVisitor& aPreVisitor,
+ EventTargetChainItem* aTargetEtci, EventTargetChainItem* aChildEtci,
+ nsINode* aContent)
+{
+ if (!aPreVisitor.mWantsPreHandleEvent) {
+ // Keep EventTargetChainItem if we need to call PreHandleEvent on it.
+ EventTargetChainItem::DestroyLast(aChain, aTargetEtci);
+ }
+ if (aPreVisitor.mAutomaticChromeDispatch && aContent) {
+ // Event target couldn't handle the event. Try to propagate to chrome.
+ EventTargetChainItem* chromeTargetEtci =
+ EventTargetChainItemForChromeTarget(aChain, aContent, aChildEtci);
+ if (chromeTargetEtci) {
+ chromeTargetEtci->GetEventTargetParent(aPreVisitor);
+ return chromeTargetEtci;
+ }
+ }
+ return nullptr;
+}
+
/* static */ nsresult
EventDispatcher::Dispatch(nsISupports* aTarget,
nsPresContext* aPresContext,
@@ -593,7 +700,6 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
// Create the event target chain item for the event target.
EventTargetChainItem* targetEtci =
EventTargetChainItem::Create(chain, target->GetTargetForEventTargetChain());
- MOZ_ASSERT(&chain[0] == targetEtci);
if (!targetEtci->IsValid()) {
EventTargetChainItem::DestroyLast(chain, targetEtci);
return NS_ERROR_FAILURE;
@@ -631,21 +737,24 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
aEvent->mFlags.mIsBeingDispatched = true;
// Create visitor object and start event dispatching.
- // PreHandleEvent for the original target.
+ // GetEventTargetParent for the original target.
nsEventStatus status = aEventStatus ? *aEventStatus : nsEventStatus_eIgnore;
EventChainPreVisitor preVisitor(aPresContext, aEvent, aDOMEvent, status,
isInAnon);
- targetEtci->PreHandleEvent(preVisitor);
-
- if (!preVisitor.mCanHandle && preVisitor.mAutomaticChromeDispatch && content) {
- // Event target couldn't handle the event. Try to propagate to chrome.
- EventTargetChainItem::DestroyLast(chain, targetEtci);
- targetEtci = EventTargetChainItemForChromeTarget(chain, content);
- NS_ENSURE_STATE(targetEtci);
- MOZ_ASSERT(&chain[0] == targetEtci);
- targetEtci->PreHandleEvent(preVisitor);
- }
- if (preVisitor.mCanHandle) {
+ targetEtci->GetEventTargetParent(preVisitor);
+
+ if (!preVisitor.mCanHandle) {
+ targetEtci = MayRetargetToChromeIfCanNotHandleEvent(chain, preVisitor,
+ targetEtci, nullptr,
+ content);
+ }
+ if (!preVisitor.mCanHandle) {
+ // The original target and chrome target (mAutomaticChromeDispatch=true)
+ // can not handle the event but we still have to call their PreHandleEvent.
+ for (uint32_t i = 0; i < chain.Length(); ++i) {
+ chain[i].PreHandleEvent(preVisitor);
+ }
+ } else {
// At least the original target can handle the event.
// Setting the retarget to the |target| simplifies retargeting code.
nsCOMPtr<EventTarget> t = do_QueryInterface(aEvent->mTarget);
@@ -670,29 +779,22 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
parentEtci->SetNewTarget(preVisitor.mEventTargetAtParent);
}
- parentEtci->PreHandleEvent(preVisitor);
+ parentEtci->GetEventTargetParent(preVisitor);
if (preVisitor.mCanHandle) {
topEtci = parentEtci;
} else {
- EventTargetChainItem::DestroyLast(chain, parentEtci);
- parentEtci = nullptr;
- if (preVisitor.mAutomaticChromeDispatch && content) {
- // Even if the current target can't handle the event, try to
- // propagate to chrome.
- nsCOMPtr<nsINode> disabledTarget = do_QueryInterface(parentTarget);
- if (disabledTarget) {
- parentEtci = EventTargetChainItemForChromeTarget(chain,
- disabledTarget,
- topEtci);
- if (parentEtci) {
- parentEtci->PreHandleEvent(preVisitor);
- if (preVisitor.mCanHandle) {
- chain[0].SetNewTarget(parentTarget);
- topEtci = parentEtci;
- continue;
- }
- }
- }
+ nsCOMPtr<nsINode> disabledTarget = do_QueryInterface(parentTarget);
+ parentEtci = MayRetargetToChromeIfCanNotHandleEvent(chain,
+ preVisitor,
+ parentEtci,
+ topEtci,
+ disabledTarget);
+ if (parentEtci && preVisitor.mCanHandle) {
+ EventTargetChainItem* item =
+ EventTargetChainItem::GetFirstCanHandleEventTarget(chain);
+ item->SetNewTarget(parentTarget);
+ topEtci = parentEtci;
+ continue;
}
break;
}
@@ -706,7 +808,11 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
targets[i] = chain[i].CurrentTarget()->GetTargetForDOMEvent();
}
} else {
- // Event target chain is created. Handle the chain.
+ // Event target chain is created. PreHandle the chain.
+ for (uint32_t i = 0; i < chain.Length(); ++i) {
+ chain[i].PreHandleEvent(preVisitor);
+ }
+ // Handle the chain.
EventChainPostVisitor postVisitor(preVisitor);
EventTargetChainItem::HandleEventTargetChain(chain, postVisitor,
aCallback, cd);
diff --git a/dom/events/EventDispatcher.h b/dom/events/EventDispatcher.h
index 3c754033d..db7b47dbf 100644
--- a/dom/events/EventDispatcher.h
+++ b/dom/events/EventDispatcher.h
@@ -31,14 +31,14 @@ class EventTarget;
* About event dispatching:
* When either EventDispatcher::Dispatch or
* EventDispatcher::DispatchDOMEvent is called an event target chain is
- * created. EventDispatcher creates the chain by calling PreHandleEvent
+ * created. EventDispatcher creates the chain by calling GetEventTargetParent
* on each event target and the creation continues until either the mCanHandle
* member of the EventChainPreVisitor object is false or the mParentTarget
* does not point to a new target. The event target chain is created in the
* heap.
*
* If the event needs retargeting, mEventTargetAtParent must be set in
- * PreHandleEvent.
+ * GetEventTargetParent.
*
* The capture, target and bubble phases of the event dispatch are handled
* by iterating through the event target chain. Iteration happens twice,
@@ -86,7 +86,7 @@ public:
/**
* Bits for items in the event target chain.
- * Set in PreHandleEvent() and used in PostHandleEvent().
+ * Set in GetEventTargetParent() and used in PostHandleEvent().
*
* @note These bits are different for each item in the event target chain.
* It is up to the Pre/PostHandleEvent implementation to decide how to
@@ -98,7 +98,7 @@ public:
/**
* Data for items in the event target chain.
- * Set in PreHandleEvent() and used in PostHandleEvent().
+ * Set in GetEventTargetParent() and used in PostHandleEvent().
*
* @note This data is different for each item in the event target chain.
* It is up to the Pre/PostHandleEvent implementation to decide how to
@@ -123,6 +123,7 @@ public:
, mOriginalTargetIsInAnon(aIsInAnon)
, mWantsWillHandleEvent(false)
, mMayHaveListenerManager(true)
+ , mWantsPreHandleEvent(false)
, mParentTarget(nullptr)
, mEventTargetAtParent(nullptr)
{
@@ -137,13 +138,14 @@ public:
mForceContentDispatch = false;
mWantsWillHandleEvent = false;
mMayHaveListenerManager = true;
+ mWantsPreHandleEvent = false;
mParentTarget = nullptr;
mEventTargetAtParent = nullptr;
}
/**
- * Member that must be set in PreHandleEvent by event targets. If set to false,
- * indicates that this event target will not be handling the event and
+ * Member that must be set in GetEventTargetParent by event targets. If set to
+ * false, indicates that this event target will not be handling the event and
* construction of the event target chain is complete. The target that sets
* mCanHandle to false is NOT included in the event target chain.
*/
@@ -170,7 +172,7 @@ public:
/**
* true if the original target of the event is inside anonymous content.
- * This is set before calling PreHandleEvent on event targets.
+ * This is set before calling GetEventTargetParent on event targets.
*/
bool mOriginalTargetIsInAnon;
@@ -182,11 +184,17 @@ public:
/**
* If it is known that the current target doesn't have a listener manager
- * when PreHandleEvent is called, set this to false.
+ * when GetEventTargetParent is called, set this to false.
*/
bool mMayHaveListenerManager;
/**
+ * Whether or not nsIDOMEventTarget::PreHandleEvent will be called. Default is
+ * false;
+ */
+ bool mWantsPreHandleEvent;
+
+ /**
* Parent item in the event target chain.
*/
dom::EventTarget* mParentTarget;
diff --git a/dom/events/test/mochitest.ini b/dom/events/test/mochitest.ini
index 0397487bb..27e8e7150 100644
--- a/dom/events/test/mochitest.ini
+++ b/dom/events/test/mochitest.ini
@@ -185,3 +185,4 @@ skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
[test_bug687787.html]
[test_bug1298970.html]
[test_bug1304044.html]
+[test_bug1305458.html]
diff --git a/dom/events/test/test_bug1305458.html b/dom/events/test/test_bug1305458.html
new file mode 100644
index 000000000..df65959a9
--- /dev/null
+++ b/dom/events/test/test_bug1305458.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1305458
+-->
+<head>
+ <title>Test for Bug 1305458</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <style>
+ input[type=number] {
+ -moz-appearance: textfield;
+ }
+ input[type=number]:focus,
+ input[type=number]:hover {
+ -moz-appearance: number-input;
+ }
+ </style>
+</head>
+<body onload="doTest()">
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1305458">Mozilla Bug 1305458</a>
+ <input id="test_input" type="number">
+ <div id="test_div">bar</div>
+ <script>
+ SimpleTest.waitForExplicitFinish();
+ var change_count = 0;
+ function doTest() {
+ let input = document.getElementById("test_input");
+ let div = document.getElementById("test_div");
+ input.addEventListener("change", () => {
+ ++change_count;
+ }, false);
+ // mouse hover
+ input.focus();
+ synthesizeMouse(input, 1, 1, {type: "mousemove"});
+ synthesizeKey("1", {});
+ input.blur();
+ is(change_count, 1, "input should fire change when blur");
+
+ input.focus();
+ synthesizeMouse(div, 1, 1, {type: "mousemove"});
+ synthesizeKey("1", {});
+ input.blur();
+ is(change_count, 2, "input should fire change when blur");
+ SimpleTest.finish();
+ }
+ </script>
+</body>
+</html>
diff --git a/dom/html/HTMLAnchorElement.cpp b/dom/html/HTMLAnchorElement.cpp
index a6cfacc53..501d6e3d0 100644
--- a/dom/html/HTMLAnchorElement.cpp
+++ b/dom/html/HTMLAnchorElement.cpp
@@ -252,9 +252,9 @@ HTMLAnchorElement::IsHTMLFocusable(bool aWithMouse,
}
nsresult
-HTMLAnchorElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLAnchorElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
- return PreHandleEventForAnchors(aVisitor);
+ return GetEventTargetParentForAnchors(aVisitor);
}
nsresult
diff --git a/dom/html/HTMLAnchorElement.h b/dom/html/HTMLAnchorElement.h
index 2cb04ad93..027d8d689 100644
--- a/dom/html/HTMLAnchorElement.h
+++ b/dom/html/HTMLAnchorElement.h
@@ -58,7 +58,8 @@ public:
bool aNullParent = true) override;
virtual bool IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, int32_t *aTabIndex) override;
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(
EventChainPostVisitor& aVisitor) override;
virtual bool IsLink(nsIURI** aURI) const override;
diff --git a/dom/html/HTMLAreaElement.cpp b/dom/html/HTMLAreaElement.cpp
index 098081b8b..213d4831d 100644
--- a/dom/html/HTMLAreaElement.cpp
+++ b/dom/html/HTMLAreaElement.cpp
@@ -81,9 +81,9 @@ HTMLAreaElement::SetTarget(const nsAString& aValue)
}
nsresult
-HTMLAreaElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLAreaElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
- return PreHandleEventForAnchors(aVisitor);
+ return GetEventTargetParentForAnchors(aVisitor);
}
nsresult
diff --git a/dom/html/HTMLAreaElement.h b/dom/html/HTMLAreaElement.h
index 650c0fd8f..c2ed7a928 100644
--- a/dom/html/HTMLAreaElement.h
+++ b/dom/html/HTMLAreaElement.h
@@ -44,7 +44,8 @@ public:
// nsIDOMHTMLAreaElement
NS_DECL_NSIDOMHTMLAREAELEMENT
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) override;
virtual bool IsLink(nsIURI** aURI) const override;
virtual void GetLinkTarget(nsAString& aTarget) override;
diff --git a/dom/html/HTMLButtonElement.cpp b/dom/html/HTMLButtonElement.cpp
index 435aa9f7f..aad1c412b 100644
--- a/dom/html/HTMLButtonElement.cpp
+++ b/dom/html/HTMLButtonElement.cpp
@@ -207,7 +207,7 @@ HTMLButtonElement::IsDisabledForEvents(EventMessage aMessage)
}
nsresult
-HTMLButtonElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLButtonElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = false;
if (IsDisabledForEvents(aVisitor.mEvent->mMessage)) {
@@ -235,7 +235,7 @@ HTMLButtonElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
}
}
- return nsGenericHTMLElement::PreHandleEvent(aVisitor);
+ return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
}
nsresult
diff --git a/dom/html/HTMLButtonElement.h b/dom/html/HTMLButtonElement.h
index ecd9e03d7..a8d206dd6 100644
--- a/dom/html/HTMLButtonElement.h
+++ b/dom/html/HTMLButtonElement.h
@@ -57,7 +57,8 @@ public:
virtual void FieldSetDisabledChanged(bool aNotify) override;
// nsIDOMEventTarget
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(
EventChainPostVisitor& aVisitor) override;
diff --git a/dom/html/HTMLCanvasElement.cpp b/dom/html/HTMLCanvasElement.cpp
index 4b5deab18..803c60e8a 100644
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -574,7 +574,7 @@ HTMLCanvasElement::CopyInnerTo(Element* aDest)
return rv;
}
-nsresult HTMLCanvasElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+nsresult HTMLCanvasElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
if (aVisitor.mEvent->mClass == eMouseEventClass) {
WidgetMouseEventBase* evt = (WidgetMouseEventBase*)aVisitor.mEvent;
@@ -592,7 +592,7 @@ nsresult HTMLCanvasElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
aVisitor.mCanHandle = true;
}
}
- return nsGenericHTMLElement::PreHandleEvent(aVisitor);
+ return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
}
nsChangeHint
diff --git a/dom/html/HTMLCanvasElement.h b/dom/html/HTMLCanvasElement.h
index e77db6ff1..de26c475a 100644
--- a/dom/html/HTMLCanvasElement.h
+++ b/dom/html/HTMLCanvasElement.h
@@ -312,7 +312,8 @@ public:
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
nsresult CopyInnerTo(mozilla::dom::Element* aDest);
- virtual nsresult PreHandleEvent(mozilla::EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ mozilla::EventChainPreVisitor& aVisitor) override;
/*
* Helpers called by various users of Canvas
diff --git a/dom/html/HTMLFieldSetElement.cpp b/dom/html/HTMLFieldSetElement.cpp
index d72fd1061..c008b9b6d 100644
--- a/dom/html/HTMLFieldSetElement.cpp
+++ b/dom/html/HTMLFieldSetElement.cpp
@@ -70,7 +70,7 @@ HTMLFieldSetElement::IsDisabledForEvents(EventMessage aMessage)
// nsIContent
nsresult
-HTMLFieldSetElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLFieldSetElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
// Do not process any DOM events if the element is disabled.
aVisitor.mCanHandle = false;
@@ -78,7 +78,7 @@ HTMLFieldSetElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
return NS_OK;
}
- return nsGenericHTMLFormElement::PreHandleEvent(aVisitor);
+ return nsGenericHTMLFormElement::GetEventTargetParent(aVisitor);
}
nsresult
diff --git a/dom/html/HTMLFieldSetElement.h b/dom/html/HTMLFieldSetElement.h
index 96fff4582..1e9f0214f 100644
--- a/dom/html/HTMLFieldSetElement.h
+++ b/dom/html/HTMLFieldSetElement.h
@@ -40,7 +40,8 @@ public:
NS_DECL_NSIDOMHTMLFIELDSETELEMENT
// nsIContent
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue, bool aNotify) override;
diff --git a/dom/html/HTMLFormElement.cpp b/dom/html/HTMLFormElement.cpp
index 6bea19a2b..bdc05b053 100644
--- a/dom/html/HTMLFormElement.cpp
+++ b/dom/html/HTMLFormElement.cpp
@@ -489,7 +489,7 @@ HTMLFormElement::UnbindFromTree(bool aDeep, bool aNullParent)
}
nsresult
-HTMLFormElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLFormElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mWantsWillHandleEvent = true;
if (aVisitor.mEvent->mOriginalTarget == static_cast<nsIContent*>(this)) {
@@ -513,7 +513,7 @@ HTMLFormElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
mGeneratingReset = true;
}
}
- return nsGenericHTMLElement::PreHandleEvent(aVisitor);
+ return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
}
nsresult
diff --git a/dom/html/HTMLFormElement.h b/dom/html/HTMLFormElement.h
index b3e836f5f..e45d4c10d 100644
--- a/dom/html/HTMLFormElement.h
+++ b/dom/html/HTMLFormElement.h
@@ -93,7 +93,8 @@ public:
nsIAtom* aAttribute,
const nsAString& aValue,
nsAttrValue& aResult) override;
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
virtual nsresult WillHandleEvent(
EventChainPostVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(
diff --git a/dom/html/HTMLImageElement.cpp b/dom/html/HTMLImageElement.cpp
index fab1cdef4..49cbebc5a 100644
--- a/dom/html/HTMLImageElement.cpp
+++ b/dom/html/HTMLImageElement.cpp
@@ -437,7 +437,7 @@ HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
nsresult
-HTMLImageElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLImageElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
// We handle image element with attribute ismap in its corresponding frame
// element. Set mMultipleActionsPrevented here to prevent the click event
@@ -446,7 +446,7 @@ HTMLImageElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
if (mouseEvent && mouseEvent->IsLeftClickEvent() && IsMap()) {
mouseEvent->mFlags.mMultipleActionsPrevented = true;
}
- return nsGenericHTMLElement::PreHandleEvent(aVisitor);
+ return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
}
bool
diff --git a/dom/html/HTMLImageElement.h b/dom/html/HTMLImageElement.h
index 62323e801..41730c2e5 100644
--- a/dom/html/HTMLImageElement.h
+++ b/dom/html/HTMLImageElement.h
@@ -70,7 +70,8 @@ public:
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
bool IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, int32_t *aTabIndex) override;
diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp
index 0b879bb9b..d5fca28f6 100644
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -147,6 +147,8 @@ namespace dom {
#define NS_CONTROL_TYPE(bits) ((bits) & ~( \
NS_OUTER_ACTIVATE_EVENT | NS_ORIGINAL_CHECKED_VALUE | NS_NO_CONTENT_DISPATCH | \
NS_ORIGINAL_INDETERMINATE_VALUE))
+#define NS_PRE_HANDLE_BLUR_EVENT (1 << 13)
+#define NS_PRE_HANDLE_INPUT_EVENT (1 << 14)
// whether textfields should be selected once focused:
// -1: no, 1: yes, 0: uninitialized
@@ -3738,7 +3740,7 @@ HTMLInputElement::IsDisabledForEvents(EventMessage aMessage)
}
nsresult
-HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLInputElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
// Do not process any DOM events if the element is disabled
aVisitor.mCanHandle = false;
@@ -3755,7 +3757,7 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
//FIXME Allow submission etc. also when there is no prescontext, Bug 329509.
if (!aVisitor.mPresContext) {
- return nsGenericHTMLElement::PreHandleEvent(aVisitor);
+ return nsGenericHTMLFormElementWithState::GetEventTargetParent(aVisitor);
}
//
// Web pages expect the value of a radio button or checkbox to be set
@@ -3865,23 +3867,16 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
// Fire onchange (if necessary), before we do the blur, bug 357684.
if (aVisitor.mEvent->mMessage == eBlur) {
- // Experimental mobile types rely on the system UI to prevent users to not
- // set invalid values but we have to be extra-careful. Especially if the
- // option has been enabled on desktop.
- if (IsExperimentalMobileType(mType)) {
- nsAutoString aValue;
- GetValueInternal(aValue);
- nsresult rv =
- SetValueInternal(aValue, nsTextEditorState::eSetValue_Internal);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- FireChangeEventIfNeeded();
+ // We set NS_PRE_HANDLE_BLUR_EVENT here and handle it in PreHandleEvent to
+ // prevent breaking event target chain creation.
+ aVisitor.mWantsPreHandleEvent = true;
+ aVisitor.mItemFlags |= NS_PRE_HANDLE_BLUR_EVENT;
}
if (mType == NS_FORM_INPUT_RANGE &&
(aVisitor.mEvent->mMessage == eFocus ||
aVisitor.mEvent->mMessage == eBlur)) {
- // Just as nsGenericHTMLFormElementWithState::PreHandleEvent calls
+ // Just as nsGenericHTMLFormElementWithState::GetEventTargetParent calls
// nsIFormControlFrame::SetFocus, we handle focus here.
nsIFrame* frame = GetPrimaryFrame();
if (frame) {
@@ -3969,10 +3964,11 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
}
}
- nsresult rv = nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
+ nsresult rv = nsGenericHTMLFormElementWithState::GetEventTargetParent(aVisitor);
- // We do this after calling the base class' PreHandleEvent so that
- // nsIContent::PreHandleEvent doesn't reset any change we make to mCanHandle.
+ // We do this after calling the base class' GetEventTargetParent so that
+ // nsIContent::GetEventTargetParent doesn't reset any change we make to
+ // mCanHandle.
if (mType == NS_FORM_INPUT_NUMBER &&
aVisitor.mEvent->IsTrusted() &&
aVisitor.mEvent->mOriginalTarget != this) {
@@ -3987,18 +3983,10 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
}
if (textControl && aVisitor.mEvent->mOriginalTarget == textControl) {
if (aVisitor.mEvent->mMessage == eEditorInput) {
- // Propogate the anon text control's new value to our HTMLInputElement:
- nsAutoString value;
- numberControlFrame->GetValueOfAnonTextControl(value);
- numberControlFrame->HandlingInputEvent(true);
- nsWeakFrame weakNumberControlFrame(numberControlFrame);
- rv = SetValueInternal(value,
- nsTextEditorState::eSetValue_BySetUserInput |
- nsTextEditorState::eSetValue_Notify);
- NS_ENSURE_SUCCESS(rv, rv);
- if (weakNumberControlFrame.IsAlive()) {
- numberControlFrame->HandlingInputEvent(false);
- }
+ aVisitor.mWantsPreHandleEvent = true;
+ // We set NS_PRE_HANDLE_INPUT_EVENT here and handle it in PreHandleEvent
+ // to prevent breaking event target chain creation.
+ aVisitor.mItemFlags |= NS_PRE_HANDLE_INPUT_EVENT;
}
else if (aVisitor.mEvent->mMessage == eFormChange) {
// We cancel the DOM 'change' event that is fired for any change to our
@@ -4037,6 +4025,50 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
return rv;
}
+nsresult
+HTMLInputElement::PreHandleEvent(EventChainVisitor& aVisitor)
+{
+ if (!aVisitor.mPresContext) {
+ return nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
+ }
+ nsresult rv;
+ if (aVisitor.mItemFlags & NS_PRE_HANDLE_BLUR_EVENT) {
+ MOZ_ASSERT(aVisitor.mEvent->mMessage == eBlur);
+ // Experimental mobile types rely on the system UI to prevent users to not
+ // set invalid values but we have to be extra-careful. Especially if the
+ // option has been enabled on desktop.
+ if (IsExperimentalMobileType(mType)) {
+ nsAutoString aValue;
+ GetValueInternal(aValue);
+ nsresult rv =
+ SetValueInternal(aValue, nsTextEditorState::eSetValue_Internal);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ FireChangeEventIfNeeded();
+ }
+ rv = nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
+ if (aVisitor.mItemFlags & NS_PRE_HANDLE_INPUT_EVENT) {
+ nsNumberControlFrame* numberControlFrame = do_QueryFrame(GetPrimaryFrame());
+ MOZ_ASSERT(aVisitor.mEvent->mMessage == eEditorInput);
+ MOZ_ASSERT(numberControlFrame);
+ MOZ_ASSERT(numberControlFrame->GetAnonTextControl() ==
+ aVisitor.mEvent->mOriginalTarget);
+ // Propogate the anon text control's new value to our HTMLInputElement:
+ nsAutoString value;
+ numberControlFrame->GetValueOfAnonTextControl(value);
+ numberControlFrame->HandlingInputEvent(true);
+ nsWeakFrame weakNumberControlFrame(numberControlFrame);
+ rv = SetValueInternal(value,
+ nsTextEditorState::eSetValue_BySetUserInput |
+ nsTextEditorState::eSetValue_Notify);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (weakNumberControlFrame.IsAlive()) {
+ numberControlFrame->HandlingInputEvent(false);
+ }
+ }
+ return rv;
+}
+
void
HTMLInputElement::StartRangeThumbDrag(WidgetGUIEvent* aEvent)
{
diff --git a/dom/html/HTMLInputElement.h b/dom/html/HTMLInputElement.h
index 98a590443..98c74893e 100644
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -185,7 +185,9 @@ public:
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
+ virtual nsresult PreHandleEvent(EventChainVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(
EventChainPostVisitor& aVisitor) override;
void PostHandleEventForRangeThumb(EventChainPostVisitor& aVisitor);
diff --git a/dom/html/HTMLLinkElement.cpp b/dom/html/HTMLLinkElement.cpp
index 8afe767bd..0a2cdaaf4 100644
--- a/dom/html/HTMLLinkElement.cpp
+++ b/dom/html/HTMLLinkElement.cpp
@@ -421,9 +421,9 @@ HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
nsresult
-HTMLLinkElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLLinkElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
- return PreHandleEventForAnchors(aVisitor);
+ return GetEventTargetParentForAnchors(aVisitor);
}
nsresult
diff --git a/dom/html/HTMLLinkElement.h b/dom/html/HTMLLinkElement.h
index 421b149e9..1fa154f41 100644
--- a/dom/html/HTMLLinkElement.h
+++ b/dom/html/HTMLLinkElement.h
@@ -46,7 +46,8 @@ public:
void UpdateImport();
// nsIDOMEventTarget
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(
EventChainPostVisitor& aVisitor) override;
diff --git a/dom/html/HTMLMenuItemElement.cpp b/dom/html/HTMLMenuItemElement.cpp
index ca8bb4feb..6a8ad8174 100644
--- a/dom/html/HTMLMenuItemElement.cpp
+++ b/dom/html/HTMLMenuItemElement.cpp
@@ -252,7 +252,7 @@ HTMLMenuItemElement::SetChecked(bool aChecked)
}
nsresult
-HTMLMenuItemElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLMenuItemElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
if (aVisitor.mEvent->mMessage == eMouseClick) {
@@ -283,7 +283,7 @@ HTMLMenuItemElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
aVisitor.mItemFlags |= mType;
}
- return nsGenericHTMLElement::PreHandleEvent(aVisitor);
+ return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
}
nsresult
diff --git a/dom/html/HTMLMenuItemElement.h b/dom/html/HTMLMenuItemElement.h
index 3c19b1170..1da63edd0 100644
--- a/dom/html/HTMLMenuItemElement.h
+++ b/dom/html/HTMLMenuItemElement.h
@@ -36,7 +36,8 @@ public:
// nsIDOMHTMLMenuItemElement
NS_DECL_NSIDOMHTMLMENUITEMELEMENT
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(
EventChainPostVisitor& aVisitor) override;
diff --git a/dom/html/HTMLOptGroupElement.cpp b/dom/html/HTMLOptGroupElement.cpp
index 9e738961d..0424ccef3 100644
--- a/dom/html/HTMLOptGroupElement.cpp
+++ b/dom/html/HTMLOptGroupElement.cpp
@@ -48,7 +48,7 @@ NS_IMPL_STRING_ATTR(HTMLOptGroupElement, Label, label)
nsresult
-HTMLOptGroupElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLOptGroupElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = false;
// Do not process any DOM events if the element is disabled
@@ -65,7 +65,7 @@ HTMLOptGroupElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
}
}
- return nsGenericHTMLElement::PreHandleEvent(aVisitor);
+ return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
}
Element*
diff --git a/dom/html/HTMLOptGroupElement.h b/dom/html/HTMLOptGroupElement.h
index e46a6a953..c669f43b4 100644
--- a/dom/html/HTMLOptGroupElement.h
+++ b/dom/html/HTMLOptGroupElement.h
@@ -35,7 +35,8 @@ public:
virtual void RemoveChildAt(uint32_t aIndex, bool aNotify) override;
// nsIContent
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
virtual EventStates IntrinsicState() const override;
diff --git a/dom/html/HTMLSelectElement.cpp b/dom/html/HTMLSelectElement.cpp
index 9ba0a1efe..272a16578 100644
--- a/dom/html/HTMLSelectElement.cpp
+++ b/dom/html/HTMLSelectElement.cpp
@@ -1442,14 +1442,14 @@ HTMLSelectElement::IsDisabledForEvents(EventMessage aMessage)
}
nsresult
-HTMLSelectElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLSelectElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = false;
if (IsDisabledForEvents(aVisitor.mEvent->mMessage)) {
return NS_OK;
}
- return nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
+ return nsGenericHTMLFormElementWithState::GetEventTargetParent(aVisitor);
}
nsresult
diff --git a/dom/html/HTMLSelectElement.h b/dom/html/HTMLSelectElement.h
index dc1075cd7..4cb5f90c9 100644
--- a/dom/html/HTMLSelectElement.h
+++ b/dom/html/HTMLSelectElement.h
@@ -278,7 +278,8 @@ public:
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
// nsIContent
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(
EventChainPostVisitor& aVisitor) override;
diff --git a/dom/html/HTMLTextAreaElement.cpp b/dom/html/HTMLTextAreaElement.cpp
index 42bc02435..796d8a49e 100644
--- a/dom/html/HTMLTextAreaElement.cpp
+++ b/dom/html/HTMLTextAreaElement.cpp
@@ -506,7 +506,7 @@ HTMLTextAreaElement::IsDisabledForEvents(EventMessage aMessage)
}
nsresult
-HTMLTextAreaElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+HTMLTextAreaElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = false;
if (IsDisabledForEvents(aVisitor.mEvent->mMessage)) {
@@ -534,11 +534,22 @@ HTMLTextAreaElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
aVisitor.mEvent->mFlags.mNoContentDispatch = false;
}
- // Fire onchange (if necessary), before we do the blur, bug 370521.
if (aVisitor.mEvent->mMessage == eBlur) {
- FireChangeEventIfNeeded();
+ // Set mWantsPreHandleEvent and fire change event in PreHandleEvent to
+ // prevent it breaks event target chain creation.
+ aVisitor.mWantsPreHandleEvent = true;
}
+ return nsGenericHTMLFormElementWithState::GetEventTargetParent(aVisitor);
+}
+
+nsresult
+HTMLTextAreaElement::PreHandleEvent(EventChainVisitor& aVisitor)
+{
+ if (aVisitor.mEvent->mMessage == eBlur) {
+ // Fire onchange (if necessary), before we do the blur, bug 370521.
+ FireChangeEventIfNeeded();
+ }
return nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
}
diff --git a/dom/html/HTMLTextAreaElement.h b/dom/html/HTMLTextAreaElement.h
index 039082818..bfc7d203d 100644
--- a/dom/html/HTMLTextAreaElement.h
+++ b/dom/html/HTMLTextAreaElement.h
@@ -125,7 +125,9 @@ public:
int32_t aModType) const override;
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
+ virtual nsresult PreHandleEvent(EventChainVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(
EventChainPostVisitor& aVisitor) override;
diff --git a/dom/html/nsGenericHTMLElement.cpp b/dom/html/nsGenericHTMLElement.cpp
index 78e4d5b95..394a77a59 100644
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -607,16 +607,16 @@ nsGenericHTMLElement::CheckHandleEventForAnchorsPreconditions(
}
nsresult
-nsGenericHTMLElement::PreHandleEventForAnchors(EventChainPreVisitor& aVisitor)
+nsGenericHTMLElement::GetEventTargetParentForAnchors(EventChainPreVisitor& aVisitor)
{
- nsresult rv = nsGenericHTMLElementBase::PreHandleEvent(aVisitor);
+ nsresult rv = nsGenericHTMLElementBase::GetEventTargetParent(aVisitor);
NS_ENSURE_SUCCESS(rv, rv);
if (!CheckHandleEventForAnchorsPreconditions(aVisitor)) {
return NS_OK;
}
- return PreHandleEventForLinks(aVisitor);
+ return GetEventTargetParentForLinks(aVisitor);
}
nsresult
@@ -2081,7 +2081,19 @@ nsGenericHTMLFormElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
nsresult
-nsGenericHTMLFormElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+nsGenericHTMLFormElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
+{
+ if (aVisitor.mEvent->IsTrusted() && (aVisitor.mEvent->mMessage == eFocus ||
+ aVisitor.mEvent->mMessage == eBlur)) {
+ // We have to handle focus/blur event to change focus states in
+ // PreHandleEvent to prevent it breaks event target chain creation.
+ aVisitor.mWantsPreHandleEvent = true;
+ }
+ return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
+}
+
+nsresult
+nsGenericHTMLFormElement::PreHandleEvent(EventChainVisitor& aVisitor)
{
if (aVisitor.mEvent->IsTrusted()) {
switch (aVisitor.mEvent->mMessage) {
@@ -2105,7 +2117,6 @@ nsGenericHTMLFormElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
break;
}
}
-
return nsGenericHTMLElement::PreHandleEvent(aVisitor);
}
diff --git a/dom/html/nsGenericHTMLElement.h b/dom/html/nsGenericHTMLElement.h
index 2b8b608b9..ab4391aa1 100644
--- a/dom/html/nsGenericHTMLElement.h
+++ b/dom/html/nsGenericHTMLElement.h
@@ -498,7 +498,8 @@ public:
*/
bool CheckHandleEventForAnchorsPreconditions(
mozilla::EventChainVisitor& aVisitor);
- nsresult PreHandleEventForAnchors(mozilla::EventChainPreVisitor& aVisitor);
+ nsresult GetEventTargetParentForAnchors(
+ mozilla::EventChainPreVisitor& aVisitor);
nsresult PostHandleEventForAnchors(mozilla::EventChainPostVisitor& aVisitor);
bool IsHTMLLink(nsIURI** aURI) const;
@@ -1219,8 +1220,10 @@ public:
virtual IMEState GetDesiredIMEState() override;
virtual mozilla::EventStates IntrinsicState() const override;
- virtual nsresult PreHandleEvent(
+ virtual nsresult GetEventTargetParent(
mozilla::EventChainPreVisitor& aVisitor) override;
+ virtual nsresult PreHandleEvent(
+ mozilla::EventChainVisitor& aVisitor) override;
/**
* This callback is called by a fieldest on all its elements whenever its
@@ -1305,7 +1308,7 @@ protected:
static bool FormIdUpdated(Element* aOldElement, Element* aNewElement,
void* aData);
- // Returns true if the event should not be handled from PreHandleEvent
+ // Returns true if the event should not be handled from GetEventTargetParent
bool IsElementDisabledForEvents(mozilla::EventMessage aMessage,
nsIFrame* aFrame);
diff --git a/dom/indexedDB/IDBFileHandle.cpp b/dom/indexedDB/IDBFileHandle.cpp
index 8b88e1722..55dd22ce9 100644
--- a/dom/indexedDB/IDBFileHandle.cpp
+++ b/dom/indexedDB/IDBFileHandle.cpp
@@ -127,7 +127,7 @@ IDBFileHandle::Run()
}
nsresult
-IDBFileHandle::PreHandleEvent(EventChainPreVisitor& aVisitor)
+IDBFileHandle::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
AssertIsOnOwningThread();
diff --git a/dom/indexedDB/IDBFileHandle.h b/dom/indexedDB/IDBFileHandle.h
index 574524090..17206e09c 100644
--- a/dom/indexedDB/IDBFileHandle.h
+++ b/dom/indexedDB/IDBFileHandle.h
@@ -117,7 +117,7 @@ public:
// nsIDOMEventTarget
virtual nsresult
- PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
// WrapperCache
virtual JSObject*
diff --git a/dom/indexedDB/IDBFileRequest.cpp b/dom/indexedDB/IDBFileRequest.cpp
index 066b2b24a..7d93f24de 100644
--- a/dom/indexedDB/IDBFileRequest.cpp
+++ b/dom/indexedDB/IDBFileRequest.cpp
@@ -64,7 +64,7 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(IDBFileRequest, DOMRequest,
mFileHandle)
nsresult
-IDBFileRequest::PreHandleEvent(EventChainPreVisitor& aVisitor)
+IDBFileRequest::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
AssertIsOnOwningThread();
diff --git a/dom/indexedDB/IDBFileRequest.h b/dom/indexedDB/IDBFileRequest.h
index 4f4252dc9..3d8d282fd 100644
--- a/dom/indexedDB/IDBFileRequest.h
+++ b/dom/indexedDB/IDBFileRequest.h
@@ -58,7 +58,7 @@ public:
// nsIDOMEventTarget
virtual nsresult
- PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
// nsWrapperCache
virtual JSObject*
diff --git a/dom/indexedDB/IDBRequest.cpp b/dom/indexedDB/IDBRequest.cpp
index e0e318059..b74725954 100644
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -449,7 +449,7 @@ NS_IMPL_ADDREF_INHERITED(IDBRequest, IDBWrapperCache)
NS_IMPL_RELEASE_INHERITED(IDBRequest, IDBWrapperCache)
nsresult
-IDBRequest::PreHandleEvent(EventChainPreVisitor& aVisitor)
+IDBRequest::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
AssertIsOnOwningThread();
diff --git a/dom/indexedDB/IDBRequest.h b/dom/indexedDB/IDBRequest.h
index 1c7fca756..e6cbaab9e 100644
--- a/dom/indexedDB/IDBRequest.h
+++ b/dom/indexedDB/IDBRequest.h
@@ -90,7 +90,7 @@ public:
// nsIDOMEventTarget
virtual nsresult
- PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
void
GetSource(Nullable<OwningIDBObjectStoreOrIDBIndexOrIDBCursor>& aSource) const;
diff --git a/dom/indexedDB/IDBTransaction.cpp b/dom/indexedDB/IDBTransaction.cpp
index a50489898..ec27c51d8 100644
--- a/dom/indexedDB/IDBTransaction.cpp
+++ b/dom/indexedDB/IDBTransaction.cpp
@@ -996,7 +996,7 @@ IDBTransaction::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
}
nsresult
-IDBTransaction::PreHandleEvent(EventChainPreVisitor& aVisitor)
+IDBTransaction::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
AssertIsOnOwningThread();
diff --git a/dom/indexedDB/IDBTransaction.h b/dom/indexedDB/IDBTransaction.h
index 1c3e8be99..5a893ca20 100644
--- a/dom/indexedDB/IDBTransaction.h
+++ b/dom/indexedDB/IDBTransaction.h
@@ -314,7 +314,7 @@ public:
// nsIDOMEventTarget
virtual nsresult
- PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
private:
IDBTransaction(IDBDatabase* aDatabase,
diff --git a/dom/interfaces/events/nsIDOMEventTarget.idl b/dom/interfaces/events/nsIDOMEventTarget.idl
index a7e3aae5a..9e00c598c 100644
--- a/dom/interfaces/events/nsIDOMEventTarget.idl
+++ b/dom/interfaces/events/nsIDOMEventTarget.idl
@@ -13,6 +13,7 @@
using mozilla::dom::Nullable;
namespace mozilla {
+class EventChainVisitor;
class EventChainPostVisitor;
class EventChainPreVisitor;
class EventListenerManager;
@@ -224,7 +225,19 @@ interface nsIDOMEventTarget : nsISupports
* @note Only EventDispatcher should call this method.
*/
[noscript, nostdcall]
- void PreHandleEvent(in EventChainPreVisitorRef aVisitor);
+ void GetEventTargetParent(in EventChainPreVisitorRef aVisitor);
+
+ /**
+ * Called before the capture phase of the event flow and after event target
+ * chain creation. This is used to handle those stuffs must be executed before
+ * dispatch event to DOM
+ */
+%{C++
+ virtual nsresult PreHandleEvent(mozilla::EventChainVisitor& aVisitor)
+ {
+ return NS_OK;
+ }
+%}
/**
* If EventChainPreVisitor.mWantsWillHandleEvent is set PR_TRUE,
diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h
index d9988a596..004067355 100644
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -135,7 +135,7 @@ public:
}
nsresult
- PreHandleEvent(EventChainPreVisitor& aVisitor) override
+ GetEventTargetParent(EventChainPreVisitor& aVisitor) override
{
aVisitor.mForceContentDispatch = true;
return NS_OK;
diff --git a/dom/mathml/nsMathMLElement.cpp b/dom/mathml/nsMathMLElement.cpp
index 2be931682..e2bc4f008 100644
--- a/dom/mathml/nsMathMLElement.cpp
+++ b/dom/mathml/nsMathMLElement.cpp
@@ -919,12 +919,12 @@ nsMathMLElement::MapMathMLAttributesInto(const nsMappedAttributes* aAttributes,
}
nsresult
-nsMathMLElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+nsMathMLElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
- nsresult rv = Element::PreHandleEvent(aVisitor);
+ nsresult rv = Element::GetEventTargetParent(aVisitor);
NS_ENSURE_SUCCESS(rv, rv);
- return PreHandleEventForLinks(aVisitor);
+ return GetEventTargetParentForLinks(aVisitor);
}
nsresult
diff --git a/dom/mathml/nsMathMLElement.h b/dom/mathml/nsMathMLElement.h
index 47ed8b165..bbcdb9771 100644
--- a/dom/mathml/nsMathMLElement.h
+++ b/dom/mathml/nsMathMLElement.h
@@ -74,7 +74,7 @@ public:
static void MapMathMLAttributesInto(const nsMappedAttributes* aAttributes,
nsRuleData* aRuleData);
- virtual nsresult PreHandleEvent(
+ virtual nsresult GetEventTargetParent(
mozilla::EventChainPreVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(
mozilla::EventChainPostVisitor& aVisitor) override;
diff --git a/dom/svg/SVGAElement.cpp b/dom/svg/SVGAElement.cpp
index a69c60ee4..95c3d6979 100644
--- a/dom/svg/SVGAElement.cpp
+++ b/dom/svg/SVGAElement.cpp
@@ -84,12 +84,12 @@ SVGAElement::Href()
// nsINode methods
nsresult
-SVGAElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+SVGAElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
- nsresult rv = Element::PreHandleEvent(aVisitor);
+ nsresult rv = Element::GetEventTargetParent(aVisitor);
NS_ENSURE_SUCCESS(rv, rv);
- return PreHandleEventForLinks(aVisitor);
+ return GetEventTargetParentForLinks(aVisitor);
}
nsresult
diff --git a/dom/svg/SVGAElement.h b/dom/svg/SVGAElement.h
index 4f7df9e50..776c96f53 100644
--- a/dom/svg/SVGAElement.h
+++ b/dom/svg/SVGAElement.h
@@ -37,7 +37,8 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SVGAElement, SVGAElementBase)
// nsINode interface methods
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(
EventChainPostVisitor& aVisitor) override;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
diff --git a/dom/svg/SVGSVGElement.cpp b/dom/svg/SVGSVGElement.cpp
index 90c3c3fff..bb3aaccd2 100644
--- a/dom/svg/SVGSVGElement.cpp
+++ b/dom/svg/SVGSVGElement.cpp
@@ -589,7 +589,7 @@ SVGSVGElement::IsAttributeMapped(const nsIAtom* name) const
// nsIContent methods:
nsresult
-SVGSVGElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+SVGSVGElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
if (aVisitor.mEvent->mMessage == eSVGLoad) {
if (mTimedDocumentRoot) {
@@ -600,7 +600,7 @@ SVGSVGElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
AnimationNeedsResample();
}
}
- return SVGSVGElementBase::PreHandleEvent(aVisitor);
+ return SVGSVGElementBase::GetEventTargetParent(aVisitor);
}
bool
diff --git a/dom/svg/SVGSVGElement.h b/dom/svg/SVGSVGElement.h
index da08ad770..0145ae8fa 100644
--- a/dom/svg/SVGSVGElement.h
+++ b/dom/svg/SVGSVGElement.h
@@ -152,7 +152,8 @@ public:
// nsIContent interface
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
- virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ virtual nsresult GetEventTargetParent(
+ EventChainPreVisitor& aVisitor) override;
virtual bool IsEventAttributeName(nsIAtom* aName) override;
diff --git a/dom/workers/SharedWorker.cpp b/dom/workers/SharedWorker.cpp
index 99bb50339..750dc9237 100644
--- a/dom/workers/SharedWorker.cpp
+++ b/dom/workers/SharedWorker.cpp
@@ -181,7 +181,7 @@ SharedWorker::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
}
nsresult
-SharedWorker::PreHandleEvent(EventChainPreVisitor& aVisitor)
+SharedWorker::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
AssertIsOnMainThread();
@@ -200,5 +200,5 @@ SharedWorker::PreHandleEvent(EventChainPreVisitor& aVisitor)
return NS_OK;
}
- return DOMEventTargetHelper::PreHandleEvent(aVisitor);
+ return DOMEventTargetHelper::GetEventTargetParent(aVisitor);
}
diff --git a/dom/workers/SharedWorker.h b/dom/workers/SharedWorker.h
index 220436e4d..4b50d39e8 100644
--- a/dom/workers/SharedWorker.h
+++ b/dom/workers/SharedWorker.h
@@ -76,7 +76,7 @@ public:
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
virtual nsresult
- PreHandleEvent(EventChainPreVisitor& aVisitor) override;
+ GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
WorkerPrivate*
GetWorkerPrivate() const
diff --git a/dom/xul/nsXULElement.cpp b/dom/xul/nsXULElement.cpp
index a854f53ec..bc9215086 100644
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -126,6 +126,8 @@ uint32_t nsXULPrototypeAttribute::gNumCacheSets;
uint32_t nsXULPrototypeAttribute::gNumCacheFills;
#endif
+#define NS_DISPATCH_XUL_COMMAND (1 << 0)
+
class nsXULElementTearoff final : public nsIFrameLoaderOwner
{
~nsXULElementTearoff() {}
@@ -1236,17 +1238,65 @@ nsXULElement::List(FILE* out, int32_t aIndent) const
}
#endif
+bool
+nsXULElement::IsEventStoppedFromAnonymousScrollbar(EventMessage aMessage)
+{
+ return (IsRootOfNativeAnonymousSubtree() &&
+ IsAnyOfXULElements(nsGkAtoms::scrollbar, nsGkAtoms::scrollcorner) &&
+ (aMessage == eMouseClick || aMessage == eMouseDoubleClick ||
+ aMessage == eXULCommand || aMessage == eContextMenu ||
+ aMessage == eDragStart));
+}
+
nsresult
-nsXULElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+nsXULElement::DispatchXULCommand(const EventChainVisitor& aVisitor,
+ nsAutoString& aCommand)
+{
+ // XXX sXBL/XBL2 issue! Owner or current document?
+ nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(GetUncomposedDoc()));
+ NS_ENSURE_STATE(domDoc);
+ nsCOMPtr<nsIDOMElement> commandElt;
+ domDoc->GetElementById(aCommand, getter_AddRefs(commandElt));
+ nsCOMPtr<nsIContent> commandContent(do_QueryInterface(commandElt));
+ if (commandContent) {
+ // Create a new command event to dispatch to the element
+ // pointed to by the command attribute. The new event's
+ // sourceEvent will be the original command event that we're
+ // handling.
+ nsCOMPtr<nsIDOMEvent> domEvent = aVisitor.mDOMEvent;
+ while (domEvent) {
+ Event* event = domEvent->InternalDOMEvent();
+ NS_ENSURE_STATE(!SameCOMIdentity(event->GetOriginalTarget(),
+ commandContent));
+ nsCOMPtr<nsIDOMXULCommandEvent> commandEvent =
+ do_QueryInterface(domEvent);
+ if (commandEvent) {
+ commandEvent->GetSourceEvent(getter_AddRefs(domEvent));
+ } else {
+ domEvent = nullptr;
+ }
+ }
+ WidgetInputEvent* orig = aVisitor.mEvent->AsInputEvent();
+ nsContentUtils::DispatchXULCommand(
+ commandContent,
+ orig->IsTrusted(),
+ aVisitor.mDOMEvent,
+ nullptr,
+ orig->IsControl(),
+ orig->IsAlt(),
+ orig->IsShift(),
+ orig->IsMeta());
+ } else {
+ NS_WARNING("A XUL element is attached to a command that doesn't exist!\n");
+ }
+ return NS_OK;
+}
+
+nsresult
+nsXULElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119
- if (IsRootOfNativeAnonymousSubtree() &&
- (IsAnyOfXULElements(nsGkAtoms::scrollbar, nsGkAtoms::scrollcorner)) &&
- (aVisitor.mEvent->mMessage == eMouseClick ||
- aVisitor.mEvent->mMessage == eMouseDoubleClick ||
- aVisitor.mEvent->mMessage == eXULCommand ||
- aVisitor.mEvent->mMessage == eContextMenu ||
- aVisitor.mEvent->mMessage == eDragStart)) {
+ if (IsEventStoppedFromAnonymousScrollbar(aVisitor.mEvent->mMessage)) {
// Don't propagate these events from native anonymous scrollbar.
aVisitor.mCanHandle = true;
aVisitor.mParentTarget = nullptr;
@@ -1263,55 +1313,33 @@ nsXULElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
// See if we have a command elt. If so, we execute on the command
// instead of on our content element.
nsAutoString command;
- if (xulEvent && GetAttr(kNameSpaceID_None, nsGkAtoms::command, command) &&
+ if (xulEvent &&
+ GetAttr(kNameSpaceID_None, nsGkAtoms::command, command) &&
!command.IsEmpty()) {
// Stop building the event target chain for the original event.
// We don't want it to propagate to any DOM nodes.
aVisitor.mCanHandle = false;
aVisitor.mAutomaticChromeDispatch = false;
-
- // XXX sXBL/XBL2 issue! Owner or current document?
- nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(GetUncomposedDoc()));
- NS_ENSURE_STATE(domDoc);
- nsCOMPtr<nsIDOMElement> commandElt;
- domDoc->GetElementById(command, getter_AddRefs(commandElt));
- nsCOMPtr<nsIContent> commandContent(do_QueryInterface(commandElt));
- if (commandContent) {
- // Create a new command event to dispatch to the element
- // pointed to by the command attribute. The new event's
- // sourceEvent will be the original command event that we're
- // handling.
- nsCOMPtr<nsIDOMEvent> domEvent = aVisitor.mDOMEvent;
- while (domEvent) {
- Event* event = domEvent->InternalDOMEvent();
- NS_ENSURE_STATE(!SameCOMIdentity(event->GetOriginalTarget(),
- commandContent));
- nsCOMPtr<nsIDOMXULCommandEvent> commandEvent =
- do_QueryInterface(domEvent);
- if (commandEvent) {
- commandEvent->GetSourceEvent(getter_AddRefs(domEvent));
- } else {
- domEvent = nullptr;
- }
- }
-
- WidgetInputEvent* orig = aVisitor.mEvent->AsInputEvent();
- nsContentUtils::DispatchXULCommand(
- commandContent,
- aVisitor.mEvent->IsTrusted(),
- aVisitor.mDOMEvent,
- nullptr,
- orig->IsControl(),
- orig->IsAlt(),
- orig->IsShift(),
- orig->IsMeta());
- } else {
- NS_WARNING("A XUL element is attached to a command that doesn't exist!\n");
- }
+ // Dispatch XUL command in PreHandleEvent to prevent it breaks event
+ // target chain creation
+ aVisitor.mWantsPreHandleEvent = true;
+ aVisitor.mItemFlags |= NS_DISPATCH_XUL_COMMAND;
return NS_OK;
}
}
+ return nsStyledElement::GetEventTargetParent(aVisitor);
+}
+
+nsresult
+nsXULElement::PreHandleEvent(EventChainVisitor& aVisitor)
+{
+ if (aVisitor.mItemFlags & NS_DISPATCH_XUL_COMMAND) {
+ nsAutoString command;
+ GetAttr(kNameSpaceID_None, nsGkAtoms::command, command);
+ MOZ_ASSERT(!command.IsEmpty());
+ return DispatchXULCommand(aVisitor, command);
+ }
return nsStyledElement::PreHandleEvent(aVisitor);
}
diff --git a/dom/xul/nsXULElement.h b/dom/xul/nsXULElement.h
index 80424412f..109f6c2e7 100644
--- a/dom/xul/nsXULElement.h
+++ b/dom/xul/nsXULElement.h
@@ -355,9 +355,10 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULElement, nsStyledElement)
// nsINode
- virtual nsresult PreHandleEvent(
+ virtual nsresult GetEventTargetParent(
mozilla::EventChainPreVisitor& aVisitor) override;
-
+ virtual nsresult PreHandleEvent(
+ mozilla::EventChainVisitor& aVisitor) override;
// nsIContent
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
@@ -689,6 +690,11 @@ protected:
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
void MaybeUpdatePrivateLifetime();
+
+ bool IsEventStoppedFromAnonymousScrollbar(mozilla::EventMessage aMessage);
+
+ nsresult DispatchXULCommand(const mozilla::EventChainVisitor& aVisitor,
+ nsAutoString& aCommand);
};
#endif // nsXULElement_h__