Bug 1651546 [wpt PR 24524] - Screen Enumeration: Add Window.isMultiScreen() function, a=testonly

Automatic update from web-platform-tests
Screen Enumeration: Add Window.isMultiScreen() function

This single bit exposes whether the device has multiple screens.
It informs the value of permission prompts to request more information.
This CL adds the IDL, IPC, implementation, and testing.

Add a mojo struct for GetDisplays results; reject on failure.

Test with the DevTools console (and multiple screens) with:
chrome://flags#enable-experimental-web-platform-features

Bug: 1098861, 1080710
Test: window.isMultiScreen() works as expected
Change-Id: I5d5d86716f1910bfc4ddc5dc70faef252b831a31
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2278529
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Victor Costan <pwnall@chromium.org>
Commit-Queue: Michael Wasserman <msw@chromium.org>
Auto-Submit: Michael Wasserman <msw@chromium.org>
Cr-Commit-Position: refs/heads/master@{#789356}

--

wpt-commits: 8ba782c9d5a545b850cd8920032cb14cfbab2c35
wpt-pr: 24524
This commit is contained in:
Mike Wasserman 2020-07-22 19:59:59 +00:00 коммит произвёл moz-wptsync-bot
Родитель 4a64e67e7b
Коммит fa0d2fd503
6 изменённых файлов: 213 добавлений и 76 удалений

Просмотреть файл

@ -44,11 +44,22 @@ var ScreenEnumerationTest = (() => {
} }
async getDisplays() { async getDisplays() {
if (!this.success_)
return Promise.resolve({ result: undefined, });
let value = new blink.mojom.Displays();
value.displays = this.displays_;
value.internalId = this.internalId_;
value.primaryId = this.primaryId_;
return Promise.resolve({ result: value, });
}
async hasMultipleDisplays() {
if (!this.success_)
return Promise.resolve({ result: blink.mojom.MultipleDisplays.kError });
return Promise.resolve({ return Promise.resolve({
displays: this.displays_, result: this.displays_.length > 1
internalId: this.internalId_, ? blink.mojom.MultipleDisplays.kTrue
primaryId: this.primaryId_, : blink.mojom.MultipleDisplays.kFalse,
success: this.success_,
}); });
} }
} }

Просмотреть файл

@ -19,6 +19,7 @@ The `ScreenEnumerationTest` interface is defined as:
addDisplay(display); // Push display to the display vector. addDisplay(display); // Push display to the display vector.
removeDisplay(id); // Remove display from the display vector. removeDisplay(id); // Remove display from the display vector.
async getDisplays(); // Interceptor of getDisplays (screen_enumeration.mojom). async getDisplays(); // Interceptor of getDisplays (screen_enumeration.mojom).
async hasMultipleDisplays(); // Interceptor of hasMultipleDisplays (screen_enumeration.mojom).
}; };
``` ```

Просмотреть файл

