Bug 1666739 - Add site-specific PiP toggle visibility threshold to the WebCompat add-on. r=mstriemer,webcompat-reviewers,denschub,twisniewski

This also adds the first threshold of 0.9 for YouTube, which allows us to avoid
hittest false positives on the PiP toggle when the user has one of the YouTube
player menus open.

Differential Revision: https://phabricator.services.mozilla.com/D93124
This commit is contained in:
Mike Conley 2020-12-04 19:43:54 +00:00
parent 73a835db89
commit 2e689029d7
6 changed files with 79 additions and 39 deletions

View File

@ -52,5 +52,9 @@ let AVAILABLE_PIP_OVERRIDES;
udemy: {
"https://*.udemy.com/*": { policy: TOGGLE_POLICIES.ONE_QUARTER },
},
youtube: {
"https://*.youtube.com/*": { visibilityThreshold: 0.9 },
},
};
}

View File

@ -254,10 +254,11 @@ class PictureInPictureToggleChild extends JSWindowActorChild {
// this is false.
isTrackingVideos: false,
togglePolicy: TOGGLE_POLICIES.DEFAULT,
// The documentURI that has been checked with toggle policies for this
// document. Note that the documentURI might change for a document via
// the history API, so we remember the last checked documentURI to
// determine if we need to check again.
toggleVisibilityThreshold: 1.0,
// The documentURI that has been checked with toggle policies and
// visibility thresholds for this document. Note that the documentURI
// might change for a document via the history API, so we remember
// the last checked documentURI to determine if we need to check again.
checkedPolicyDocumentURI: null,
};
this.weakDocStates.set(this.document, state);
@ -638,6 +639,7 @@ class PictureInPictureToggleChild extends JSWindowActorChild {
return;
}
let state = this.docState;
let { clientX, clientY } = event;
let winUtils = this.contentWindow.windowUtils;
// We use winUtils.nodesFromRect instead of document.elementsFromPoint,
@ -656,7 +658,8 @@ class PictureInPictureToggleChild extends JSWindowActorChild {
1,
true,
false,
true /* aOnlyVisible */
true /* aOnlyVisible */,
state.toggleVisibilityThreshold
);
if (!Array.from(elements).includes(video)) {
return;
@ -664,7 +667,6 @@ class PictureInPictureToggleChild extends JSWindowActorChild {
let toggle = this.getToggleElement(shadowRoot);
if (this.isMouseOverToggle(toggle, event)) {
let state = this.docState;
state.isClickingToggle = true;
state.clickedElement = Cu.getWeakReference(event.originalTarget);
event.stopImmediatePropagation();
@ -853,9 +855,13 @@ class PictureInPictureToggleChild extends JSWindowActorChild {
: gSiteOverrides;
// Do we have any toggle overrides? If so, try to apply them.
for (let [override, { policy }] of siteOverrides) {
if (policy && override.matches(this.document.documentURI)) {
state.togglePolicy = policy;
for (let [override, { policy, visibilityThreshold }] of siteOverrides) {
if (
(policy || visibilityThreshold) &&
override.matches(this.document.documentURI)
) {
state.togglePolicy = policy || TOGGLE_POLICIES.DEFAULT;
state.toggleVisibilityThreshold = visibilityThreshold || 1.0;
break;
}
}

View File

@ -3,12 +3,6 @@
"use strict";
const SHARED_DATA_KEY = "PictureInPicture:SiteOverrides";
const { TOGGLE_POLICIES } = ChromeUtils.import(
"resource://gre/modules/PictureInPictureControls.jsm"
);
/**
* Tests that by setting a Picture-in-Picture toggle position policy
* in the sharedData structure, that the toggle position can be

View File

@ -5,7 +5,9 @@
/**
* Tests that the Picture-in-Picture toggle can appear and be clicked
* when the video is overlaid with transparent elements.
* when the video is overlaid with transparent elements. Also tests the
* site-specific toggle visibility threshold to ensure that we can
* configure opacities that can't be clicked through.
*/
add_task(async () => {
const PAGE = TEST_ROOT + "test-transparent-overlay-1.html";
@ -13,4 +15,19 @@ add_task(async () => {
"video-transparent-background": { canToggle: true },
"video-alpha-background": { canToggle: true },
});
// Now set a toggle visibility threshold to 0.4 and ensure that the
// partially obscured toggle can't be clicked.
Services.ppmm.sharedData.set(SHARED_DATA_KEY, {
"*://example.com/*": { visibilityThreshold: 0.4 },
});
Services.ppmm.sharedData.flush();
await testToggle(PAGE, {
"video-transparent-background": { canToggle: true },
"video-alpha-background": { canToggle: false },
});
Services.ppmm.sharedData.set(SHARED_DATA_KEY, {});
Services.ppmm.sharedData.flush();
});

View File

@ -5,8 +5,9 @@
/**
* Tests that the Picture-in-Picture toggle can appear and be clicked
* when the video is overlaid with elements that have zero and
* partial opacity.
* when the video is overlaid with elements that have zero and partial
* opacity. Also tests the site-specific toggle visibility threshold to
* ensure that we can configure opacities that can't be clicked through.
*/
add_task(async () => {
const PAGE = TEST_ROOT + "test-transparent-overlay-2.html";
@ -14,4 +15,19 @@ add_task(async () => {
"video-zero-opacity": { canToggle: true },
"video-partial-opacity": { canToggle: true },
});
// Now set a toggle visibility threshold to 0.4 and ensure that the
// partially obscured toggle can't be clicked.
Services.ppmm.sharedData.set(SHARED_DATA_KEY, {
"*://example.com/*": { visibilityThreshold: 0.4 },
});
Services.ppmm.sharedData.flush();
await testToggle(PAGE, {
"video-zero-opacity": { canToggle: true },
"video-partial-opacity": { canToggle: false },
});
Services.ppmm.sharedData.set(SHARED_DATA_KEY, {});
Services.ppmm.sharedData.flush();
});

View File

@ -3,6 +3,10 @@
"use strict";
const { TOGGLE_POLICIES } = ChromeUtils.import(
"resource://gre/modules/PictureInPictureControls.jsm"
);
const TEST_ROOT = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"http://example.com"
@ -20,6 +24,7 @@ const TOGGLE_POSITION_PREF =
"media.videocontrols.picture-in-picture.video-toggle.position";
const HAS_USED_PREF =
"media.videocontrols.picture-in-picture.video-toggle.has-used";
const SHARED_DATA_KEY = "PictureInPicture:SiteOverrides";
/**
* We currently ship with a few different variations of the
@ -433,8 +438,8 @@ async function prepareForToggleClick(browser, videoID) {
}
/**
* Returns the client rect for the toggle if it's supposed to be visible
* on hover. Otherwise, returns the client rect for the video with the
* Returns client rect info for the toggle if it's supposed to be visible
* on hover. Otherwise, returns client rect info for the video with the
* associated ID.
*
* @param {Element} browser The <xul:browser> that has the <video> loaded in it.
@ -444,9 +449,9 @@ async function prepareForToggleClick(browser, videoID) {
* @resolves With the following Object structure:
* {
* top: <Number>,
* right: <Number>,
* left: <Number>,
* bottom: <Number>,
* width: <Number>,
* height: <Number>,
* }
*/
async function getToggleClientRect(
@ -476,9 +481,9 @@ async function getToggleClientRect(
return {
top: rect.top,
right: rect.right,
left: rect.left,
bottom: rect.bottom,
width: rect.width,
height: rect.height,
};
});
}
@ -605,22 +610,20 @@ async function testToggleHelper(
);
info("Hovering the toggle rect now.");
// The toggle center, because of how it slides out, is actually outside
// of the bounds of a click event. For now, we move the mouse in by a
// hard-coded 2 pixels along the x and y axis to achieve the hover.
let toggleLeft = toggleClientRect.left + 2;
let toggleTop = toggleClientRect.top + 2;
let toggleCenterX = toggleClientRect.left + toggleClientRect.width / 2;
let toggleCenterY = toggleClientRect.top + toggleClientRect.height / 2;
await BrowserTestUtils.synthesizeMouseAtPoint(
toggleLeft,
toggleTop,
toggleCenterX,
toggleCenterY,
{
type: "mousemove",
},
browser
);
await BrowserTestUtils.synthesizeMouseAtPoint(
toggleLeft,
toggleTop,
toggleCenterX,
toggleCenterY,
{
type: "mouseover",
},
@ -641,8 +644,8 @@ async function testToggleHelper(
info("Right-clicking on toggle.");
await BrowserTestUtils.synthesizeMouseAtPoint(
toggleLeft,
toggleTop,
toggleCenterX,
toggleCenterY,
{ button: 2 },
browser
);
@ -675,8 +678,8 @@ async function testToggleHelper(
);
let domWindowOpened = BrowserTestUtils.domWindowOpenedAndLoaded(null);
await BrowserTestUtils.synthesizeMouseAtPoint(
toggleLeft,
toggleTop,
toggleCenterX,
toggleCenterY,
{},
browser
);
@ -695,8 +698,8 @@ async function testToggleHelper(
"Clicking on toggle, and expecting no Picture-in-Picture window opens"
);
await BrowserTestUtils.synthesizeMouseAtPoint(
toggleLeft,
toggleTop,
toggleCenterX,
toggleCenterY,
{},
browser
);