Bug 1304044 - implement auxclick r=smaug

After click events with button 2 or 3 are fired, fire auxclick, a new
event intended to represent a non-primary mouse click. Because this
event, based on the design examples and blink's implementation, is
intended to be used with content listeners, always dispatch on content
listeners--not just those that force all events to be dispatched (i.e.
document/window). This diverges from the behavior of our click events
from non-primary buttons.

Eventually, we hope this will replace click events for non-primary
buttons. For now, leave those events for compatibility reasons.

Additionally, add handling of this new event, where necessary.

MozReview-Commit-ID: 8osozM4h6Ya

--HG--
extra : rebase_source : 558261dd0d0b9241efa84ca168c50455850af03a
This commit is contained in:
Kevin Wern 2016-11-30 19:48:02 -05:00
parent ff8701836d
commit b2052e9ddc
16 changed files with 202 additions and 30 deletions

View File

@ -703,6 +703,7 @@ GK_ATOM(onattributechanged, "onattributechanged")
GK_ATOM(onattributereadreq, "onattributereadreq")
GK_ATOM(onattributewritereq, "onattributewritereq")
GK_ATOM(onaudioprocess, "onaudioprocess")
GK_ATOM(onauxclick, "onauxclick")
GK_ATOM(onbeforecopy, "onbeforecopy")
GK_ATOM(onbeforecut, "onbeforecut")
GK_ATOM(onbeforepaste, "onbeforepaste")

View File

