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:
Matt A. Tobin 2020-04-14 21:24:51 -04:00 committed by Roy Tam
commit cb2b45e472
70 changed files with 547 additions and 258 deletions

View file

@ -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);
}