Bug 1671657 - setPointerCapture should do nothing if the element's node document is not active document for the pointer; r=smaug

Depends on D94297

Differential Revision: https://phabricator.services.mozilla.com/D94001
This commit is contained in:
Edgar Chen 2020-10-30 08:31:42 +00:00
parent 33c996c701
commit 2737da4055
6 changed files with 42 additions and 122 deletions

View File

@ -1197,13 +1197,14 @@ class Element : public FragmentOrElement {
ErrorResult& aError);
void SetPointerCapture(int32_t aPointerId, ErrorResult& aError) {
bool activeState = false;
if (nsContentUtils::ShouldResistFingerprinting(GetComposedDoc()) &&
aPointerId != PointerEventHandler::GetSpoofedPointerIdForRFP()) {
aError.ThrowNotFoundError("Invalid pointer id");
return;
}
if (!PointerEventHandler::GetPointerInfo(aPointerId, activeState)) {
const PointerInfo* pointerInfo =
PointerEventHandler::GetPointerInfo(aPointerId);
if (!pointerInfo) {
aError.ThrowNotFoundError("Invalid pointer id");
return;
}
@ -1217,19 +1218,19 @@ class Element : public FragmentOrElement {
aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
if (!activeState) {
if (!pointerInfo->mActiveState ||
pointerInfo->mActiveDocument != OwnerDoc()) {
return;
}
PointerEventHandler::RequestPointerCaptureById(aPointerId, this);
}
void ReleasePointerCapture(int32_t aPointerId, ErrorResult& aError) {
bool activeState = false;
if (nsContentUtils::ShouldResistFingerprinting(GetComposedDoc()) &&
aPointerId != PointerEventHandler::GetSpoofedPointerIdForRFP()) {
aError.ThrowNotFoundError("Invalid pointer id");
return;
}
if (!PointerEventHandler::GetPointerInfo(aPointerId, activeState)) {
if (!PointerEventHandler::GetPointerInfo(aPointerId)) {
aError.ThrowNotFoundError("Invalid pointer id");
return;
}

View File

@ -567,7 +567,7 @@ nsresult EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
}
}
PointerEventHandler::UpdateActivePointerState(mouseEvent);
PointerEventHandler::UpdateActivePointerState(mouseEvent, aTargetContent);
switch (aEvent->mMessage) {
case eContextMenu:

View File

@ -19,20 +19,6 @@ using namespace dom;
Maybe<int32_t> PointerEventHandler::sSpoofedPointerId;
class PointerInfo final {
public:
uint16_t mPointerType;
bool mActiveState;
bool mPrimaryState;
bool mPreventMouseEventByContent;
explicit PointerInfo(bool aActiveState, uint16_t aPointerType,
bool aPrimaryState)
: mPointerType(aPointerType),
mActiveState(aActiveState),
mPrimaryState(aPrimaryState),
mPreventMouseEventByContent(false) {}
};
// Keeps a map between pointerId and element that currently capturing pointer
// with such pointerId. If pointerId is absent in this map then nobody is
// capturing it. Additionally keep information about pending capturing content.
@ -81,7 +67,8 @@ bool PointerEventHandler::IsPointerEventImplicitCaptureForTouchEnabled() {
}
/* static */
void PointerEventHandler::UpdateActivePointerState(WidgetMouseEvent* aEvent) {
void PointerEventHandler::UpdateActivePointerState(WidgetMouseEvent* aEvent,
nsIContent* aTargetContent) {
if (!StaticPrefs::dom_w3c_pointer_events_enabled() || !aEvent) {
return;
}
@ -90,17 +77,21 @@ void PointerEventHandler::UpdateActivePointerState(WidgetMouseEvent* aEvent) {
// In this case we have to know information about available mouse pointers
sActivePointersIds->Put(
aEvent->pointerId,
new PointerInfo(false, aEvent->mInputSource, true));
new PointerInfo(false, aEvent->mInputSource, true, nullptr));
MaybeCacheSpoofedPointerID(aEvent->mInputSource, aEvent->pointerId);
break;
case ePointerDown:
// In this case we switch pointer to active state
if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
// XXXedgar, test could possibly synthesize a mousedown event on a
// coordinate outside the browser window and cause aTargetContent to be
// nullptr, not sure if this also happens on real usage.
sActivePointersIds->Put(
pointerEvent->pointerId,
new PointerInfo(true, pointerEvent->mInputSource,
pointerEvent->mIsPrimary));
new PointerInfo(
true, pointerEvent->mInputSource, pointerEvent->mIsPrimary,
aTargetContent ? aTargetContent->OwnerDoc() : nullptr));
MaybeCacheSpoofedPointerID(pointerEvent->mInputSource,
pointerEvent->pointerId);
}
@ -118,7 +109,7 @@ void PointerEventHandler::UpdateActivePointerState(WidgetMouseEvent* aEvent) {
sActivePointersIds->Put(
pointerEvent->pointerId,
new PointerInfo(false, pointerEvent->mInputSource,
pointerEvent->mIsPrimary));
pointerEvent->mIsPrimary, nullptr));
} else {
sActivePointersIds->Remove(pointerEvent->pointerId);
}
@ -267,14 +258,8 @@ void PointerEventHandler::ReleaseAllPointerCaptureRemoteTarget() {
}
/* static */
bool PointerEventHandler::GetPointerInfo(uint32_t aPointerId,
bool& aActiveState) {
PointerInfo* pointerInfo = nullptr;
if (sActivePointersIds->Get(aPointerId, &pointerInfo) && pointerInfo) {
aActiveState = pointerInfo->mActiveState;
return true;
}
return false;
const PointerInfo* PointerEventHandler::GetPointerInfo(uint32_t aPointerId) {
return sActivePointersIds->Get(aPointerId);
}
/* static */

View File

@ -10,6 +10,7 @@
#include "mozilla/EventForwards.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/TouchEvents.h"
#include "mozilla/WeakPtr.h"
class nsIFrame;
class nsIContent;
@ -20,6 +21,7 @@ class PresShell;
namespace dom {
class BrowserParent;
class Document;
class Element;
}; // namespace dom
@ -38,6 +40,22 @@ class PointerCaptureInfo final {
bool Empty() { return !(mPendingElement || mOverrideElement); }
};
class PointerInfo final {
public:
uint16_t mPointerType;
bool mActiveState;
bool mPrimaryState;
bool mPreventMouseEventByContent;
WeakPtr<dom::Document> mActiveDocument;
explicit PointerInfo(bool aActiveState, uint16_t aPointerType,
bool aPrimaryState, dom::Document* aActiveDocument)
: mPointerType(aPointerType),
mActiveState(aActiveState),
mPrimaryState(aPrimaryState),
mPreventMouseEventByContent(false),
mActiveDocument(aActiveDocument) {}
};
class PointerEventHandler final {
public:
// Called in nsLayoutStatics::Initialize/Shutdown to initialize pointer event
@ -50,7 +68,8 @@ class PointerEventHandler final {
// Called in ESM::PreHandleEvent to update current active pointers in a hash
// table.
static void UpdateActivePointerState(WidgetMouseEvent* aEvent);
static void UpdateActivePointerState(WidgetMouseEvent* aEvent,
nsIContent* aTargetContent);
// Request/release pointer capture of the specified pointer by the element.
static void RequestPointerCaptureById(uint32_t aPointerId,
@ -74,11 +93,9 @@ class PointerEventHandler final {
// Get the pointer captured info of the specified pointer.
static PointerCaptureInfo* GetPointerCaptureInfo(uint32_t aPointerId);
// GetPointerInfo returns true if pointer with aPointerId is situated in
// device, false otherwise.
// aActiveState is additional information, which shows state of pointer like
// button state for mouse.
static bool GetPointerInfo(uint32_t aPointerId, bool& aActiveState);
// Return the PointerInfo if the pointer with aPointerId is situated in device
// , nullptr otherwise.
static const PointerInfo* GetPointerInfo(uint32_t aPointerId);
// CheckPointerCaptureState checks cases, when got/lostpointercapture events
// should be fired.

View File

@ -25,8 +25,6 @@
topLevelDocumentEventHandling,
topLevelDocumentEventHandlingWithTouch,
iframeEventHandling,
iframeEventHandlingWithCapturingInParent,
iframeEventHandlingwithHiddenCapturingInParent
];
function next() {
@ -229,79 +227,6 @@
next();
}
function iframeEventHandlingWithCapturingInParent(
name = "iframeEventHandlingWithCapturingInParent") {
var pid;
var iframe = document.getElementById("iframe");
var doc = iframe.contentDocument;
doc.body.innerHTML = "";
doc.head.innerHTML =
"<style>" + document.getElementsByTagName("style")[0].textContent + "</style>";
var area = doc.createElement("div");
area.id = "area";
var target = doc.createElement("div");
target.id = "target";
area.appendChild(target);
doc.body.appendChild(area);
var body = doc.body;
var html = doc.documentElement;
var win = doc.defaultView;
var targetOutsideIframe = document.getElementById("targetOutsideIframe");
var eventLog = [];
function captureEvent(e) {
eventLog.push([e.type, e.composedPath()]);
}
var expectedEvents = [
["pointerdown", [ target, area, body, html, doc, win ]],
["mousedown", [ target, area, body, html, doc, win ]],
["pointerup", [ targetOutsideIframe, document.body, document.documentElement, document, window ]],
["mouseup", [ targetOutsideIframe, document.body, document.documentElement, document, window ]],
["click", [ target, area, body, html, doc, win ]],
];
win.addEventListener("pointerdown",
function(e) {
captureEvent(e);
pid = e.pointerId;
targetOutsideIframe.setPointerCapture(pid);
}, { once: true});
win.addEventListener("mousedown",
function(e) {
captureEvent(e);
}, { once: true});
window.addEventListener("pointerup",
function(e) {
captureEvent(e);
targetOutsideIframe.releasePointerCapture(pid);
}, { once: true});
window.addEventListener("mouseup", function(e) {
captureEvent(e);
}, { once: true});
win.addEventListener("click", function(e) {
captureEvent(e);
}, { once: true});
synthesizeMouseAtCenter(target, {}, win);
opener.is(eventLog.length, expectedEvents.length,
`[${name}] Same number events expected.`);
for (var i = 0; i < eventLog.length; ++i) {
opener.is(eventLog[i][0], expectedEvents[i][0],
`${name} ${i}`);
for (var j = 0; j < eventLog[i][1].length; ++j) {
opener.is(eventLog[i][1][j], expectedEvents[i][1][j],
`${name} ${i} ${j}`);
}
}
next();
}
function iframeEventHandlingwithHiddenCapturingInParent() {
document.getElementById("targetOutsideIframe").style.display = "none";
document.getElementById("targetOutsideIframe").offsetLeft;
iframeEventHandlingWithCapturingInParent("iframeEventHandlingwithHiddenCapturingInParent");
}
</script>
</head>
<body onload="start();">

View File

@ -1,8 +0,0 @@
[pointerevent_mouse_pointercapture_inactivate_pointer.html]
expected: TIMEOUT
[setPointerCapture: pointer active in outer frame, set capture to inner frame]
expected: TIMEOUT
[setPointerCapture: pointer active in inner frame, set capture to outer frame]
expected: NOTRUN