@ -164,6 +164,10 @@ EVENT(change,
eFormChange,
EventNameType_HTMLXUL,
eBasicEventClass)
EVENT(auxclick,
eMouseAuxClick,
EventNameType_All,
eMouseEventClass)
EVENT(click,
eMouseClick,
EventNameType_All,

View File

@ -489,6 +489,7 @@ IsMessageMouseUserActivity(EventMessage aMessage)
return aMessage == eMouseMove ||
aMessage == eMouseUp ||
aMessage == eMouseDown ||
aMessage == eMouseAuxClick ||
aMessage == eMouseDoubleClick ||
aMessage == eMouseClick ||
aMessage == eMouseActivate ||
@ -4617,6 +4618,32 @@ EventStateManager::SetClickCount(WidgetMouseEvent* aEvent,
return NS_OK;
}
nsresult
EventStateManager::InitAndDispatchClickEvent(WidgetMouseEvent* aEvent,
nsEventStatus* aStatus,
EventMessage aMessage,
nsIPresShell* aPresShell,
nsIContent* aMouseTarget,
nsWeakFrame aCurrentTarget,
bool aNoContentDispatch)
{
WidgetMouseEvent event(aEvent->IsTrusted(), aMessage,
aEvent->mWidget, WidgetMouseEvent::eReal);
event.mRefPoint = aEvent->mRefPoint;
event.mClickCount = aEvent->mClickCount;
event.mModifiers = aEvent->mModifiers;
event.buttons = aEvent->buttons;
event.mTime = aEvent->mTime;
event.mTimeStamp = aEvent->mTimeStamp;
event.mFlags.mNoContentDispatch = aNoContentDispatch;
event.button = aEvent->button;
event.inputSource = aEvent->inputSource;
return aPresShell->HandleEventWithTarget(&event, aCurrentTarget,
aMouseTarget, aStatus);
}
nsresult
EventStateManager::CheckForAndDispatchClick(WidgetMouseEvent* aEvent,
nsEventStatus* aStatus)
@ -4636,17 +4663,7 @@ EventStateManager::CheckForAndDispatchClick(WidgetMouseEvent* aEvent,
(aEvent->button == WidgetMouseEvent::eMiddleButton ||
aEvent->button == WidgetMouseEvent::eRightButton);
WidgetMouseEvent event(aEvent->IsTrusted(), eMouseClick,
aEvent->mWidget, WidgetMouseEvent::eReal);
event.mRefPoint = aEvent->mRefPoint;
event.mClickCount = aEvent->mClickCount;
event.mModifiers = aEvent->mModifiers;
event.buttons = aEvent->buttons;
event.mTime = aEvent->mTime;
event.mTimeStamp = aEvent->mTimeStamp;
event.mFlags.mNoContentDispatch = notDispatchToContents;
event.button = aEvent->button;
event.inputSource = aEvent->inputSource;
bool fireAuxClick = notDispatchToContents;
nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
if (presShell) {
@ -4665,25 +4682,22 @@ EventStateManager::CheckForAndDispatchClick(WidgetMouseEvent* aEvent,
// HandleEvent clears out mCurrentTarget which we might need again
nsWeakFrame currentTarget = mCurrentTarget;
ret = presShell->HandleEventWithTarget(&event, currentTarget,
mouseContent, aStatus);
ret = InitAndDispatchClickEvent(aEvent, aStatus, eMouseClick,
presShell, mouseContent, currentTarget,
notDispatchToContents);
if (NS_SUCCEEDED(ret) && aEvent->mClickCount == 2 &&
mouseContent && mouseContent->IsInComposedDoc()) {
//fire double click
WidgetMouseEvent event2(aEvent->IsTrusted(), eMouseDoubleClick,
aEvent->mWidget, WidgetMouseEvent::eReal);
event2.mRefPoint = aEvent->mRefPoint;
event2.mClickCount = aEvent->mClickCount;
event2.mModifiers = aEvent->mModifiers;
event2.buttons = aEvent->buttons;
event2.mTime = aEvent->mTime;
event2.mTimeStamp = aEvent->mTimeStamp;
event2.mFlags.mNoContentDispatch = notDispatchToContents;
event2.button = aEvent->button;
event2.inputSource = aEvent->inputSource;
ret = presShell->HandleEventWithTarget(&event2, currentTarget,
mouseContent, aStatus);
ret = InitAndDispatchClickEvent(aEvent, aStatus, eMouseDoubleClick,
presShell, mouseContent, currentTarget,
notDispatchToContents);
}
if (NS_SUCCEEDED(ret) && mouseContent && fireAuxClick &&
mouseContent->IsInComposedDoc()) {
ret = InitAndDispatchClickEvent(aEvent, aStatus, eMouseAuxClick,
presShell, mouseContent, currentTarget,
false);
}
}
}

View File

@ -415,6 +415,13 @@ protected:
*/
void UpdateDragDataTransfer(WidgetDragEvent* dragEvent);
static nsresult InitAndDispatchClickEvent(WidgetMouseEvent* aEvent,
nsEventStatus* aStatus,
EventMessage aMessage,
nsIPresShell* aPresShell,
nsIContent* aMouseTarget,
nsWeakFrame aCurrentTarget,
bool aNoContentDispatch);
nsresult SetClickCount(WidgetMouseEvent* aEvent, nsEventStatus* aStatus);
nsresult CheckForAndDispatchClick(WidgetMouseEvent* aEvent,
nsEventStatus* aStatus);
@ -1044,6 +1051,7 @@ private:
#define NS_EVENT_NEEDS_FRAME(event) \
(!(event)->HasPluginActivationEventMessage() && \
(event)->mMessage != eMouseClick && \
(event)->mMessage != eMouseDoubleClick)
(event)->mMessage != eMouseDoubleClick && \
(event)->mMessage != eMouseAuxClick)
#endif // mozilla_EventStateManager_h_

View File

@ -257,6 +257,7 @@ WheelTransaction::OnEvent(WidgetEvent* aEvent)
case eMouseUp:
case eMouseDown:
case eMouseDoubleClick:
case eMouseAuxClick:
case eMouseClick:
case eContextMenu:
case eDrop:

View File

@ -184,3 +184,4 @@ skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
[test_bug687787.html]
[test_bug1305458.html]
[test_bug1298970.html]
[test_bug1304044.html]

View File

@ -0,0 +1,133 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1304044
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1304044</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
var eventsFired = [];
var target;
var eventsExpected;
function GetNodeString(node) {
if (node == window)
return "window";
if (node == document)
return "document";
if (node.id)
return node.id;
if (node.nodeName)
return node.nodeName;
return node;
}
function TargetAndListener(listener, target) {
this.listener = listener;
this.target = target;
}
TargetAndListener.prototype.toString = function() {
var targetName = GetNodeString(this.target);
var listenerName = GetNodeString(this.listener);
return "(listener: " + listenerName + ", target: " + targetName + ")";
}
var tests = [
TestAuxClickBubblesForEventListener,
TestAuxClickBubblesForOnAuxClick,
];
function CompareEvents(evt, expected) {
return evt && expected && evt.listener == expected.listener &&
evt.target == expected.target;
}
function ResetEventsFired() {
eventsFired = [];
}
function ClearEventListeners() {
for (i in arguments) {
arguments[i].removeEventListener("auxclick", log_event);
}
}
function ClickTarget(tgt) {
synthesizeMouseAtCenter(tgt, {type : "mousedown", button: 2}, window);
synthesizeMouseAtCenter(tgt, {type : "mouseup", button: 2}, window);
}
function log_event(e) {
eventsFired[eventsFired.length] = new TargetAndListener(this, e.target);
}
function CompareEventsToExpected(expected, actual) {
for (var i = 0; i < expected.length || i < actual.length; i++) {
ok(CompareEvents(actual[i], expected[i]),
"Auxclick receiver's don't match: TargetAndListener " +
i + ": Expected: " + expected[i] + ", Actual: " + actual[i]);
}
}
function TestAuxClickBubblesForEventListener() {
target.addEventListener("auxclick", log_event);
document.addEventListener("auxclick", log_event);
window.addEventListener("auxclick", log_event);
ClickTarget(target)
CompareEventsToExpected(eventsExpected, eventsFired);
ResetEventsFired();
ClearEventListeners(target, document, window);
}
function TestAuxClickBubblesForOnAuxClick() {
target.onauxclick = log_event;
document.onauxclick = log_event;
window.onauxclick = log_event;
ClickTarget(target);
CompareEventsToExpected(eventsExpected, eventsFired);
ResetEventsFired();
}
function RunTests(){
for (var i = 0; i < tests.length; i++) {
tests[i]();
}
}
function Begin() {
target = document.getElementById("target");
eventsExpected = [
new TargetAndListener(target, target),
new TargetAndListener(document, target),
new TargetAndListener(window, target),
];
RunTests();
target.remove();
SimpleTest.finish();
}
window.onload = function() {
SimpleTest.waitForExplicitFinish();
SimpleTest.executeSoon(Begin);
}
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1304044">Mozilla Bug 1304044</a>
<p id="display">
<div id="target">Target</div>
</p>
<div id="content" style:"display:none">
</div>
<pre id="test">
</pre>
</body>
</html>

View File

@ -2532,6 +2532,7 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent)
NS_ASSERTION(anEvent.mMessage == eMouseDown ||
anEvent.mMessage == eMouseUp ||
anEvent.mMessage == eMouseDoubleClick ||
anEvent.mMessage == eMouseAuxClick ||
anEvent.mMessage == eMouseOver ||
anEvent.mMessage == eMouseOut ||
anEvent.mMessage == eMouseMove ||
@ -2594,6 +2595,7 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent)
switch (anEvent.mMessage) {
case eMouseClick:
case eMouseDoubleClick:
case eMouseAuxClick:
// Button up/down events sent instead.
return rv;
default:
@ -2797,6 +2799,7 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent)
switch (anEvent.mMessage) {
case eMouseClick:
case eMouseDoubleClick:
case eMouseAuxClick:
// Button up/down events sent instead.
return rv;
default:

View File

@ -33,6 +33,7 @@ interface GlobalEventHandlers {
// attribute OnErrorEventHandler onerror;
attribute EventHandler onfocus;
//(Not implemented)attribute EventHandler oncancel;
attribute EventHandler onauxclick;
attribute EventHandler oncanplay;
attribute EventHandler oncanplaythrough;
attribute EventHandler onchange;

View File

@ -1277,7 +1277,7 @@ nsXULElement::IsEventStoppedFromAnonymousScrollbar(EventMessage aMessage)
IsAnyOfXULElements(nsGkAtoms::scrollbar, nsGkAtoms::scrollcorner) &&
(aMessage == eMouseClick || aMessage == eMouseDoubleClick ||
aMessage == eXULCommand || aMessage == eContextMenu ||
aMessage == eDragStart));
aMessage == eDragStart || aMessage == eMouseAuxClick));
}
nsresult