@ -1,39 +1,63 @@
// META: global=window // META: global=window
// META: script=/resources/testdriver.js // META: script=/resources/testdriver.js
// META: script=/resources/testdriver-vendor.js // META: script=/resources/testdriver-vendor.js
"use strict"; 'use strict';
promise_test(async testCase => { promise_test(async t => {
assert_equals(typeof self.getScreens, "function"); assert_equals(typeof self.getScreens, 'function');
}, "self.getScreens is present"); }, 'getScreens() is present');
promise_test(async testCase => { promise_test(async t => {
await test_driver.set_permission({name: "window-placement"}, "granted"); await test_driver.set_permission({name: 'window-placement'}, 'granted');
const screens = await self.getScreens(); const screens = await self.getScreens();
assert_greater_than(screens.length, 0); assert_greater_than(screens.length, 0);
assert_equals(typeof screens[0].availWidth, "number"); assert_equals(typeof screens[0].availWidth, 'number');
assert_equals(typeof screens[0].availHeight, "number"); assert_equals(typeof screens[0].availHeight, 'number');
assert_equals(typeof screens[0].width, "number"); assert_equals(typeof screens[0].width, 'number');
assert_equals(typeof screens[0].height, "number"); assert_equals(typeof screens[0].height, 'number');
assert_equals(typeof screens[0].colorDepth, "number"); assert_equals(typeof screens[0].colorDepth, 'number');
assert_equals(typeof screens[0].pixelDepth, "number"); assert_equals(typeof screens[0].pixelDepth, 'number');
assert_equals(typeof screens[0].availLeft, "number"); assert_equals(typeof screens[0].availLeft, 'number');
assert_equals(typeof screens[0].availTop, "number"); assert_equals(typeof screens[0].availTop, 'number');
assert_equals(typeof screens[0].left, "number"); assert_equals(typeof screens[0].left, 'number');
assert_equals(typeof screens[0].top, "number"); assert_equals(typeof screens[0].top, 'number');
assert_equals(typeof screens[0].orientation, "object"); assert_equals(typeof screens[0].orientation, 'object');
assert_equals(typeof screens[0].primary, "boolean"); assert_equals(typeof screens[0].primary, 'boolean');
assert_equals(typeof screens[0].internal, "boolean"); assert_equals(typeof screens[0].internal, 'boolean');
assert_equals(typeof screens[0].scaleFactor, "number"); assert_equals(typeof screens[0].scaleFactor, 'number');
assert_equals(typeof screens[0].id, "string"); assert_equals(typeof screens[0].id, 'string');
assert_equals(typeof screens[0].touchSupport, "boolean"); assert_equals(typeof screens[0].touchSupport, 'boolean');
}, "self.getScreens returns at least 1 Screen with permission granted"); }, 'getScreens() returns at least 1 Screen with permission granted');
promise_test(async testCase => { promise_test(async t => {
await test_driver.set_permission({name: 'window-placement'}, 'granted');
assert_greater_than((await self.getScreens()).length, 0);
await test_driver.set_permission({name: 'window-placement'}, 'denied'); await test_driver.set_permission({name: 'window-placement'}, 'denied');
const screens = await self.getScreens(); await promise_rejects_dom(t, 'NotAllowedError', self.getScreens());
assert_equals(screens.length, 0); }, 'getScreens() rejects the promise with permission denied');
}, 'self.getScreens returns no Screen objects with permission denied');
async_test(async t => {
await test_driver.set_permission({name: 'window-placement'}, 'granted');
let iframe = document.body.appendChild(document.createElement('iframe'));
assert_greater_than((await iframe.contentWindow.getScreens()).length, 0);
iframe.contentWindow.onunload = t.step_func(async () => {
// TODO(crbug.com/1106132): This should reject or resolve; not hang.
// assert_greater_than((await iframe.contentWindow.getScreens()).length, 0);
let iframeGetScreens = iframe.contentWindow.getScreens;
let constructor = iframe.contentWindow.DOMException;
assert_not_equals(iframeGetScreens, undefined);
assert_not_equals(constructor, undefined);
await t.step_wait(() => !iframe.contentWindow, "execution context invalid");
assert_equals(iframe.contentWindow, null);
await promise_rejects_dom(t, 'InvalidStateError', constructor, iframeGetScreens());
t.done();
});
document.body.removeChild(iframe);
}, "getScreens() resolves for attached iframe; rejects for detached iframe");

Просмотреть файл

