From 4354c7a1bceb484e80001fe82e3c723e6a413918 Mon Sep 17 00:00:00 2001 From: Martok Date: Sun, 27 Nov 2022 16:35:38 +0100 Subject: [PATCH] Issue #2030 - Allow child nodes of button to participate in mouse hit tests This is needed for web compatibility, even if standards compliance is debatable. --- dom/html/HTMLButtonElement.cpp | 7 +++-- dom/html/HTMLInputElement.cpp | 33 +++++++++++++---------- layout/forms/nsHTMLButtonControlFrame.cpp | 4 +-- widget/BasicEvents.h | 2 ++ 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/dom/html/HTMLButtonElement.cpp b/dom/html/HTMLButtonElement.cpp index e493d1891d..e3fdbb4d32 100644 --- a/dom/html/HTMLButtonElement.cpp +++ b/dom/html/HTMLButtonElement.cpp @@ -221,11 +221,14 @@ HTMLButtonElement::GetEventTargetParent(EventChainPreVisitor& aVisitor) bool outerActivateEvent = ((mouseEvent && mouseEvent->IsLeftClickEvent()) || (aVisitor.mEvent->mMessage == eLegacyDOMActivate && - !mInInternalActivate)); + !mInInternalActivate && + aVisitor.mEvent->mOriginalTarget == this)); if (outerActivateEvent) { aVisitor.mItemFlags |= NS_OUTER_ACTIVATE_EVENT; - if (mType == NS_FORM_BUTTON_SUBMIT && mForm) { + if (mType == NS_FORM_BUTTON_SUBMIT && mForm && + !aVisitor.mEvent->mFlags.mMultiplePreActionsPrevented) { + aVisitor.mEvent->mFlags.mMultiplePreActionsPrevented = true; aVisitor.mItemFlags |= NS_IN_SUBMIT_CLICK; // tell the form that we are about to enter a click handler. // that means that if there are scripted submissions, the diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index 557e673e15..2f4ee84a49 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -143,11 +143,14 @@ namespace dom { #define NS_ORIGINAL_CHECKED_VALUE (1 << 10) #define NS_NO_CONTENT_DISPATCH (1 << 11) #define NS_ORIGINAL_INDETERMINATE_VALUE (1 << 12) -#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) +#define NS_IN_SUBMIT_CLICK (1 << 15) +#define NS_CONTROL_TYPE(bits) \ + ((bits) & ~(NS_OUTER_ACTIVATE_EVENT | NS_ORIGINAL_CHECKED_VALUE | \ + NS_NO_CONTENT_DISPATCH | NS_ORIGINAL_INDETERMINATE_VALUE | \ + NS_PRE_HANDLE_BLUR_EVENT | NS_PRE_HANDLE_INPUT_EVENT | \ + NS_IN_SUBMIT_CLICK)) // whether textfields should be selected once focused: // -1: no, 1: yes, 0: uninitialized @@ -3800,7 +3803,10 @@ HTMLInputElement::GetEventTargetParent(EventChainPreVisitor& aVisitor) case NS_FORM_INPUT_SUBMIT: case NS_FORM_INPUT_IMAGE: - if (mForm) { + if (mForm && !aVisitor.mEvent->mFlags.mMultiplePreActionsPrevented) { + // Make sure other submit elements don't try to trigger submission. + aVisitor.mEvent->mFlags.mMultiplePreActionsPrevented = true; + aVisitor.mItemFlags |= NS_IN_SUBMIT_CLICK; // tell the form that we are about to enter a click handler. // that means that if there are scripted submissions, the // latest one will be deferred until after the exit point of the handler. @@ -4394,17 +4400,15 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) } } - if (outerActivateEvent) { + if ((aVisitor.mItemFlags & NS_IN_SUBMIT_CLICK) && mForm) { switch(oldType) { case NS_FORM_INPUT_SUBMIT: case NS_FORM_INPUT_IMAGE: - if (mForm) { - // tell the form that we are about to exit a click handler - // so the form knows not to defer subsequent submissions - // the pending ones that were created during the handler - // will be flushed or forgoten. - mForm->OnSubmitClickEnd(); - } + // tell the form that we are about to exit a click handler + // so the form knows not to defer subsequent submissions + // the pending ones that were created during the handler + // will be flushed or forgoten. + mForm->OnSubmitClickEnd(); break; default: break; @@ -4770,7 +4774,8 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) if (outerActivateEvent) { if (mForm && (oldType == NS_FORM_INPUT_SUBMIT || oldType == NS_FORM_INPUT_IMAGE)) { - if (mType != NS_FORM_INPUT_SUBMIT && mType != NS_FORM_INPUT_IMAGE) { + if (mType != NS_FORM_INPUT_SUBMIT && mType != NS_FORM_INPUT_IMAGE && + aVisitor.mItemFlags & NS_IN_SUBMIT_CLICK) { // If the type has changed to a non-submit type, then we want to // flush the stored submission if there is one (as if the submit() // was allowed to succeed) @@ -4809,7 +4814,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) break; } //switch } //click or outer activate event - } else if (outerActivateEvent && + } else if ((aVisitor.mItemFlags & NS_IN_SUBMIT_CLICK) && (oldType == NS_FORM_INPUT_SUBMIT || oldType == NS_FORM_INPUT_IMAGE) && mForm) { diff --git a/layout/forms/nsHTMLButtonControlFrame.cpp b/layout/forms/nsHTMLButtonControlFrame.cpp index 1ec0ec6c94..d1fbfbabd7 100644 --- a/layout/forms/nsHTMLButtonControlFrame.cpp +++ b/layout/forms/nsHTMLButtonControlFrame.cpp @@ -118,8 +118,8 @@ nsHTMLButtonControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, nsDisplayListCollection set(aBuilder); - // Do not allow the child subtree to receive events. - if (!isForEventDelivery) { + // HTMLInputElement buttons are opaque to hit tests, HTMLButtonElement buttons are not. + if (!(isForEventDelivery && this->IsInput())) { DisplayListClipState::AutoSaveRestore clipState(aBuilder); if (ShouldClipPaintingToBorderBox()) { diff --git a/widget/BasicEvents.h b/widget/BasicEvents.h index 0ce0f587dd..9631dfd257 100644 --- a/widget/BasicEvents.h +++ b/widget/BasicEvents.h @@ -80,6 +80,8 @@ public: // the first