View File

@ -1145,6 +1145,7 @@ APZCTreeManager::UpdateWheelTransaction(LayoutDeviceIntPoint aRefPoint,
case eMouseUp:
case eMouseDown:
case eMouseDoubleClick:
case eMouseAuxClick:
case eMouseClick:
case eContextMenu:
case eDrop:

View File

@ -595,6 +595,7 @@ public:
case eMouseEventClass:
mFlags.mComposed = mMessage == eMouseClick ||
mMessage == eMouseDoubleClick ||
mMessage == eMouseAuxClick ||
mMessage == eMouseDown || mMessage == eMouseUp ||
mMessage == eMouseEnter || mMessage == eMouseLeave ||
mMessage == eMouseOver || mMessage == eMouseOut ||

View File

@ -84,6 +84,7 @@ NS_EVENT_MESSAGE(eMouseEnterIntoWidget)
NS_EVENT_MESSAGE(eMouseExitFromWidget)
NS_EVENT_MESSAGE(eMouseDoubleClick)
NS_EVENT_MESSAGE(eMouseClick)
NS_EVENT_MESSAGE(eMouseAuxClick)
// eMouseActivate is fired when the widget is activated by a click.
NS_EVENT_MESSAGE(eMouseActivate)
NS_EVENT_MESSAGE(eMouseOver)

View File

@ -236,6 +236,7 @@ WidgetEvent::HasMouseEventMessage() const
case eMouseUp:
case eMouseClick:
case eMouseDoubleClick:
case eMouseAuxClick:
case eMouseEnterIntoWidget:
case eMouseExitFromWidget:
case eMouseActivate:

View File

@ -3086,6 +3086,7 @@ case _value: eventName.AssignLiteral(_name) ; break
_ASSIGN_eventName(eMouseDown,"eMouseDown");
_ASSIGN_eventName(eMouseUp,"eMouseUp");
_ASSIGN_eventName(eMouseClick,"eMouseClick");
_ASSIGN_eventName(eMouseAuxClick,"eMouseAuxClick");
_ASSIGN_eventName(eMouseDoubleClick,"eMouseDoubleClick");
_ASSIGN_eventName(eMouseMove,"eMouseMove");
_ASSIGN_eventName(eLoad,"eLoad");

View File

@ -1143,7 +1143,8 @@ WinUtils::GetIsMouseFromTouch(EventMessage aEventMessage)
const uint32_t MOZ_T_I_SIGNATURE = TABLET_INK_TOUCH | TABLET_INK_SIGNATURE;
const uint32_t MOZ_T_I_CHECK_TCH = TABLET_INK_TOUCH | TABLET_INK_CHECK;
return ((aEventMessage == eMouseMove || aEventMessage == eMouseDown ||
aEventMessage == eMouseUp || aEventMessage == eMouseDoubleClick) &&
aEventMessage == eMouseUp || aEventMessage == eMouseAuxClick ||
aEventMessage == eMouseDoubleClick) &&
(GetMessageExtraInfo() & MOZ_T_I_SIGNATURE) == MOZ_T_I_CHECK_TCH);
}