moebius#71: DOM - Pointer Events - improvements

https://github.com/MoonchildProductions/moebius/pull/71
This commit is contained in:
janekptacijarabaci
2018-04-20 22:18:52 +02:00
committed by Roy Tam
parent 10e5833dce
commit 40c62c205b
23 changed files with 293 additions and 429 deletions
+18 -34
View File
@@ -731,6 +731,9 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
FlushPendingEvents(aPresContext);
break;
}
case ePointerGotCapture:
GenerateMouseEnterExit(mouseEvent);
break;
case eDragStart:
if (Prefs::ClickHoldContextMenu()) {
// an external drag gesture event came in, not generated internally
@@ -3890,10 +3893,7 @@ CreateMouseOrPointerWidgetEvent(WidgetMouseEvent* aMouseEvent,
newPointerEvent->mWidth = sourcePointer->mWidth;
newPointerEvent->mHeight = sourcePointer->mHeight;
newPointerEvent->inputSource = sourcePointer->inputSource;
newPointerEvent->relatedTarget =
nsIPresShell::GetPointerCapturingContent(sourcePointer->pointerId)
? nullptr
: aRelatedContent;
newPointerEvent->relatedTarget = aRelatedContent;
aNewEvent = newPointerEvent.forget();
} else {
aNewEvent =
@@ -4106,14 +4106,8 @@ EventStateManager::NotifyMouseOut(WidgetMouseEvent* aMouseEvent,
SetContentState(nullptr, NS_EVENT_STATE_HOVER);
}
// In case we go out from capturing element (retargetedByPointerCapture is true)
// we should dispatch ePointerLeave event and only for capturing element.
RefPtr<nsIContent> movingInto = aMouseEvent->retargetedByPointerCapture
? wrapper->mLastOverElement->GetParent()
: aMovingInto;
EnterLeaveDispatcher leaveDispatcher(this, wrapper->mLastOverElement,
movingInto, aMouseEvent,
aMovingInto, aMouseEvent,
isPointer ? ePointerLeave : eMouseLeave);
// Fire mouseout
@@ -4134,13 +4128,9 @@ EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
{
NS_ASSERTION(aContent, "Mouse must be over something");
// If pointer capture is set, we should suppress pointerover/pointerenter events
// for all elements except element which have pointer capture.
bool dispatch = !aMouseEvent->retargetedByPointerCapture;
OverOutElementsWrapper* wrapper = GetWrapperByEventID(aMouseEvent);
if (wrapper->mLastOverElement == aContent && dispatch)
if (wrapper->mLastOverElement == aContent)
return;
// Before firing mouseover, check for recursion
@@ -4163,7 +4153,7 @@ EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
}
// Firing the DOM event in the parent document could cause all kinds
// of havoc. Reverify and take care.
if (wrapper->mLastOverElement == aContent && dispatch)
if (wrapper->mLastOverElement == aContent)
return;
// Remember mLastOverElement as the related content for the
@@ -4172,11 +4162,9 @@ EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
bool isPointer = aMouseEvent->mClass == ePointerEventClass;
Maybe<EnterLeaveDispatcher> enterDispatcher;
if (dispatch) {
enterDispatcher.emplace(this, aContent, lastOverElement, aMouseEvent,
isPointer ? ePointerEnter : eMouseEnter);
}
EnterLeaveDispatcher enterDispatcher(this, aContent, lastOverElement,
aMouseEvent,
isPointer ? ePointerEnter : eMouseEnter);
NotifyMouseOut(aMouseEvent, aContent);
@@ -4188,18 +4176,13 @@ EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
SetContentState(aContent, NS_EVENT_STATE_HOVER);
}
if (dispatch) {
// Fire mouseover
wrapper->mLastOverFrame =
DispatchMouseOrPointerEvent(aMouseEvent,
isPointer ? ePointerOver : eMouseOver,
aContent, lastOverElement);
enterDispatcher->Dispatch();
wrapper->mLastOverElement = aContent;
} else {
wrapper->mLastOverFrame = nullptr;
wrapper->mLastOverElement = nullptr;
}
// Fire mouseover
wrapper->mLastOverFrame =
DispatchMouseOrPointerEvent(aMouseEvent,
isPointer ? ePointerOver : eMouseOver,
aContent, lastOverElement);
enterDispatcher.Dispatch();
wrapper->mLastOverElement = aContent;
// Turn recursion protection back off
wrapper->mFirstOverEventElement = nullptr;
@@ -4292,6 +4275,7 @@ EventStateManager::GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent)
MOZ_FALLTHROUGH;
case ePointerMove:
case ePointerDown:
case ePointerGotCapture:
{
// Get the target content target (mousemove target == mouseover target)
nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
+14
View File
@@ -93,8 +93,10 @@ PointerEvent::Constructor(EventTarget* aOwner,
widgetEvent->mWidth = aParam.mWidth;
widgetEvent->mHeight = aParam.mHeight;
widgetEvent->pressure = aParam.mPressure;
widgetEvent->tangentialPressure = aParam.mTangentialPressure;
widgetEvent->tiltX = aParam.mTiltX;
widgetEvent->tiltY = aParam.mTiltY;
widgetEvent->twist = aParam.mTwist;
widgetEvent->inputSource = ConvertStringToPointerType(aParam.mPointerType);
widgetEvent->mIsPrimary = aParam.mIsPrimary;
widgetEvent->buttons = aParam.mButtons;
@@ -145,6 +147,12 @@ PointerEvent::Pressure()
return mEvent->AsPointerEvent()->pressure;
}
float
PointerEvent::TangentialPressure()
{
return mEvent->AsPointerEvent()->tangentialPressure;
}
int32_t
PointerEvent::TiltX()
{
@@ -157,6 +165,12 @@ PointerEvent::TiltY()
return mEvent->AsPointerEvent()->tiltY;
}
int32_t
PointerEvent::Twist()
{
return mEvent->AsPointerEvent()->twist;
}
bool
PointerEvent::IsPrimary()
{
+2
View File
@@ -44,8 +44,10 @@ public:
int32_t Width();
int32_t Height();
float Pressure();
float TangentialPressure();
int32_t TiltX();
int32_t TiltY();
int32_t Twist();
bool IsPrimary();
void GetPointerType(nsAString& aPointerType);
};
@@ -148,5 +148,6 @@ support-files =
support-files = bug1293174_implicit_pointer_capture_for_touch_1.html
[test_bug1293174_implicit_pointer_capture_for_touch_2.html]
support-files = bug1293174_implicit_pointer_capture_for_touch_2.html
[test_bug1323158.html]
[test_empty_file.html]
disabled = disabled # Bug 1150091 - Issue with support-files
@@ -12,20 +12,24 @@
<script type="text/javascript" src="pointerevent_support.js"></script>
<script type="text/javascript" src="mochitest_support_internal.js"></script>
<script type="text/javascript">
var test_pointerEvent;
var detected_pointertypes = {};
var test_pointerEvent = async_test("lostpointercapture: subsequent events to target."); // set up test harness
// showPointerTypes is defined in pointerevent_support.js
// Requirements: the callback function will reference the test_pointerEvent object and
// will fail unless the async_test is created with the var name "test_pointerEvent".
add_completion_callback(showPointerTypes);
var captured_event;
var captured_event = null;
var test_done = false;
var overEnterEventsFail = false;
var outLeaveEventsFail = false;
var f_gotPointerCapture = false;
var f_lostPointerCapture = false;
function resetTestState() {
captured_event = null;
test_done = false;
overEnterEventsFail = false;
outLeaveEventsFail = false;
f_gotPointerCapture = false;
f_lostPointerCapture = false;
}
function listenerEventHandler(event) {
if (test_done)
return;
@@ -40,10 +44,10 @@
check_PointerEvent(event);
}
else if(event.type == "pointerover" || event.type == "pointerenter") {
if(!overEnterEventsFail) {
if(captured_event && !overEnterEventsFail) {
test(function() {
assert_true(f_gotPointerCapture, "pointerover/enter should not be received when the target doesn't have capture and pointer is not over it.");
}, "pointerover/enter should not be received when the target doesn't have capture and pointer is not over it.");
assert_false(f_gotPointerCapture, "pointerover/enter should be received before the target receives gotpointercapture even when the pointer is not over it.");
}, expectedPointerType + " pointerover/enter should be received before the target receives gotpointercapture even when the pointer is not over it.");
overEnterEventsFail = true;
}
}
@@ -51,7 +55,7 @@
if(!outLeaveEventsFail) {
test(function() {
assert_true(f_lostPointerCapture, "pointerout/leave should not be received unless the target just lost the capture.");
}, "pointerout/leave should not be received unless the target just lost the capture.");
}, expectedPointerType + " pointerout/leave should not be received unless the target just lost the capture.");
outLeaveEventsFail = true;
}
}
@@ -64,7 +68,7 @@
// if any other events are received after releaseCapture, then the test fails
test(function () {
assert_unreached(event.target.id + "-" + event.type + " should be handled by target element handler");
}, "No other events should be recieved by capturing node after release");
}, expectedPointerType + " No other events should be recieved by capturing node after release");
}
}
}
@@ -76,7 +80,7 @@
if(event.type != "pointerout" && event.type != "pointerleave") {
test(function () {
assert_unreached("The Target element should not have received any events while capture is active. Event recieved:" + event.type + ". ");
}, "The target element should not receive any events while capture is active");
}, expectedPointerType + " The target element should not receive any events while capture is active");
}
}
@@ -91,13 +95,14 @@
assert_equals(event.pointerId, captured_event.pointerId, "pointerID is same for event captured and after release");
});
if (event.type == "pointerup") {
test_pointerEvent.done(); // complete test
test_done = true;
test_pointerEvent.done(); // complete test
}
}
}
function run() {
test_pointerEvent = setup_pointerevent_test("got/lost pointercapture: subsequent events to target", ALL_POINTERS); // set up test harness
var listener = document.getElementById("listener");
var target0 = document.getElementById("target0");
target0.style["touchAction"] = "none";
@@ -111,18 +116,19 @@
</script>
</head>
<body onload="run()">
<h2 id="pointerTypeDescription"></h2>
<div id="listener"></div>
<h1>Pointer Event: releasePointerCapture() - subsequent events follow normal hitting testing mechanisms</h1>
<!--
<h4>
Test Description:
Use your pointer and press down in the black box. Then move around in the box and release your pointer.
After invoking the releasePointerCapture method on an element, subsequent events for the specified
pointer must follow normal hit testing mechanisms for determining the event target
pointer must follow normal hit testing mechanisms for determining the event target.
</h4>
<br />
-->
<div id="target0">
Use mouse, touch or pen to contact here and move around.
</div>
<div id="complete-notice">
<p>Test complete: Scroll to Summary to view Pass/Fail Results.</p>
@@ -13,7 +13,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1285128
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1285128">Mozilla Bug 1285128</a>
<p id="display"></p>
<div id="target0" style="width: 200px; height: 200px; background: green"></div>
<div id="target0" style="width: 50px; height: 50px; background: green"></div>
<div id="target1" style="width: 50px; height: 50px; background: red"></div>
<script type="text/javascript">
/** Test for Bug 1285128 **/
@@ -31,7 +32,7 @@ function runTests() {
}, false);
});
target0.addEventListener("mouseenter", () => {
target1.addEventListener("mouseup", () => {
ok(!receivedPointerEvents, "synthesized mousemove should not trigger any pointer events");
SimpleTest.finish();
});
@@ -39,6 +40,8 @@ function runTests() {
synthesizeMouseAtCenter(target0, { type: "mousemove",
inputSource: SpecialPowers.Ci.nsIDOMMouseEvent.MOZ_SOURCE_MOUSE,
isWidgetEventSynthesized: true });
synthesizeMouseAtCenter(target1, { type: "mousedown" });
synthesizeMouseAtCenter(target1, { type: "mouseup" });
}
SpecialPowers.pushPrefEnv({"set": [["dom.w3c_pointer_events.enabled", true]]}, runTests);
@@ -0,0 +1,93 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1323158
-->
<head>
<meta charset="utf-8">
<title>This is a test to check if target and relatedTarget of mouse events are the same as pointer events</title>
<script type="text/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"/>
</head>
<body>
<p id="content"></p>
<script type="text/javascript">
/** Test for Bug 1323158 **/
SimpleTest.waitForExplicitFinish();
function runTests() {
let content = document.getElementById('content');
let iframe = document.createElement('iframe');
iframe.width = 500;
iframe.height = 500;
content.appendChild(iframe);
iframe.contentDocument.body.innerHTML =
"<br><div id='target0' style='width: 30px; height: 30px; background: black;'></div>" +
"<br><div id='target1' style='width: 30px; height: 30px; background: red;'></div>" +
"<br><div id='done' style='width: 30px; height: 30px; background: green;'></div>";
let target0 = iframe.contentDocument.getElementById("target0");
let target1 = iframe.contentDocument.getElementById("target1");
let done = iframe.contentDocument.getElementById("done");
let pointerBoundaryEvents = ["pointerover", "pointerenter", "pointerleave", "pointerout"];
let mouseBoundaryEvents = ["mouseover", "mouseenter", "mouseleave", "mouseout"];
let receivedPointerBoundaryEvents = {};
let mouseEvent2pointerEvent = {"mouseover": "pointerover",
"mouseenter": "pointerenter",
"mouseleave": "pointerleave",
"mouseout": "pointerout"
};
pointerBoundaryEvents.forEach((event) => {
target1.addEventListener(event, (e) => {
receivedPointerBoundaryEvents[event] = e;
});
});
let attributes = ["target", "relatedTarget"];
mouseBoundaryEvents.forEach((event) => {
target1.addEventListener(event, (e) => {
let correspondingPointerEv = receivedPointerBoundaryEvents[mouseEvent2pointerEvent[event]];
ok(correspondingPointerEv, "Should receive " + mouseEvent2pointerEvent[event] + " before " + e.type);
if (correspondingPointerEv) {
attributes.forEach((attr) => {
ok(correspondingPointerEv[attr] == e[attr],
attr + " of " + e.type + " should be the same as the correcponding pointer event expect " +
correspondingPointerEv[attr] + " got " + e[attr]);
});
}
receivedPointerBoundaryEvents[mouseEvent2pointerEvent[event]] = null;
});
});
target0.addEventListener("pointerdown", (e) => {
target1.setPointerCapture(e.pointerId);
});
done.addEventListener("mouseup", () => {
SimpleTest.finish();
});
let source = SpecialPowers.Ci.nsIDOMMouseEvent.MOZ_SOURCE_MOUSE;
synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: source },
iframe.contentWindow);
synthesizeMouse(target0, 5, 5, { type: "mousedown", inputSource: source },
iframe.contentWindow);
synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: source },
iframe.contentWindow);
synthesizeMouse(target0, 5, 5, { type: "mouseup", inputSource: source },
iframe.contentWindow);
synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: source },
iframe.contentWindow);
synthesizeMouse(done, 5, 5, { type: "mousedown", inputSource: source },
iframe.contentWindow);
synthesizeMouse(done, 5, 5, { type: "mouseup", inputSource: source },
iframe.contentWindow);
}
SimpleTest.waitForFocus(() => {
SpecialPowers.pushPrefEnv({"set": [["dom.w3c_pointer_events.enabled", true]]}, runTests);
});
</script>
</body>
</html>
@@ -19,6 +19,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
function executeTest(int_win) {
sendMouseEvent(int_win, "target0", "mousemove");
sendMouseEvent(int_win, "target1", "mousemove");
sendMouseEvent(int_win, "btnCapture", "mousemove");
sendMouseEvent(int_win, "btnCapture", "mousedown");
sendMouseEvent(int_win, "target1", "mousemove");
sendMouseEvent(int_win, "target0", "mousemove");
@@ -17,9 +17,30 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
runTestInNewWindow("pointerevent_releasepointercapture_events_to_original_target-manual.html");
}
function executeTest(int_win) {
sendTouchEvent(int_win, "target0", "touchstart");
sendTouchEvent(int_win, "target0", "touchmove");
sendTouchEvent(int_win, "target0", "touchend");
// Synthesize mouse events to run this test.
sendMouseEvent(int_win, "target0", "mousemove");
sendMouseEvent(int_win, "target0", "mousedown");
sendMouseEvent(int_win, "target0", "mousemove", {buttons: 1});
sendMouseEvent(int_win, "target0", "mousemove", {buttons: 1});
sendMouseEvent(int_win, "target0", "mouseup");
window.addEventListener("message", function(aEvent) {
if (aEvent.data == "Test Touch") {
// Synthesize touch events to run this test.
sendTouchEvent(int_win, "target0", "touchstart");
sendTouchEvent(int_win, "target0", "touchmove");
sendTouchEvent(int_win, "target0", "touchend");
window.postMessage("Test Pen", "*");
} else if (aEvent.data == "Test Pen") {
// Synthesize pen events to run this test.
sendMouseEvent(int_win, "target0", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
sendMouseEvent(int_win, "target0", "mousedown", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
sendMouseEvent(int_win, "target0", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_PEN, buttons: 1});
sendMouseEvent(int_win, "target0", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_PEN, buttons: 1});
sendMouseEvent(int_win, "target0", "mouseup", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
}
});
window.postMessage("Test Touch", "*");
}
</script>
</head>
@@ -19,8 +19,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
function executeTest(int_win) {
sendMouseEvent(int_win, "target1", "mousemove");
sendMouseEvent(int_win, "btnCapture", "mousedown");
sendMouseEvent(int_win, "target1", "mousemove");
sendMouseEvent(int_win, "target1", "mouseup");
sendMouseEvent(int_win, "btnCapture", "mousemove");
sendMouseEvent(int_win, "btnCapture", "mouseup");
}
</script>
</head>
+4
View File
@@ -17,8 +17,10 @@ interface PointerEvent : MouseEvent
readonly attribute long width;
readonly attribute long height;
readonly attribute float pressure;
readonly attribute float tangentialPressure;
readonly attribute long tiltX;
readonly attribute long tiltY;
readonly attribute long twist;
readonly attribute DOMString pointerType;
readonly attribute boolean isPrimary;
};
@@ -29,8 +31,10 @@ dictionary PointerEventInit : MouseEventInit
long width = 1;
long height = 1;
float pressure = 0;
float tangentialPressure = 0;
long tiltX = 0;
long tiltY = 0;
long twist = 0;
DOMString pointerType = "";
boolean isPrimary = false;
};
+7 -7
View File
@@ -1298,11 +1298,11 @@ public:
}
};
static void DispatchGotOrLostPointerCaptureEvent(bool aIsGotCapture,
uint32_t aPointerId,
uint16_t aPointerType,
bool aIsPrimary,
nsIContent* aCaptureTarget);
static void DispatchGotOrLostPointerCaptureEvent(
bool aIsGotCapture,
const mozilla::WidgetPointerEvent* aPointerEvent,
nsIContent* aCaptureTarget);
static PointerCaptureInfo* GetPointerCaptureInfo(uint32_t aPointerId);
static void SetPointerCapturingContent(uint32_t aPointerId,
nsIContent* aContent);
@@ -1311,8 +1311,8 @@ public:
// CheckPointerCaptureState checks cases, when got/lostpointercapture events
// should be fired.
static void CheckPointerCaptureState(uint32_t aPointerId,
uint16_t aPointerType, bool aIsPrimary);
static void CheckPointerCaptureState(
const mozilla::WidgetPointerEvent* aPointerEvent);
// GetPointerInfo returns true if pointer with aPointerId is situated in
// device, false otherwise.
+68 -72
View File
@@ -6514,10 +6514,11 @@ nsIPresShell::GetPointerCapturingContent(uint32_t aPointerId)
}
/* static */ void
nsIPresShell::CheckPointerCaptureState(uint32_t aPointerId,
uint16_t aPointerType, bool aIsPrimary)
nsIPresShell::CheckPointerCaptureState(const WidgetPointerEvent* aPointerEvent)
{
PointerCaptureInfo* captureInfo = GetPointerCaptureInfo(aPointerId);
PointerCaptureInfo* captureInfo =
GetPointerCaptureInfo(aPointerEvent->pointerId);
if (captureInfo &&
captureInfo->mPendingContent != captureInfo->mOverrideContent) {
// cache captureInfo->mPendingContent since it may be changed in the pointer
@@ -6525,17 +6526,16 @@ nsIPresShell::CheckPointerCaptureState(uint32_t aPointerId,
nsIContent* pendingContent = captureInfo->mPendingContent.get();
if (captureInfo->mOverrideContent) {
DispatchGotOrLostPointerCaptureEvent(/* aIsGotCapture */ false,
aPointerId, aPointerType, aIsPrimary,
aPointerEvent,
captureInfo->mOverrideContent);
}
if (pendingContent) {
DispatchGotOrLostPointerCaptureEvent(/* aIsGotCapture */ true, aPointerId,
aPointerType, aIsPrimary,
pendingContent);
DispatchGotOrLostPointerCaptureEvent(/* aIsGotCapture */ true,
aPointerEvent, pendingContent);
}
captureInfo->mOverrideContent = pendingContent;
if (captureInfo->Empty()) {
sPointerCaptureList->Remove(aPointerId);
sPointerCaptureList->Remove(aPointerEvent->pointerId);
}
}
}
@@ -6976,37 +6976,30 @@ DispatchPointerFromMouseOrTouch(PresShell* aShell,
return NS_OK;
}
class ReleasePointerCaptureCaller
class ReleasePointerCaptureCaller final
{
public:
ReleasePointerCaptureCaller() :
mPointerId(0),
mPointerType(nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN),
mIsPrimary(false),
mIsSet(false)
ReleasePointerCaptureCaller()
: mPointerEvent(nullptr)
{
}
~ReleasePointerCaptureCaller()
{
if (mIsSet) {
nsIPresShell::ReleasePointerCapturingContent(mPointerId);
nsIPresShell::CheckPointerCaptureState(mPointerId, mPointerType,
mIsPrimary);
if (mPointerEvent) {
nsIPresShell::ReleasePointerCapturingContent(mPointerEvent->pointerId);
nsIPresShell::CheckPointerCaptureState(mPointerEvent);
}
}
void SetTarget(uint32_t aPointerId, uint16_t aPointerType, bool aIsPrimary)
void SetTarget(const WidgetPointerEvent* aPointerEvent)
{
mPointerId = aPointerId;
mPointerType = aPointerType;
mIsPrimary = aIsPrimary;
mIsSet = true;
MOZ_ASSERT(aPointerEvent);
mPointerEvent = aPointerEvent;
}
private:
int32_t mPointerId;
uint16_t mPointerType;
bool mIsPrimary;
bool mIsSet;
// This is synchronously used inside PresShell::HandleEvent.
const WidgetPointerEvent* mPointerEvent;
};
static bool
@@ -7719,9 +7712,7 @@ PresShell::HandleEvent(nsIFrame* aFrame,
nsWeakFrame frameKeeper(frame);
// Handle pending pointer capture before any pointer events except
// gotpointercapture / lostpointercapture.
CheckPointerCaptureState(pointerEvent->pointerId,
pointerEvent->inputSource,
pointerEvent->mIsPrimary);
CheckPointerCaptureState(pointerEvent);
// Prevent application crashes, in case damaged frame.
if (!frameKeeper.IsAlive()) {
frame = nullptr;
@@ -7742,33 +7733,29 @@ PresShell::HandleEvent(nsIFrame* aFrame,
}
}
if (aEvent->mClass == ePointerEventClass &&
aEvent->mMessage != ePointerDown) {
if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
uint32_t pointerId = pointerEvent->pointerId;
// Mouse events should be fired to the same target as their mapped pointer
// events
if ((aEvent->mClass == ePointerEventClass ||
aEvent->mClass == eMouseEventClass) &&
aEvent->mMessage != ePointerDown && aEvent->mMessage != eMouseDown) {
if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) {
uint32_t pointerId = mouseEvent->pointerId;
nsIContent* pointerCapturingContent =
GetPointerCapturingContent(pointerId);
if (pointerCapturingContent) {
if (nsIFrame* capturingFrame = pointerCapturingContent->GetPrimaryFrame()) {
// If pointer capture is set, we should suppress
// pointerover/pointerenter events for all elements except element
// which have pointer capture. (Code in EventStateManager)
pointerEvent->retargetedByPointerCapture =
frame && frame->GetContent() &&
!nsContentUtils::ContentIsDescendantOf(frame->GetContent(),
pointerCapturingContent);
frame = capturingFrame;
}
if (pointerEvent->mMessage == ePointerUp ||
pointerEvent->mMessage == ePointerCancel) {
if (aEvent->mMessage == ePointerUp ||
aEvent->mMessage == ePointerCancel) {
// Implicitly releasing capture for given pointer.
// ePointerLostCapture should be send after ePointerUp or
// ePointerCancel.
releasePointerCaptureCaller.SetTarget(pointerId,
pointerEvent->inputSource,
pointerEvent->mIsPrimary);
WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent();
MOZ_ASSERT(pointerEvent);
releasePointerCaptureCaller.SetTarget(pointerEvent);
}
}
}
@@ -8340,35 +8327,44 @@ PresShell::HandleEventInternal(WidgetEvent* aEvent,
return rv;
}
void
nsIPresShell::DispatchGotOrLostPointerCaptureEvent(bool aIsGotCapture,
uint32_t aPointerId,
uint16_t aPointerType,
bool aIsPrimary,
nsIContent* aCaptureTarget)
/* static */ void
nsIPresShell::DispatchGotOrLostPointerCaptureEvent(
bool aIsGotCapture,
const WidgetPointerEvent* aPointerEvent,
nsIContent* aCaptureTarget)
{
PointerEventInit init;
init.mPointerId = aPointerId;
init.mBubbles = true;
ConvertPointerTypeToString(aPointerType, init.mPointerType);
init.mIsPrimary = aIsPrimary;
RefPtr<mozilla::dom::PointerEvent> event;
event = PointerEvent::Constructor(aCaptureTarget,
aIsGotCapture
? NS_LITERAL_STRING("gotpointercapture")
: NS_LITERAL_STRING("lostpointercapture"),
init);
if (event) {
nsIDocument* targetDoc = aCaptureTarget->OwnerDoc();
nsCOMPtr<nsIPresShell> shell = targetDoc->GetShell();
NS_ENSURE_TRUE_VOID(shell);
if (!aIsGotCapture && !aCaptureTarget->IsInUncomposedDoc()) {
// If the capturing element was removed from the DOM tree, fire
// ePointerLostCapture at the document.
PointerEventInit init;
init.mPointerId = aPointerEvent->pointerId;
init.mBubbles = true;
init.mComposed = true;
ConvertPointerTypeToString(aPointerEvent->inputSource, init.mPointerType);
init.mIsPrimary = aPointerEvent->mIsPrimary;
RefPtr<mozilla::dom::PointerEvent> event;
event = PointerEvent::Constructor(aCaptureTarget,
NS_LITERAL_STRING("lostpointercapture"),
init);
bool dummy;
// If the capturing element was removed from the DOM tree,
// lostpointercapture event should be fired at the document.
if (!aIsGotCapture && !aCaptureTarget->IsInUncomposedDoc()) {
aCaptureTarget->OwnerDoc()->DispatchEvent(event->InternalDOMEvent(),
&dummy);
} else {
aCaptureTarget->DispatchEvent(event->InternalDOMEvent(), &dummy);
}
targetDoc->DispatchEvent(event->InternalDOMEvent(), &dummy);
return;
}
nsEventStatus status = nsEventStatus_eIgnore;
WidgetPointerEvent localEvent(aPointerEvent->IsTrusted(),
aIsGotCapture ? ePointerGotCapture :
ePointerLostCapture,
aPointerEvent->mWidget);
localEvent.AssignPointerEventData(*aPointerEvent, true);
nsresult rv = shell->HandleEventWithTarget(
&localEvent,
aCaptureTarget->GetPrimaryFrame(),
aCaptureTarget, &status);
NS_ENSURE_SUCCESS_VOID(rv);
}
nsresult
+4 -4
View File
@@ -24,16 +24,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1078327
var test_mediator_move = false;
var test_mediator_out = false;
var test_listener = false;
var test_lost_capture = false;
function TargetHandler(event) {
logger("Target receive event: " + event.type + ". Mediator.setPointerCapture()");
mediator.setPointerCapture(event.pointerId);
test_target = true;
test_capture = true;
}
function MediatorHandler(event) {
logger("Mediator receive event: " + event.type);
if(event.type == "gotpointercapture")
test_capture = true;
if(!test_capture)
return;
if(event.type == "pointermove")
@@ -43,7 +43,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1078327
if(event.type == "pointerout")
test_mediator_out++;
if(event.type == "lostpointercapture")
test_capture = false;
test_lost_capture = true;
}
function ListenerHandler(event) {
logger("Listener receive event: " + event.type);
@@ -86,7 +86,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1078327
}
function finishTest() {
parent.is(test_target, true, "pointerdown event should be received by target");
parent.is(test_capture, false, "test_capture should be false at the end of the test");
parent.is(test_lost_capture, true, "mediator should receive lostpointercapture");
parent.is(test_mediator_over, 1, "mediator should receive pointerover event only once");
parent.is(test_mediator_move, 5, "mediator should receive pointermove event five times");
parent.is(test_mediator_out, 1, "mediator should receive pointerout event only once");
+2 -2
View File
@@ -111,10 +111,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1162990
}
function finishTest() {
parent.is(test_basketLeave, 0, "Part1: basket should not receive pointerleave event after pointer capturing");
parent.is(test_basketLeave, 1, "Part1: basket should receive pointerleave event after pointer capturing");
parent.is(test_targetGotCapture, 1, "Part1: target should receive gotpointercapture event");
parent.is(test_targetLostCapture, 1, "Part1: target should receive lostpointercapture event");
parent.is(test_targetLeave, 2, "Part1: target should receive pointerleave event two times");
parent.is(test_targetLeave, 1, "Part1: target should receive pointerleave event only one time");
parent.is(test_childLeave, 0, "Part1: child should not receive pointerleave event after pointer capturing");
parent.is(test_listenerDown, 1, "Part1: listener should receive pointerdown event");
parent.is(test_listenerLeave, 1, "Part1: listener should receive pointerleave event only one time");
+1 -1
View File
@@ -116,7 +116,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1162990
parent.is(test_targetDown, 1, "Part2: target should receive pointerdown event");
parent.is(test_targetGotCapture, 1, "Part2: target should receive gotpointercapture event");
parent.is(test_targetLostCapture, 1, "Part2: target should receive lostpointercapture event");
parent.is(test_targetLeave, 1, "Part2: target should receive pointerleave event");
parent.is(test_targetLeave, 0, "Part2: target should not receive pointerleave event");
parent.is(test_childLeave, 0, "Part2: child should not receive pointerleave event after pointer capturing");
parent.is(test_listenerLeave, 0, "Part2: listener should not receive pointerleave event after pointer capturing");
logger("finishTest");
-241
View File
@@ -1,241 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=976963
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 976963</title>
<meta name="author" content="Maksim Lebedev" />
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style>
div#listener {
background: yellow;
position: absolute;
top: -100px;
}
div#middler {
background: yellow;
margin: 10px;
}
div#target {
background: yellow;
}
</style>
<script type="application/javascript">
/** Test for Bug 976963 **/
var All_Pointer_Events = ["pointerover", "pointerenter",
"pointermove",
"pointerdown", "pointerup",
"pointerout", "pointerleave",
"pointercancel",
"gotpointercapture", "lostpointercapture"];
function on_event(object, event, callback) {
object.addEventListener(event, callback, false);
}
function ok(check, msg) {
parent.ok(check, msg);
}
function is(a, b, msg) {
parent.is(a, b, msg);
}
var listener = undefined;
var middler = undefined;
var target = undefined;
var test_ListenerGotCapture = 0;
var test_ListenerUnwanted = 0;
var test_ListenerLostCapture = 0;
var test_ListenerAfterCapture = 0;
var test_MiddlerGotCapture = 0;
var test_MiddlerOver = 0;
var test_MiddlerLeave = 0;
var test_MiddlerUp = 0;
var test_MiddlerLostCapture = 0;
var test_TargetDown = 0;
var test_TargetUnwanted = 0;
var test_TargetUp = 0;
var captured_event = undefined;
var f_gotPointerCapture = false;
var f_lostPointerCapture = false;
var f_gotMiddlerPointerCapture = false;
function listenerEventHandler(event) {
logger("Listener: " + event.type + ". Captured_event: " + captured_event);
if(test_ListenerLostCapture)
test_ListenerAfterCapture++;
if (event.type == "gotpointercapture") {
f_gotPointerCapture = true;
test_ListenerGotCapture++;
}
else if (event.type == "lostpointercapture") {
f_lostPointerCapture = true;
f_gotPointerCapture = false;
test_ListenerLostCapture++;
}
else if (event.type == "pointermove") {
ok(captured_event && captured_event.pointerId == event.pointerId, "Listener: equals pointerId for lostpointercapture event");
if (f_gotPointerCapture) {
// on first event received for capture, release capture
logger("Listener call release");
ok(!!listener, "Listener should be live!");
ok(typeof(listener.releasePointerCapture) == "function", "Listener should have a function releasePointerCapture");
listener.releasePointerCapture(event.pointerId);
}
else {
logger("Listener.ASSERT: " + event.type);
test_ListenerUnwanted++;
// if any other events are received after releaseCapture, then the test fails
ok(false, event.target.id + "-" + event.type + " should be handled by target element handler");
}
}
else {
test_ListenerUnwanted++;
logger("Listener.ASSERT: " + event.type);
ok(false, event.type + "should be never handled by listener");
}
}
function middlerEventHandler(event) {
logger("Middler: " + event.type + ". Captured_event: " + captured_event);
if (event.type == "gotpointercapture") {
test_MiddlerGotCapture++;
f_gotMiddlerPointerCapture = true;
ok(captured_event && captured_event.pointerId == event.pointerId, "Middler: equals pointerId for gotpointercapture event");
}
else if (event.type == "pointerover") {
test_MiddlerOver++;
ok(captured_event && captured_event.pointerId == event.pointerId, "Middler: equals pointerId for pointerover event");
}
else if (event.type == "pointerleave") {
test_MiddlerLeave++;
ok(captured_event && captured_event.pointerId == event.pointerId, "Middler: equals pointerId for pointerleave event");
ok(!!listener, "Listener should be live!");
ok(typeof(listener.setPointerCapture) == "function", "Listener should have a function setPointerCapture");
listener.setPointerCapture(event.pointerId);
}
else if (event.type == "lostpointercapture") {
test_MiddlerLostCapture++;
f_gotMiddlerPointerCapture = false;
ok(captured_event && captured_event.pointerId == event.pointerId, "Middler: equals pointerId for lostpointercapture event");
}
else if (event.type == "pointerup" ) {
test_MiddlerUp++;
}
}
function targetEventHandler(event) {
logger("Target: " + event.type + ". Captured_event: " + captured_event);
if (f_gotPointerCapture || f_gotMiddlerPointerCapture) {
if (event.type != "pointerout" && event.type != "pointerleave") {
logger("Target.ASSERT: " + event.type + " " + event.pointerId);
test_TargetUnwanted++;
ok(false, "The Target element should not have received any events while capture is active. Event recieved:" + event.type + ". ");
}
}
if (event.type == "pointerdown") {
logger("Target.pointerdown 1: " + captured_event);
test_TargetDown++;
captured_event = event;
ok(!!middler, "Middler should be live!");
ok(typeof(middler.setPointerCapture) == "function", "Middler should have a function setPointerCapture");
middler.setPointerCapture(event.pointerId);
logger("Target.pointerdown 2: " + captured_event);
}
else if (event.type == "pointerup") {
ok(f_lostPointerCapture, "Target should have received pointerup");
ok(captured_event && captured_event.pointerId == event.pointerId, "Target: equals pointerId for lostpointercapture event");
test_TargetUp++; // complete test
}
}
function colorerHandler(event) {
if(event.type == "pointerover")
event.target.style.background = "red";
else if(event.type == "pointerout")
event.target.style.background = "yellow";
}
function setEventHandlers() {
listener = document.getElementById("listener");
middler = document.getElementById("middler");
target = document.getElementById("target");
target.style["touchAction"] = "none";
// target and listener - handle all events
for (var i = 0; i < All_Pointer_Events.length; i++) {
on_event(target, All_Pointer_Events[i], targetEventHandler);
on_event(listener, All_Pointer_Events[i], listenerEventHandler);
on_event(middler, All_Pointer_Events[i], middlerEventHandler);
on_event(target, All_Pointer_Events[i], colorerHandler);
on_event(middler, All_Pointer_Events[i], colorerHandler);
}
}
function prepareTest() {
SpecialPowers.pushPrefEnv({
"set": [
["dom.w3c_pointer_events.enabled", true]
]
}, executeTest);
}
function executeTest()
{
logger("executeTest");
setEventHandlers();
document.body.offsetLeft;
var rect = target.getBoundingClientRect();
synthesizePointer(target, rect.width/2, rect.height/2, {type: "pointermove"});
synthesizePointer(target, rect.width/2, rect.height/2, {type: "pointerdown"});
synthesizePointer(target, rect.width/3, rect.height/3, {type: "pointermove"});
synthesizePointer(middler, rect.width/2, rect.height/2, {type: "pointermove"});
synthesizePointer(target, rect.width/2, rect.height/2, {type: "pointermove"});
synthesizePointer(middler, rect.width/2, rect.height/2, {type: "pointermove"});
synthesizePointer(target, rect.width/2, rect.height/2, {type: "pointermove"});
synthesizePointer(target, rect.width/2, rect.height/2, {type: "pointerup"});
finishTest();
}
function finishTest() {
setTimeout(function() {
is(test_ListenerGotCapture, 1, "Listener should receive gotpointercapture event");
is(test_ListenerUnwanted, 0, "Listener should not receive any unwanted events");
is(test_ListenerLostCapture, 1, "Listener should receive lostpointercapture event");
is(test_ListenerAfterCapture, 0, "Listener should not receive any events after release pointer capture");
is(test_MiddlerGotCapture, 1, "Middler should receive gotpointercapture event");
is(test_MiddlerOver, 1, "Middler should receive pointerover event");
is(test_MiddlerLeave, 1, "Middler should receive pointerleave event");
is(test_MiddlerUp, 0, "Middler should not receive pointerup event");
is(test_MiddlerLostCapture, 1, "Middler should receive lostpointercapture event");
is(test_TargetDown, 1, "Target should receive pointerdown event");
is(test_TargetUnwanted, 0, "Target should not receive any event while pointer capture is active");
is(test_TargetUp, 1, "Target should receive pointerup event");
logger("finishTest");
parent.finishTest();
}, 1000);
}
function logger(message) {
console.log(message);
var log = document.getElementById('log');
log.innerHTML = message + "<br>" + log.innerHTML;
}
</script>
</head>
<body onload="prepareTest()">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=976963">Mozilla Bug 976963</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<div id="listener">div id=listener</div>
<div id="middler">div id=middler</div>
<div id="target">div id=target</div>
<pre id="log">
</pre>
</body>
</html>
+7 -1
View File
@@ -26,6 +26,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1098139
var test_lost_listener = false;
var test_lost_type = "";
var test_move_listener = false;
var test_over_listener = false;
var test_listener = false;
var test_lost_primary = false;
@@ -53,6 +54,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1098139
logger("Receive event on Listener: " + event.type);
test_move_listener = true;
}
function ListenerOverHandler(event) {
logger("Receive event on Listener: " + event.type);
test_over_listener = true;
}
function ListenerHandler(event) {
logger("Receive event on Listener: " + event.type);
test_listener = true;
@@ -74,7 +79,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1098139
target.addEventListener("pointerdown", TargetDownHandler, false);
listener.addEventListener("gotpointercapture", ListenerGotPCHandler, false);
listener.addEventListener("lostpointercapture", ListenerLostPCHandler, false);
listener.addEventListener("pointerover", ListenerHandler, false);
listener.addEventListener("pointerover", ListenerOverHandler, false);
listener.addEventListener("pointermove", ListenerMoveHandler, false);
listener.addEventListener("pointerup", ListenerHandler, false);
listener.addEventListener("pointerout", ListenerHandler, false);
@@ -93,6 +98,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1098139
parent.is(test_lost_type, "touch", "Part 5: lostpointercapture event should have pointerType touch");
parent.is(test_lost_primary, true, "Part 5: lostpointercapture event should have isPrimary as true");
parent.is(test_move_listener, true, "Part 5: gotpointercapture should be triggered by pointermove");
parent.is(test_over_listener, true, "Part 5: listener should receive pointerover when capturing pointer");
parent.is(test_listener, false, "Part 5: listener should not receive any other events");
logger("finishTest");
parent.finishTest();
+5 -1
View File
@@ -19,6 +19,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1073563
var listener = undefined;
var test_target = false;
var test_move = false;
var test_over = false;
var test_listener = false;
var receive_lostpointercapture = false;
@@ -44,6 +45,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1073563
}
} else if(event.type == "pointermove") {
test_move = true;
} else if(event.type == "pointerover") {
test_over = true;
} else {
test_listener = true;
}
@@ -81,7 +84,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1073563
// PE level 2 defines that the pending pointer capture is processed when firing next pointer events.
// In this test case, pointer capture release is processed when firing pointermove
parent.is(test_move, true, "Part 6: gotpointercapture should be triggered by pointermove");
parent.is(test_listener, false, "Part 6: no other pointerevents should be fired before gotpointercapture");
parent.is(test_over, true, "Part 6: pointerover should be received when capturing pointer");
parent.is(test_listener, false, "Part 6: no other pointerevents should be fired before gotpointercapture except pointerover");
logger("finishTest");
parent.finishTest();
}
-2
View File
@@ -256,8 +256,6 @@ skip-if = toolkit == 'android'
support-files = bug851445_helper.html
[test_bug970964.html]
support-files = bug970964_inner.html
[test_bug976963.html]
support-files = bug976963_inner.html
[test_bug977003.html]
support-files =
bug977003_inner_1.html
-35
View File
@@ -1,35 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=976963
-->
<head>
<meta charset="utf-8">
<meta name="author" content="Maksim Lebedev" />
<title>Test for Bug 976963</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript">
function prepareTest() {
SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout("untriaged");
SpecialPowers.pushPrefEnv({
"set": [
["dom.w3c_pointer_events.enabled", true],
["layout.reflow.synthMouseMove", false]
]
}, startTest);
}
function startTest() {
var iframe = document.getElementById("testFrame");
iframe.src = "bug976963_inner.html";
}
function finishTest() {
SimpleTest.finish();
}
</script>
</head>
<body onload="prepareTest()">
<iframe id="testFrame" height="700" width="700"></iframe>
</body>
</html>
+6 -3
View File
@@ -46,15 +46,17 @@ public:
uint32_t pointerId;
uint32_t tiltX;
uint32_t tiltY;
uint32_t twist;
float tangentialPressure;
bool convertToPointer;
bool retargetedByPointerCapture;
WidgetPointerHelper()
: pointerId(0)
, tiltX(0)
, tiltY(0)
, twist(0)
, tangentialPressure(0)
, convertToPointer(true)
, retargetedByPointerCapture(false)
{
}
@@ -63,8 +65,9 @@ public:
pointerId = aEvent.pointerId;
tiltX = aEvent.tiltX;
tiltY = aEvent.tiltY;
twist = aEvent.twist;
tangentialPressure = aEvent.tangentialPressure;
convertToPointer = aEvent.convertToPointer;
retargetedByPointerCapture = aEvent.retargetedByPointerCapture;
}
};
+7 -3
View File
@@ -228,8 +228,10 @@ struct ParamTraits<mozilla::WidgetPointerHelper>
WriteParam(aMsg, aParam.pointerId);
WriteParam(aMsg, aParam.tiltX);
WriteParam(aMsg, aParam.tiltY);
// We don't serialize convertToPointer and retargetedByPointerCapture since
// they are temporarily variable and should be reset to default.
WriteParam(aMsg, aParam.twist);
WriteParam(aMsg, aParam.tangentialPressure);
// We don't serialize convertToPointer since it's temporarily variable and
// should be reset to default.
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
@@ -237,7 +239,9 @@ struct ParamTraits<mozilla::WidgetPointerHelper>
bool rv;
rv = ReadParam(aMsg, aIter, &aResult->pointerId) &&
ReadParam(aMsg, aIter, &aResult->tiltX) &&
ReadParam(aMsg, aIter, &aResult->tiltY);
ReadParam(aMsg, aIter, &aResult->tiltY) &&
ReadParam(aMsg, aIter, &aResult->twist) &&
ReadParam(aMsg, aIter, &aResult->tangentialPressure);
return rv;
}
};