Commits:
-
f24d6cd4
by Edgar Chen at 2023-07-31T21:15:57+02:00
Bug 1821884 - Ensure consistent state for fullscreen/pointerlock warnings; r=Gijs
Fullscreen/PointerLock warnings are initialized with hidden="true", but
change to hidden="" after being shown and hidden again. I think this
started happening when we began using HTML elements instead of XUL as
they handle hidden attribute differently.
Differential Revision: https://phabricator.services.mozilla.com/D177790
-
53142727
by Edgar Chen at 2023-07-31T21:16:28+02:00
Bug 1821884 - Reshow initial fullscreen notification; r=Gijs
Depends on D177790
Differential Revision: https://phabricator.services.mozilla.com/D178339
4 changed files:
Changes:
browser/base/content/browser-fullScreenAndPointerLock.js
... |
... |
@@ -62,9 +62,14 @@ var PointerlockFsWarning = { |
62
|
62
|
this._element = document.getElementById(elementId);
|
63
|
63
|
// Setup event listeners
|
64
|
64
|
this._element.addEventListener("transitionend", this);
|
|
65
|
+ this._element.addEventListener("transitioncancel", this);
|
65
|
66
|
window.addEventListener("mousemove", this, true);
|
|
67
|
+ window.addEventListener("activate", this);
|
|
68
|
+ window.addEventListener("deactivate", this);
|
66
|
69
|
// The timeout to hide the warning box after a while.
|
67
|
70
|
this._timeoutHide = new this.Timeout(() => {
|
|
71
|
+ window.removeEventListener("activate", this);
|
|
72
|
+ window.removeEventListener("deactivate", this);
|
68
|
73
|
this._state = "hidden";
|
69
|
74
|
}, timeout);
|
70
|
75
|
// The timeout to show the warning box when the pointer is at the top
|
... |
... |
@@ -116,11 +121,10 @@ var PointerlockFsWarning = { |
116
|
121
|
return;
|
117
|
122
|
}
|
118
|
123
|
|
119
|
|
- // Explicitly set the last state to hidden to avoid the warning
|
120
|
|
- // box being hidden immediately because of mousemove.
|
121
|
|
- this._state = "onscreen";
|
122
|
|
- this._lastState = "hidden";
|
123
|
|
- this._timeoutHide.start();
|
|
124
|
+ if (Services.focus.activeWindow == window) {
|
|
125
|
+ this._state = "onscreen";
|
|
126
|
+ this._timeoutHide.start();
|
|
127
|
+ }
|
124
|
128
|
},
|
125
|
129
|
|
126
|
130
|
/**
|
... |
... |
@@ -148,7 +152,10 @@ var PointerlockFsWarning = { |
148
|
152
|
this._element.hidden = true;
|
149
|
153
|
// Remove all event listeners
|
150
|
154
|
this._element.removeEventListener("transitionend", this);
|
|
155
|
+ this._element.removeEventListener("transitioncancel", this);
|
151
|
156
|
window.removeEventListener("mousemove", this, true);
|
|
157
|
+ window.removeEventListener("activate", this);
|
|
158
|
+ window.removeEventListener("deactivate", this);
|
152
|
159
|
// Clear fields
|
153
|
160
|
this._element = null;
|
154
|
161
|
this._timeoutHide = null;
|
... |
... |
@@ -186,7 +193,7 @@ var PointerlockFsWarning = { |
186
|
193
|
}
|
187
|
194
|
if (newState != "hidden") {
|
188
|
195
|
if (currentState != "hidden") {
|
189
|
|
- this._element.setAttribute(newState, true);
|
|
196
|
+ this._element.setAttribute(newState, "");
|
190
|
197
|
} else {
|
191
|
198
|
// When the previous state is hidden, the display was none,
|
192
|
199
|
// thus no box was constructed. We need to wait for the new
|
... |
... |
@@ -197,7 +204,7 @@ var PointerlockFsWarning = { |
197
|
204
|
requestAnimationFrame(() => {
|
198
|
205
|
requestAnimationFrame(() => {
|
199
|
206
|
if (this._element) {
|
200
|
|
- this._element.setAttribute(newState, true);
|
|
207
|
+ this._element.setAttribute(newState, "");
|
201
|
208
|
}
|
202
|
209
|
});
|
203
|
210
|
});
|
... |
... |
@@ -217,7 +224,7 @@ var PointerlockFsWarning = { |
217
|
224
|
} else if (this._timeoutShow.delay >= 0) {
|
218
|
225
|
this._timeoutShow.start();
|
219
|
226
|
}
|
220
|
|
- } else {
|
|
227
|
+ } else if (state != "onscreen") {
|
221
|
228
|
let elemRect = this._element.getBoundingClientRect();
|
222
|
229
|
if (state == "hiding" && this._lastState != "hidden") {
|
223
|
230
|
// If we are on the hiding transition, and the pointer
|
... |
... |
@@ -239,12 +246,23 @@ var PointerlockFsWarning = { |
239
|
246
|
}
|
240
|
247
|
break;
|
241
|
248
|
}
|
242
|
|
- case "transitionend": {
|
|
249
|
+ case "transitionend":
|
|
250
|
+ case "transitioncancel": {
|
243
|
251
|
if (this._state == "hiding") {
|
244
|
252
|
this._element.hidden = true;
|
245
|
253
|
}
|
246
|
254
|
break;
|
247
|
255
|
}
|
|
256
|
+ case "activate": {
|
|
257
|
+ this._state = "onscreen";
|
|
258
|
+ this._timeoutHide.start();
|
|
259
|
+ break;
|
|
260
|
+ }
|
|
261
|
+ case "deactivate": {
|
|
262
|
+ this._state = "hidden";
|
|
263
|
+ this._timeoutHide.cancel();
|
|
264
|
+ break;
|
|
265
|
+ }
|
248
|
266
|
}
|
249
|
267
|
},
|
250
|
268
|
};
|
browser/base/content/fullscreen-and-pointerlock.inc.xhtml
... |
... |
@@ -3,7 +3,7 @@ |
3
|
3
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
4
|
4
|
|
5
|
5
|
<html:div id="fullscreen-and-pointerlock-wrapper">
|
6
|
|
- <html:div id="fullscreen-warning" class="pointerlockfswarning" hidden="true">
|
|
6
|
+ <html:div id="fullscreen-warning" class="pointerlockfswarning" hidden="">
|
7
|
7
|
<html:div class="pointerlockfswarning-domain-text">
|
8
|
8
|
<html:span class="pointerlockfswarning-domain" data-l10n-name="domain"/>
|
9
|
9
|
</html:div>
|
... |
... |
@@ -20,7 +20,7 @@ |
20
|
20
|
</html:button>
|
21
|
21
|
</html:div>
|
22
|
22
|
|
23
|
|
- <html:div id="pointerlock-warning" class="pointerlockfswarning" hidden="true">
|
|
23
|
+ <html:div id="pointerlock-warning" class="pointerlockfswarning" hidden="">
|
24
|
24
|
<html:div class="pointerlockfswarning-domain-text">
|
25
|
25
|
<html:span class="pointerlockfswarning-domain" data-l10n-name="domain"/>
|
26
|
26
|
</html:div>
|
browser/base/content/test/fullscreen/browser_fullscreen_warning.js
... |
... |
@@ -3,14 +3,35 @@ |
3
|
3
|
|
4
|
4
|
"use strict";
|
5
|
5
|
|
6
|
|
-add_task(async function test_fullscreen_display_none() {
|
|
6
|
+function checkWarningState(aWarningElement, aExpectedState, aMsg) {
|
|
7
|
+ ["hidden", "ontop", "onscreen"].forEach(state => {
|
|
8
|
+ is(
|
|
9
|
+ aWarningElement.hasAttribute(state),
|
|
10
|
+ state == aExpectedState,
|
|
11
|
+ `${aMsg} - check ${state} attribute.`
|
|
12
|
+ );
|
|
13
|
+ });
|
|
14
|
+}
|
|
15
|
+
|
|
16
|
+async function waitForWarningState(aWarningElement, aExpectedState) {
|
|
17
|
+ await BrowserTestUtils.waitForAttribute(aExpectedState, aWarningElement, "");
|
|
18
|
+ checkWarningState(
|
|
19
|
+ aWarningElement,
|
|
20
|
+ aExpectedState,
|
|
21
|
+ `Wait for ${aExpectedState} state`
|
|
22
|
+ );
|
|
23
|
+}
|
|
24
|
+
|
|
25
|
+add_setup(async function init() {
|
7
|
26
|
await SpecialPowers.pushPrefEnv({
|
8
|
27
|
set: [
|
9
|
28
|
["full-screen-api.enabled", true],
|
10
|
29
|
["full-screen-api.allow-trusted-requests-only", false],
|
11
|
30
|
],
|
12
|
31
|
});
|
|
32
|
+});
|
13
|
33
|
|
|
34
|
+add_task(async function test_fullscreen_display_none() {
|
14
|
35
|
await BrowserTestUtils.withNewTab(
|
15
|
36
|
{
|
16
|
37
|
gBrowser,
|
... |
... |
@@ -30,11 +51,13 @@ add_task(async function test_fullscreen_display_none() { |
30
|
51
|
},
|
31
|
52
|
async function(browser) {
|
32
|
53
|
let warning = document.getElementById("fullscreen-warning");
|
33
|
|
- let warningShownPromise = BrowserTestUtils.waitForAttribute(
|
34
|
|
- "onscreen",
|
|
54
|
+ checkWarningState(
|
35
|
55
|
warning,
|
36
|
|
- "true"
|
|
56
|
+ "hidden",
|
|
57
|
+ "Should not show full screen warning initially"
|
37
|
58
|
);
|
|
59
|
+
|
|
60
|
+ let warningShownPromise = waitForWarningState(warning, "onscreen");
|
38
|
61
|
// Enter fullscreen
|
39
|
62
|
await SpecialPowers.spawn(browser, [], async () => {
|
40
|
63
|
let frame = content.document.querySelector("iframe");
|
... |
... |
@@ -54,39 +77,33 @@ add_task(async function test_fullscreen_display_none() { |
54
|
77
|
);
|
55
|
78
|
document.getElementById("fullscreen-exit-button").click();
|
56
|
79
|
await exitFullscreenPromise;
|
|
80
|
+
|
|
81
|
+ checkWarningState(
|
|
82
|
+ warning,
|
|
83
|
+ "hidden",
|
|
84
|
+ "Should hide fullscreen warning after exiting fullscreen"
|
|
85
|
+ );
|
57
|
86
|
}
|
58
|
87
|
);
|
59
|
88
|
});
|
60
|
89
|
|
61
|
90
|
add_task(async function test_fullscreen_pointerlock_conflict() {
|
62
|
|
- await SpecialPowers.pushPrefEnv({
|
63
|
|
- set: [
|
64
|
|
- ["full-screen-api.enabled", true],
|
65
|
|
- ["full-screen-api.allow-trusted-requests-only", false],
|
66
|
|
- ],
|
67
|
|
- });
|
68
|
|
-
|
69
|
91
|
await BrowserTestUtils.withNewTab("https://example.com", async browser => {
|
70
|
92
|
let fsWarning = document.getElementById("fullscreen-warning");
|
71
|
93
|
let plWarning = document.getElementById("pointerlock-warning");
|
72
|
94
|
|
73
|
|
- is(
|
74
|
|
- fsWarning.getAttribute("onscreen"),
|
75
|
|
- null,
|
76
|
|
- "Should not show full screen warning initially."
|
77
|
|
- );
|
78
|
|
- is(
|
79
|
|
- plWarning.getAttribute("onscreen"),
|
80
|
|
- null,
|
81
|
|
- "Should not show pointer lock warning initially."
|
82
|
|
- );
|
83
|
|
-
|
84
|
|
- let fsWarningShownPromise = BrowserTestUtils.waitForAttribute(
|
85
|
|
- "onscreen",
|
|
95
|
+ checkWarningState(
|
86
|
96
|
fsWarning,
|
87
|
|
- "true"
|
|
97
|
+ "hidden",
|
|
98
|
+ "Should not show full screen warning initially"
|
|
99
|
+ );
|
|
100
|
+ checkWarningState(
|
|
101
|
+ plWarning,
|
|
102
|
+ "hidden",
|
|
103
|
+ "Should not show pointer lock warning initially"
|
88
|
104
|
);
|
89
|
105
|
|
|
106
|
+ let fsWarningShownPromise = waitForWarningState(fsWarning, "onscreen");
|
90
|
107
|
info("Entering full screen and pointer lock.");
|
91
|
108
|
await SpecialPowers.spawn(browser, [], async () => {
|
92
|
109
|
await content.document.body.requestFullscreen();
|
... |
... |
@@ -94,15 +111,10 @@ add_task(async function test_fullscreen_pointerlock_conflict() { |
94
|
111
|
});
|
95
|
112
|
|
96
|
113
|
await fsWarningShownPromise;
|
97
|
|
- is(
|
98
|
|
- fsWarning.getAttribute("onscreen"),
|
99
|
|
- "true",
|
100
|
|
- "Should show full screen warning."
|
101
|
|
- );
|
102
|
|
- is(
|
103
|
|
- plWarning.getAttribute("onscreen"),
|
104
|
|
- null,
|
105
|
|
- "Should not show pointer lock warning."
|
|
114
|
+ checkWarningState(
|
|
115
|
+ plWarning,
|
|
116
|
+ "hidden",
|
|
117
|
+ "Should not show pointer lock warning"
|
106
|
118
|
);
|
107
|
119
|
|
108
|
120
|
info("Exiting pointerlock");
|
... |
... |
@@ -110,18 +122,19 @@ add_task(async function test_fullscreen_pointerlock_conflict() { |
110
|
122
|
await content.document.exitPointerLock();
|
111
|
123
|
});
|
112
|
124
|
|
113
|
|
- is(
|
114
|
|
- fsWarning.getAttribute("onscreen"),
|
115
|
|
- "true",
|
116
|
|
- "Should still show full screen warning."
|
|
125
|
+ checkWarningState(
|
|
126
|
+ fsWarning,
|
|
127
|
+ "onscreen",
|
|
128
|
+ "Should still show full screen warning"
|
117
|
129
|
);
|
118
|
|
- is(
|
119
|
|
- plWarning.getAttribute("onscreen"),
|
120
|
|
- null,
|
121
|
|
- "Should not show pointer lock warning."
|
|
130
|
+ checkWarningState(
|
|
131
|
+ plWarning,
|
|
132
|
+ "hidden",
|
|
133
|
+ "Should not show pointer lock warning"
|
122
|
134
|
);
|
123
|
135
|
|
124
|
136
|
// Cleanup
|
|
137
|
+ info("Exiting fullscreen");
|
125
|
138
|
await document.exitFullscreen();
|
126
|
139
|
});
|
127
|
140
|
}); |
dom/tests/browser/browser_pointerlock_warning.js
... |
... |
@@ -15,6 +15,25 @@ const FRAME_TEST_URL = |
15
|
15
|
encodeURI(BODY_URL) +
|
16
|
16
|
'"></iframe></body>';
|
17
|
17
|
|
|
18
|
+function checkWarningState(aWarningElement, aExpectedState, aMsg) {
|
|
19
|
+ ["hidden", "ontop", "onscreen"].forEach(state => {
|
|
20
|
+ is(
|
|
21
|
+ aWarningElement.hasAttribute(state),
|
|
22
|
+ state == aExpectedState,
|
|
23
|
+ `${aMsg} - check ${state} attribute.`
|
|
24
|
+ );
|
|
25
|
+ });
|
|
26
|
+}
|
|
27
|
+
|
|
28
|
+async function waitForWarningState(aWarningElement, aExpectedState) {
|
|
29
|
+ await BrowserTestUtils.waitForAttribute(aExpectedState, aWarningElement, "");
|
|
30
|
+ checkWarningState(
|
|
31
|
+ aWarningElement,
|
|
32
|
+ aExpectedState,
|
|
33
|
+ `Wait for ${aExpectedState} state`
|
|
34
|
+ );
|
|
35
|
+}
|
|
36
|
+
|
18
|
37
|
// Make sure the pointerlock warning is shown and exited with the escape key
|
19
|
38
|
add_task(async function show_pointerlock_warning_escape() {
|
20
|
39
|
let urls = [TEST_URL, FRAME_TEST_URL];
|
... |
... |
@@ -24,11 +43,7 @@ add_task(async function show_pointerlock_warning_escape() { |
24
|
43
|
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
|
25
|
44
|
|
26
|
45
|
let warning = document.getElementById("pointerlock-warning");
|
27
|
|
- let warningShownPromise = BrowserTestUtils.waitForAttribute(
|
28
|
|
- "onscreen",
|
29
|
|
- warning,
|
30
|
|
- "true"
|
31
|
|
- );
|
|
46
|
+ let warningShownPromise = waitForWarningState(warning, "onscreen");
|
32
|
47
|
|
33
|
48
|
let expectedWarningText;
|
34
|
49
|
|
... |
... |
@@ -49,11 +64,7 @@ add_task(async function show_pointerlock_warning_escape() { |
49
|
64
|
|
50
|
65
|
ok(true, "Pointerlock warning shown");
|
51
|
66
|
|
52
|
|
- let warningHiddenPromise = BrowserTestUtils.waitForAttribute(
|
53
|
|
- "hidden",
|
54
|
|
- warning,
|
55
|
|
- ""
|
56
|
|
- );
|
|
67
|
+ let warningHiddenPromise = waitForWarningState(warning, "hidden");
|
57
|
68
|
|
58
|
69
|
await BrowserTestUtils.waitForCondition(
|
59
|
70
|
() => warning.innerText == expectedWarningText,
|
|