mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-07 18:04:46 +00:00
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:
parent
33c996c701
commit
2737da4055
@ -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;
|
||||
}
|
||||
|
@ -567,7 +567,7 @@ nsresult EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
}
|
||||
}
|
||||
|
||||
PointerEventHandler::UpdateActivePointerState(mouseEvent);
|
||||
PointerEventHandler::UpdateActivePointerState(mouseEvent, aTargetContent);
|
||||
|
||||
switch (aEvent->mMessage) {
|
||||
case eContextMenu:
|
||||
|
@ -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 */
|
||||
|
@ -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.
|
||||
|
@ -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();">
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user