mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-22 08:27:31 +09:00
Bug 1305458 - Changing -moz-appearence on hover breaks change event
* Rename nsIDOMEventTarget::PreHandleEvent to nsIDOMEventTarget::GetEventTargetParent * Add nsIDOMEventTarget::PreHandleEvent * Add EventTargetChainItem::GetFirstEventTarget * Call EventTargetChainItem::PreHandleEvent even it sets mCanHandle=false * Move form control frame focus/blur from nsGenericHTMLFormElement::GetEventTargetParent to PreHandleEvent * Move fire change event from HTMLTextAreaElement::GetEventTargetParent to PreHandleEvent * Refine nsXULElement::GetEventTargetParent * Move dispatch XUL command from nsXULElement::GetEventTargetParent to PreHandleEvent * Move fire events and set value from HTMLInputElement::GetEventTargetParent to PreHandleEvent * Add test case * Let HTMLInputElement delegate event handling to it's parent class * Refine EventTargetChain flags to reduce overheads * Refine event target chain creation * Refine assertion in EventTargetChainItem::Create Tag #1375
This commit is contained in:
parent
20b2c26451
commit
cb2b45e472
70 changed files with 547 additions and 258 deletions
|
|
@ -328,7 +328,7 @@ DOMEventTargetHelper::GetEventHandler(nsIAtom* aType,
|
|||
}
|
||||
|
||||
nsresult
|
||||
DOMEventTargetHelper::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
DOMEventTargetHelper::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mCanHandle = true;
|
||||
aVisitor.mParentTarget = nullptr;
|
||||
|
|
|
|||
|
|
@ -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); \
|
||||
} \
|
||||
|
|
|
|||
|
|
@ -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,36 +363,48 @@ 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)
|
||||
{
|
||||
|
|
@ -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);
|
||||
targetEtci->GetEventTargetParent(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 = MayRetargetToChromeIfCanNotHandleEvent(chain, preVisitor,
|
||||
targetEtci, nullptr,
|
||||
content);
|
||||
}
|
||||
if (preVisitor.mCanHandle) {
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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,10 +184,16 @@ 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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -185,3 +185,4 @@ skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
|
|||
[test_bug687787.html]
|
||||
[test_bug1298970.html]
|
||||
[test_bug1304044.html]
|
||||
[test_bug1305458.html]
|
||||
|
|
|
|||
50
dom/events/test/test_bug1305458.html
Normal file
50
dom/events/test/test_bug1305458.html
Normal file
|
|
@ -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>
|
||||
Loading…
Add table
Add a link
Reference in a new issue