Bug 1428913 - Deny full-screen on right or middle mouse button. r=smaug

Differential Revision: https://phabricator.services.mozilla.com/D31481

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Paul Zuehlcke 2019-05-22 19:16:31 +00:00
parent ab55be14db
commit 4bccc4cede
9 changed files with 104 additions and 29 deletions

View File

@ -3291,11 +3291,7 @@ CORSMode Element::AttrValueToCORSMode(const nsAttrValue* aValue) {
}
static const char* GetFullscreenError(CallerType aCallerType) {
if (!nsContentUtils::IsRequestFullscreenAllowed(aCallerType)) {
return "FullscreenDeniedNotInputDriven";
}
return nullptr;
return nsContentUtils::CheckRequestFullscreenAllowed(aCallerType);
}
already_AddRefed<Promise> Element::RequestFullscreen(CallerType aCallerType,

View File

@ -6581,24 +6581,36 @@ bool nsContentUtils::ChannelShouldInheritPrincipal(
}
/* static */
bool nsContentUtils::IsRequestFullscreenAllowed(CallerType aCallerType) {
// If more time has elapsed since the user input than is specified by the
// dom.event.handling-user-input-time-limit pref (default 1 second), this
// function also returns false.
const char* nsContentUtils::CheckRequestFullscreenAllowed(
CallerType aCallerType) {
if (!StaticPrefs::full_screen_api_allow_trusted_requests_only() ||
aCallerType == CallerType::System) {
return true;
return nullptr;
}
if (EventStateManager::IsHandlingUserInput()) {
TimeDuration timeout = HandlingUserInputTimeout();
return timeout <= TimeDuration(nullptr) ||
(TimeStamp::Now() - EventStateManager::GetHandlingInputStart()) <=
timeout;
if (!EventStateManager::IsHandlingUserInput()) {
return "FullscreenDeniedNotInputDriven";
}
return false;
// If more time has elapsed since the user input than is specified by the
// dom.event.handling-user-input-time-limit pref (default 1 second),
// disallow fullscreen
TimeDuration timeout = HandlingUserInputTimeout();
if (timeout > TimeDuration(nullptr) &&
(TimeStamp::Now() - EventStateManager::GetHandlingInputStart()) >
timeout) {
return "FullscreenDeniedNotInputDriven";
}
// Entering full-screen on mouse mouse event is only allowed with left mouse
// button
if (StaticPrefs::full_screen_api_mouse_event_allow_left_button_only() &&
(EventStateManager::sCurrentMouseBtn == MouseButton::eMiddle ||
EventStateManager::sCurrentMouseBtn == MouseButton::eRight)) {
return "FullscreenDeniedMouseEventOnlyLeftBtn";
}
return nullptr;
}
/* static */

View File

@ -2332,12 +2332,14 @@ class nsContentUtils {
static bool IsFocusedContent(const nsIContent* aContent);
/**
* Returns true if requests for fullscreen are allowed in the current
* Returns nullptr if requests for fullscreen are allowed in the current
* context. Requests are only allowed if the user initiated them (like with
* a mouse-click or key press), unless this check has been disabled by
* setting the pref "full-screen-api.allow-trusted-requests-only" to false.
* If fullscreen is not allowed, a key for the error message is returned.
*/
static bool IsRequestFullscreenAllowed(mozilla::dom::CallerType aCallerType);
static const char* CheckRequestFullscreenAllowed(
mozilla::dom::CallerType aCallerType);
/**
* Returns true if calling execCommand with 'cut' or 'copy' arguments is

View File

@ -197,6 +197,7 @@ static uint32_t sESMInstanceCount = 0;
int32_t EventStateManager::sUserInputEventDepth = 0;
int32_t EventStateManager::sUserKeyboardEventDepth = 0;
bool EventStateManager::sNormalLMouseEventInProcess = false;
int16_t EventStateManager::sCurrentMouseBtn = MouseButton::eNotPressed;
EventStateManager* EventStateManager::sActiveESM = nullptr;
Document* EventStateManager::sMouseOverDocument = nullptr;
AutoWeakFrame EventStateManager::sLastDragOverFrame = nullptr;
@ -6282,6 +6283,12 @@ AutoHandlingUserInputStatePusher::AutoHandlingUserInputStatePusher(
mMouseButtonEventHandlingDocument =
fm->SetMouseButtonHandlingDocument(aDocument);
}
if (NeedsToUpdateCurrentMouseBtnState()) {
WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
if (mouseEvent) {
EventStateManager::sCurrentMouseBtn = mouseEvent->mButton;
}
}
}
AutoHandlingUserInputStatePusher::~AutoHandlingUserInputStatePusher() {
@ -6298,6 +6305,9 @@ AutoHandlingUserInputStatePusher::~AutoHandlingUserInputStatePusher() {
nsCOMPtr<Document> handlingDocument =
fm->SetMouseButtonHandlingDocument(mMouseButtonEventHandlingDocument);
}
if (NeedsToUpdateCurrentMouseBtnState()) {
EventStateManager::sCurrentMouseBtn = MouseButton::eNotPressed;
}
}
} // namespace mozilla

View File

@ -1262,6 +1262,7 @@ class EventStateManager : public nsSupportsWeakReference, public nsIObserver {
static int32_t sUserKeyboardEventDepth;
static bool sNormalLMouseEventInProcess;
static int16_t sCurrentMouseBtn;
static EventStateManager* sActiveESM;
@ -1298,6 +1299,11 @@ class MOZ_RAII AutoHandlingUserInputStatePusher final {
bool NeedsToResetFocusManagerMouseButtonHandlingState() const {
return mMessage == eMouseDown || mMessage == eMouseUp;
}
bool NeedsToUpdateCurrentMouseBtnState() const {
return mMessage == eMouseDown || mMessage == eMouseUp ||
mMessage == ePointerDown || mMessage == ePointerUp;
}
};
} // namespace mozilla

View File

@ -111,15 +111,50 @@ function testLongRunningEventHandler() {
}
addFullscreenErrorContinuation(() => {
ok(!document.fullscreenElement,
"Should not grant request in long-running event handler.");
// Restore the pref environment we changed before
// entering testNonTrustContext.
SpecialPowers.popPrefEnv(finish);
"Should not grant request in long-running event handler.");
SimpleTest.executeSoon(testFullscreenMouseBtn);
});
window.addEventListener("keypress", longRunningHandler);
sendString("a");
}
function requestFullscreenMouseBtn(event, button) {
let clickEl = document.createElement("p");
clickEl.innerText = "Click Me";
function eventHandler(event) {
document.body.requestFullscreen();
event.target.removeEventListener(event, this);
}
clickEl.addEventListener(event, eventHandler);
document.body.appendChild(clickEl);
synthesizeMouseAtCenter(clickEl, { button });
}
async function testFullscreenMouseBtn(event, button, next) {
await SpecialPowers.pushPrefEnv({
"set": [["full-screen-api.mouse-event-allow-left-button-only", true]]
});
let fsRequestEvents = ["mousedown", "mouseup", "pointerdown", "pointerup"];
let mouseButtons = [1, 2];
for (let i = 0; i < fsRequestEvents.length; i++) {
let event = fsRequestEvents[i];
for (let j = 0; j < mouseButtons.length; j++) {
let mouseButton = mouseButtons[j];
let fsDenied = addFullscreenErrorContinuation();
requestFullscreenMouseBtn(event, mouseButton);
await fsDenied;
ok(!document.fullscreenElement, `Should not grant request on '${event}' triggered by mouse button ${mouseButton}`);
}
}
// Restore the pref environment we changed before
// entering testNonTrustContext.
await SpecialPowers.popPrefEnv();
finish();
}
function finish() {
opener.nextTest();
}

View File

@ -72,12 +72,19 @@ function addFullscreenChangeContinuation(type, callback, inDoc) {
// Calls |callback| when the next fullscreenerror is dispatched to inDoc||document.
function addFullscreenErrorContinuation(callback, inDoc) {
var doc = inDoc || document;
var listener = function(event) {
doc.removeEventListener("fullscreenerror", listener);
setTimeout(function(){callback(event);}, 0);
};
doc.addEventListener("fullscreenerror", listener);
return new Promise((resolve) => {
let doc = inDoc || document;
let listener = function(event) {
doc.removeEventListener("fullscreenerror", listener);
setTimeout(function(){
if(callback) {
callback(event);
}
resolve();
}, 0);
};
doc.addEventListener("fullscreenerror", listener);
})
}
// Waits until the window has both the load event and a MozAfterPaint called on

View File

@ -63,6 +63,7 @@ FullscreenDeniedFocusedPlugin=Request for fullscreen was denied because a window
FullscreenDeniedHidden=Request for fullscreen was denied because the document is no longer visible.
FullscreenDeniedContainerNotAllowed=Request for fullscreen was denied because at least one of the documents containing elements is not an iframe or does not have an “allowfullscreen” attribute.
FullscreenDeniedNotInputDriven=Request for fullscreen was denied because Element.requestFullscreen() was not called from inside a short running user-generated event handler.
FullscreenDeniedMouseEventOnlyLeftBtn=Request for fullscreen was denied because Element.requestFullscreen() was called from inside a mouse event handler not triggered by left mouse button.
FullscreenDeniedNotHTMLSVGOrMathML=Request for fullscreen was denied because requesting element is not <svg>, <math>, or an HTML element.
FullscreenDeniedNotInDocument=Request for fullscreen was denied because requesting element is no longer in its document.
FullscreenDeniedMovedDocument=Request for fullscreen was denied because requesting element has moved document.

View File

@ -786,6 +786,12 @@ VARCACHE_PREF(
bool, true
)
VARCACHE_PREF(
"full-screen-api.mouse-event-allow-left-button-only",
full_screen_api_mouse_event_allow_left_button_only,
bool, true
)
//---------------------------------------------------------------------------
// Preference stylesheet prefs.
//---------------------------------------------------------------------------