@ -1,19 +1,37 @@
<!DOCTYPE html> <!DOCTYPE html>
<meta charset="utf-8"> <meta charset='utf-8'>
<title>Screen Enumeration: getScreens() tentative</title> <title>Screen Enumeration: getScreens() tentative</title>
<!-- TODO: update link to W3C whenever specifications are ready --> <!-- TODO: update link to W3C whenever specifications are ready -->
<link rel="help" href="https://github.com/webscreens/screen-enumeration"/> <link rel='help' href='https://github.com/webscreens/screen-enumeration'/>
<script src="/resources/testharness.js"></script> <script src='/resources/testharness.js'></script>
<script src="/resources/testharnessreport.js"></script> <script src='/resources/testharnessreport.js'></script>
<script src="resources/screenenumeration-helpers.js"></script> <script src='resources/screenenumeration-helpers.js'></script>
<script> <script>
"use strict"; 'use strict';
function check_screen_matches_display(screen, display) {
assert_equals(screen.left, display.bounds.x);
assert_equals(screen.top, display.bounds.y);
assert_equals(screen.width, display.bounds.width);
assert_equals(screen.height, display.bounds.height);
assert_equals(screen.availLeft, display.workArea.x);
assert_equals(screen.availTop, display.workArea.y);
assert_equals(screen.availWidth, display.workArea.width);
assert_equals(screen.availHeight, display.workArea.height);
assert_equals(screen.scaleFactor, display.deviceScaleFactor);
}
screen_enumeration_test(async (t, mockScreenEnum) => {
mockScreenEnum.setSuccess(true);
await test_driver.set_permission({name: 'window-placement'}, 'granted');
assert_equals((await self.getScreens()).length, 0);
}, 'getScreens() supports an empty set of mocked screens');
screen_enumeration_test(async (t, mockScreenEnum) => { screen_enumeration_test(async (t, mockScreenEnum) => {
let display1 = makeDisplay(10, let display1 = makeDisplay(10,
{x: 0, y: 10, width: 1200, height: 800}, {x: 0, y: 0, width: 800, height: 600},
{x: 20, y: 30, width: 1000, height: 600}, {x: 0, y: 0, width: 800, height: 550},
1.0); 1.0);
mockScreenEnum.addDisplay(display1); mockScreenEnum.addDisplay(display1);
@ -21,43 +39,31 @@ screen_enumeration_test(async (t, mockScreenEnum) => {
mockScreenEnum.setInternalId(mockScreenEnum.displays_[0].id); mockScreenEnum.setInternalId(mockScreenEnum.displays_[0].id);
mockScreenEnum.setSuccess(true); mockScreenEnum.setSuccess(true);
// Grant window-placement permissions for testdriver. await test_driver.set_permission({name: 'window-placement'}, 'granted');
await test_driver.set_permission({name: "window-placement"}, "granted");
// This returns the mocked displays via MockScreenEnumeration implementation.
const screens = await self.getScreens(); const screens = await self.getScreens();
assert_equals(screens.length, 1); assert_equals(screens.length, 1);
check_screen_matches_display(screens[0], display1);
assert_equals(screens[0].left, 0);
assert_equals(screens[0].top, 10);
assert_equals(screens[0].width, 1200);
assert_equals(screens[0].height, 800);
assert_equals(screens[0].availLeft, 20);
assert_equals(screens[0].availTop, 30);
assert_equals(screens[0].availWidth, 1000);
assert_equals(screens[0].availHeight, 600);
assert_equals(screens[0].primary, true); assert_equals(screens[0].primary, true);
assert_equals(screens[0].internal, true); assert_equals(screens[0].internal, true);
assert_equals(screens[0].scaleFactor, 1.0); assert_equals(screens[0].id, '0');
assert_equals(screens[0].id, "0"); }, 'getScreens() supports a single mocked screen');
}, "getScreens() returns a single mocked screen");
screen_enumeration_test(async (t, mockScreenEnum) => { screen_enumeration_test(async (t, mockScreenEnum) => {
let display1 = makeDisplay(10, let display1 = makeDisplay(10,
{x: 0, y: 10, width: 1200, height: 800}, {x: 0, y: 0, width: 800, height: 600},
{x: 20, y: 30, width: 1000, height: 600}, {x: 0, y: 0, width: 800, height: 550},
1.0); 1.0);
let display2 = makeDisplay(11, let display2 = makeDisplay(11,
{x: 0, y: 10, width: 1200, height: 800}, {x: 800, y: 0, width: 800, height: 600},
{x: 20, y: 30, width: 1000, height: 600}, {x: 800, y: 0, width: 800, height: 550},
1.0); 2.0);
let display3 = makeDisplay(12, let display3 = makeDisplay(12,
{x: 0, y: 10, width: 1200, height: 800}, {x: 0, y: 600, width: 1200, height: 800},
{x: 20, y: 30, width: 1000, height: 600}, {x: 50, y: 50, width: 1150, height: 750},
1.0); 1.5);
mockScreenEnum.addDisplay(display1); mockScreenEnum.addDisplay(display1);
mockScreenEnum.addDisplay(display2); mockScreenEnum.addDisplay(display2);
@ -66,29 +72,42 @@ screen_enumeration_test(async (t, mockScreenEnum) => {
mockScreenEnum.setInternalId(mockScreenEnum.displays_[0].id); mockScreenEnum.setInternalId(mockScreenEnum.displays_[0].id);
mockScreenEnum.setSuccess(true); mockScreenEnum.setSuccess(true);
// Grant window-placement permissions for testdriver. await test_driver.set_permission({name: 'window-placement'}, 'granted');
await test_driver.set_permission({name: "window-placement"}, "granted");
// This returns the mocked displays via MockScreenEnumeration implementation.
let screens = await self.getScreens(); let screens = await self.getScreens();
assert_equals(screens.length, 3); assert_equals(screens.length, 3);
assert_equals(screens[0].id, "0"); check_screen_matches_display(screens[0], display1);
assert_equals(screens[1].id, "1"); assert_equals(screens[0].primary, true);
assert_equals(screens[2].id, "2"); assert_equals(screens[0].internal, true);
assert_equals(screens[0].id, '0');
check_screen_matches_display(screens[1], display2);
assert_equals(screens[1].primary, false);
assert_equals(screens[1].internal, false);
assert_equals(screens[1].id, '1');
check_screen_matches_display(screens[2], display3);
assert_equals(screens[2].primary, false);
assert_equals(screens[2].internal, false);
assert_equals(screens[2].id, '2');
mockScreenEnum.removeDisplay(display2.id); mockScreenEnum.removeDisplay(display2.id);
screens = await self.getScreens(); screens = await self.getScreens();
assert_equals(screens.length, 2); assert_equals(screens.length, 2);
assert_equals(screens[0].id, "0"); check_screen_matches_display(screens[0], display1);
assert_equals(screens[1].id, "1"); assert_equals(screens[0].id, '0');
check_screen_matches_display(screens[1], display3);
assert_equals(screens[1].id, '1');
mockScreenEnum.removeDisplay(display1.id); mockScreenEnum.removeDisplay(display1.id);
screens = await self.getScreens(); screens = await self.getScreens();
assert_equals(screens.length, 1); assert_equals(screens.length, 1);
assert_equals(screens[0].id, "0"); check_screen_matches_display(screens[0], display3);
}, "getScreens() supports multiple mocked screens"); assert_equals(screens[0].id, '0');
}, 'getScreens() supports multiple mocked screens');
screen_enumeration_test(async (t, mockScreenEnum) => {
mockScreenEnum.setSuccess(false);
await test_driver.set_permission({name: 'window-placement'}, 'granted');
promise_rejects_dom(t, 'NotAllowedError', self.getScreens());
}, 'getScreens() rejects when the mock success value is set to false');
</script> </script>

Просмотреть файл

@ -0,0 +1,40 @@
// META: global=window
// META: script=/resources/testdriver.js
// META: script=/resources/testdriver-vendor.js
'use strict';
promise_test(async t => {
assert_equals(typeof self.isMultiScreen, 'function');
}, 'isMultiScreen() is present');
promise_test(async t => {
await test_driver.set_permission({name: 'window-placement'}, 'granted');
assert_equals(typeof await self.isMultiScreen(), 'boolean');
}, 'isMultiScreen() returns a boolean value with permission granted');
promise_test(async t => {
await test_driver.set_permission({name: 'window-placement'}, 'denied');
assert_equals(typeof await self.isMultiScreen(), 'boolean');
}, 'isMultiScreen() returns a boolean value with permission denied');
async_test(async t => {
let iframe = document.body.appendChild(document.createElement('iframe'));
assert_equals(typeof await iframe.contentWindow.isMultiScreen(), 'boolean');
iframe.contentWindow.onunload = t.step_func(async () => {
// TODO(crbug.com/1106132): This should reject or resolve; not hang.
// assert_equals(typeof await iframe.contentWindow.isMultiScreen(), 'boolean');
let iframeIsMultiScreen = iframe.contentWindow.isMultiScreen;
let constructor = iframe.contentWindow.DOMException;
assert_not_equals(iframeIsMultiScreen, undefined);
assert_not_equals(constructor, undefined);
await t.step_wait(() => !iframe.contentWindow, "execution context invalid");
assert_equals(iframe.contentWindow, null);
await promise_rejects_dom(t, 'InvalidStateError', constructor, iframeIsMultiScreen());
t.done();
});
document.body.removeChild(iframe);
}, "isMultiScreen() resolves for attached iframe; rejects for detached iframe");

Просмотреть файл

@ -0,0 +1,42 @@
<!DOCTYPE html>
<meta charset='utf-8'>
<title>Screen Enumeration: isMultiScreen() tentative</title>
<!-- TODO: update link to W3C whenever specifications are ready -->
<link rel='help' href='https://github.com/webscreens/screen-enumeration'/>
<script src='/resources/testharness.js'></script>
<script src='/resources/testharnessreport.js'></script>
<script src='resources/screenenumeration-helpers.js'></script>
<script>
'use strict';
screen_enumeration_test(async (t, mockScreenEnum) => {
let display1 = makeDisplay(10,
{x: 0, y: 0, width: 800, height: 600},
{x: 0, y: 0, width: 800, height: 550},
1.0);
let display2 = makeDisplay(11,
{x: 800, y: 0, width: 800, height: 600},
{x: 800, y: 0, width: 800, height: 550},
2.0);
mockScreenEnum.setSuccess(true);
assert_equals(await self.isMultiScreen(), false);
mockScreenEnum.addDisplay(display1);
assert_equals(await self.isMultiScreen(), false);
mockScreenEnum.addDisplay(display2);
assert_equals(await self.isMultiScreen(), true);
mockScreenEnum.removeDisplay(display2.id);
assert_equals(await self.isMultiScreen(), false);
}, 'isMultiScreen() works as expected with mocked screens');
screen_enumeration_test(async (t, mockScreenEnum) => {
mockScreenEnum.setSuccess(false);
promise_rejects_dom(t, 'NotAllowedError', self.isMultiScreen());
}, 'isMultiScreen() rejects when the mock success value is set to false');
</script>