Commits:
-
a9279174
by Edgar Chen at 2023-07-31T23:49:06+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
-
9f2eaedb
by Edgar Chen at 2023-07-31T23:49:06+02:00
Bug 1821884 - Reshow initial fullscreen notification; r=Gijs
Depends on D177790
Differential Revision: https://phabricator.services.mozilla.com/D178339
-
30d19aa0
by Eitan Isaacson at 2023-07-31T23:49:07+02:00
Bug 1819160 - Map Android ids to doc/accessible id pairs. r=Jamie
Differential Revision: https://phabricator.services.mozilla.com/D179737
-
efee8978
by Jon Coppeard at 2023-07-31T23:49:07+02:00
Bug 1828024 - Require the helper thread lock in the GC helper thread count getter r=sfink
This makes us take a lock to read this state (we already lock when writing it).
Also it adds a release assert in case something goes wrong with the thread
count calculations, as a crash is preferable to the potential deadlock.
Differential Revision: https://phabricator.services.mozilla.com/D181257
12 changed files:
Changes:
accessible/android/SessionAccessibility.cpp
... |
... |
@@ -269,12 +269,9 @@ RefPtr<SessionAccessibility> SessionAccessibility::GetInstanceFor( |
269
|
269
|
return GetInstanceFor(doc->GetPresShell());
|
270
|
270
|
}
|
271
|
271
|
} else {
|
272
|
|
- DocAccessibleParent* remoteDoc = aAccessible->AsRemote()->Document();
|
273
|
|
- if (remoteDoc->mSessionAccessibility) {
|
274
|
|
- return remoteDoc->mSessionAccessibility;
|
275
|
|
- }
|
276
|
272
|
dom::CanonicalBrowsingContext* cbc =
|
277
|
|
- static_cast<dom::BrowserParent*>(remoteDoc->Manager())
|
|
273
|
+ static_cast<dom::BrowserParent*>(
|
|
274
|
+ aAccessible->AsRemote()->Document()->Manager())
|
278
|
275
|
->GetBrowsingContext()
|
279
|
276
|
->Top();
|
280
|
277
|
dom::BrowserParent* bp = cbc->GetBrowserParent();
|
... |
... |
@@ -285,10 +282,7 @@ RefPtr<SessionAccessibility> SessionAccessibility::GetInstanceFor( |
285
|
282
|
if (auto element = bp->GetOwnerElement()) {
|
286
|
283
|
if (auto doc = element->OwnerDoc()) {
|
287
|
284
|
if (nsPresContext* presContext = doc->GetPresContext()) {
|
288
|
|
- RefPtr<SessionAccessibility> sessionAcc =
|
289
|
|
- GetInstanceFor(presContext->PresShell());
|
290
|
|
- remoteDoc->mSessionAccessibility = sessionAcc;
|
291
|
|
- return sessionAcc;
|
|
285
|
+ return GetInstanceFor(presContext->PresShell());
|
292
|
286
|
}
|
293
|
287
|
} else {
|
294
|
288
|
MOZ_ASSERT_UNREACHABLE(
|
... |
... |
@@ -684,14 +678,7 @@ void SessionAccessibility::PopulateNodeInfo( |
684
|
678
|
}
|
685
|
679
|
|
686
|
680
|
Accessible* SessionAccessibility::GetAccessibleByID(int32_t aID) const {
|
687
|
|
- Accessible* accessible = mIDToAccessibleMap.Get(aID);
|
688
|
|
- if (accessible && accessible->IsLocal() &&
|
689
|
|
- accessible->AsLocal()->IsDefunct()) {
|
690
|
|
- MOZ_ASSERT_UNREACHABLE("Registered accessible is defunct!");
|
691
|
|
- return nullptr;
|
692
|
|
- }
|
693
|
|
-
|
694
|
|
- return accessible;
|
|
681
|
+ return mIDToAccessibleMap.Get(aID);
|
695
|
682
|
}
|
696
|
683
|
|
697
|
684
|
#ifdef DEBUG
|
... |
... |
@@ -705,6 +692,58 @@ static bool IsDetachedDoc(Accessible* aAccessible) { |
705
|
692
|
}
|
706
|
693
|
#endif
|
707
|
694
|
|
|
695
|
+SessionAccessibility::IDMappingEntry::IDMappingEntry(Accessible* aAccessible)
|
|
696
|
+ : mInternalID(0) {
|
|
697
|
+ *this = aAccessible;
|
|
698
|
+}
|
|
699
|
+
|
|
700
|
+SessionAccessibility::IDMappingEntry&
|
|
701
|
+SessionAccessibility::IDMappingEntry::operator=(Accessible* aAccessible) {
|
|
702
|
+ mInternalID = aAccessible->ID();
|
|
703
|
+ MOZ_ASSERT(!(mInternalID & IS_REMOTE), "First bit is used in accessible ID!");
|
|
704
|
+ if (aAccessible->IsRemote()) {
|
|
705
|
+ mInternalID |= IS_REMOTE;
|
|
706
|
+ }
|
|
707
|
+
|
|
708
|
+ Accessible* docAcc = nsAccUtils::DocumentFor(aAccessible);
|
|
709
|
+ MOZ_ASSERT(docAcc);
|
|
710
|
+ if (docAcc) {
|
|
711
|
+ MOZ_ASSERT(docAcc->IsRemote() == aAccessible->IsRemote());
|
|
712
|
+ if (docAcc->IsRemote()) {
|
|
713
|
+ mDoc = docAcc->AsRemote()->AsDoc();
|
|
714
|
+ } else {
|
|
715
|
+ mDoc = docAcc->AsLocal();
|
|
716
|
+ }
|
|
717
|
+ }
|
|
718
|
+
|
|
719
|
+ return *this;
|
|
720
|
+}
|
|
721
|
+
|
|
722
|
+SessionAccessibility::IDMappingEntry::operator Accessible*() const {
|
|
723
|
+ if (mInternalID == 0) {
|
|
724
|
+ return static_cast<LocalAccessible*>(mDoc.get());
|
|
725
|
+ }
|
|
726
|
+
|
|
727
|
+ if (mInternalID == IS_REMOTE) {
|
|
728
|
+ return static_cast<DocAccessibleParent*>(mDoc.get());
|
|
729
|
+ }
|
|
730
|
+
|
|
731
|
+ if (mInternalID & IS_REMOTE) {
|
|
732
|
+ return static_cast<DocAccessibleParent*>(mDoc.get())
|
|
733
|
+ ->GetAccessible(mInternalID & ~IS_REMOTE);
|
|
734
|
+ }
|
|
735
|
+
|
|
736
|
+ Accessible* accessible =
|
|
737
|
+ static_cast<LocalAccessible*>(mDoc.get())
|
|
738
|
+ ->AsDoc()
|
|
739
|
+ ->GetAccessibleByUniqueID(reinterpret_cast<void*>(mInternalID));
|
|
740
|
+ // If the accessible is retrievable from the DocAccessible, it can't be
|
|
741
|
+ // defunct.
|
|
742
|
+ MOZ_ASSERT(!accessible->AsLocal()->IsDefunct());
|
|
743
|
+
|
|
744
|
+ return accessible;
|
|
745
|
+}
|
|
746
|
+
|
708
|
747
|
void SessionAccessibility::RegisterAccessible(Accessible* aAccessible) {
|
709
|
748
|
if (IPCAccessibilityActive()) {
|
710
|
749
|
// Don't register accessible in content process.
|
... |
... |
@@ -766,7 +805,6 @@ void SessionAccessibility::UnregisterAccessible(Accessible* aAccessible) { |
766
|
805
|
}
|
767
|
806
|
|
768
|
807
|
RefPtr<SessionAccessibility> sessionAcc = GetInstanceFor(aAccessible);
|
769
|
|
- MOZ_ASSERT(sessionAcc, "Need SessionAccessibility to unregister Accessible!");
|
770
|
808
|
if (sessionAcc) {
|
771
|
809
|
Accessible* registeredAcc =
|
772
|
810
|
sessionAcc->mIDToAccessibleMap.Get(virtualViewID);
|
accessible/android/SessionAccessibility.h
... |
... |
@@ -110,10 +110,34 @@ class SessionAccessibility final |
110
|
110
|
jni::NativeWeakPtr<widget::GeckoViewSupport> mWindow; // Parent only
|
111
|
111
|
java::SessionAccessibility::NativeProvider::GlobalRef mSessionAccessibility;
|
112
|
112
|
|
|
113
|
+ class IDMappingEntry {
|
|
114
|
+ public:
|
|
115
|
+ explicit IDMappingEntry(Accessible* aAccessible);
|
|
116
|
+
|
|
117
|
+ IDMappingEntry& operator=(Accessible* aAccessible);
|
|
118
|
+
|
|
119
|
+ operator Accessible*() const;
|
|
120
|
+
|
|
121
|
+ private:
|
|
122
|
+ // A strong reference to a DocAccessible or DocAccessibleParent. They don't
|
|
123
|
+ // share any useful base class except nsISupports, so we use that.
|
|
124
|
+ // When we retrieve the document from this reference we cast it to
|
|
125
|
+ // LocalAccessible in the DocAccessible case because DocAccessible has
|
|
126
|
+ // multiple inheritance paths for nsISupports.
|
|
127
|
+ RefPtr<nsISupports> mDoc;
|
|
128
|
+ // The ID of the accessible as used in the internal doc mapping.
|
|
129
|
+ // We rely on this ID being pointer derived and therefore divisible by two
|
|
130
|
+ // so we can use the first bit to mark if it is remote or not.
|
|
131
|
+ uint64_t mInternalID;
|
|
132
|
+
|
|
133
|
+ static const uintptr_t IS_REMOTE = 0x1;
|
|
134
|
+ };
|
|
135
|
+
|
113
|
136
|
/*
|
114
|
137
|
* This provides a mapping from 32 bit id to accessible objects.
|
115
|
138
|
*/
|
116
|
|
- nsTHashMap<nsUint32HashKey, Accessible*> mIDToAccessibleMap;
|
|
139
|
+ nsBaseHashtable<nsUint32HashKey, IDMappingEntry, Accessible*>
|
|
140
|
+ mIDToAccessibleMap;
|
117
|
141
|
};
|
118
|
142
|
|
119
|
143
|
} // namespace a11y
|
accessible/ipc/DocAccessibleParent.cpp
... |
... |
@@ -29,7 +29,6 @@ |
29
|
29
|
#endif
|
30
|
30
|
|
31
|
31
|
#if defined(ANDROID)
|
32
|
|
-# include "mozilla/a11y/SessionAccessibility.h"
|
33
|
32
|
# define ACQUIRE_ANDROID_LOCK \
|
34
|
33
|
MonitorAutoLock mal(nsAccessibilityService::GetAndroidMonitor());
|
35
|
34
|
#else
|
accessible/ipc/DocAccessibleParent.h
... |
... |
@@ -29,10 +29,6 @@ class xpcAccessibleGeneric; |
29
|
29
|
class DocAccessiblePlatformExtParent;
|
30
|
30
|
#endif
|
31
|
31
|
|
32
|
|
-#ifdef ANDROID
|
33
|
|
-class SessionAccessibility;
|
34
|
|
-#endif
|
35
|
|
-
|
36
|
32
|
/*
|
37
|
33
|
* These objects live in the main process and comunicate with and represent
|
38
|
34
|
* an accessible document in a content process.
|
... |
... |
@@ -348,10 +344,6 @@ class DocAccessibleParent : public RemoteAccessible, |
348
|
344
|
|
349
|
345
|
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) override;
|
350
|
346
|
|
351
|
|
-#ifdef ANDROID
|
352
|
|
- RefPtr<SessionAccessibility> mSessionAccessibility;
|
353
|
|
-#endif
|
354
|
|
-
|
355
|
347
|
private:
|
356
|
348
|
~DocAccessibleParent();
|
357
|
349
|
|
accessible/ipc/moz.build
... |
... |
@@ -24,11 +24,6 @@ else: |
24
|
24
|
LOCAL_INCLUDES += [
|
25
|
25
|
"/accessible/mac",
|
26
|
26
|
]
|
27
|
|
- elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "android":
|
28
|
|
- LOCAL_INCLUDES += [
|
29
|
|
- "/accessible/android",
|
30
|
|
- "/widget/android",
|
31
|
|
- ]
|
32
|
27
|
else:
|
33
|
28
|
LOCAL_INCLUDES += [
|
34
|
29
|
"/accessible/other",
|
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,
|
js/src/gc/GC.cpp
... |
... |
@@ -1331,6 +1331,11 @@ void GCRuntime::assertNoMarkingWork() const { |
1331
|
1331
|
}
|
1332
|
1332
|
#endif
|
1333
|
1333
|
|
|
1334
|
+static size_t GetGCParallelThreadCount() {
|
|
1335
|
+ AutoLockHelperThreadState lock;
|
|
1336
|
+ return HelperThreadState().getGCParallelThreadCount(lock);
|
|
1337
|
+}
|
|
1338
|
+
|
1334
|
1339
|
bool GCRuntime::updateMarkersVector() {
|
1335
|
1340
|
MOZ_ASSERT(helperThreadCount >= 1,
|
1336
|
1341
|
"There must always be at least one mark task");
|
... |
... |
@@ -1339,8 +1344,8 @@ bool GCRuntime::updateMarkersVector() { |
1339
|
1344
|
|
1340
|
1345
|
// Limit worker count to number of GC parallel tasks that can run
|
1341
|
1346
|
// concurrently, otherwise one thread can deadlock waiting on another.
|
1342
|
|
- size_t targetCount = std::min(markingWorkerCount(),
|
1343
|
|
- HelperThreadState().getGCParallelThreadCount());
|
|
1347
|
+ size_t targetCount =
|
|
1348
|
+ std::min(markingWorkerCount(), GetGCParallelThreadCount());
|
1344
|
1349
|
|
1345
|
1350
|
if (markers.length() > targetCount) {
|
1346
|
1351
|
return markers.resize(targetCount);
|
js/src/gc/ParallelMarking.cpp
... |
... |
@@ -103,6 +103,10 @@ bool ParallelMarker::markOneColor(MarkColor color, SliceBudget& sliceBudget) { |
103
|
103
|
{
|
104
|
104
|
AutoLockHelperThreadState lock;
|
105
|
105
|
|
|
106
|
+ // There should always be enough parallel tasks to run our marking work.
|
|
107
|
+ MOZ_RELEASE_ASSERT(HelperThreadState().getGCParallelThreadCount(lock) >=
|
|
108
|
+ workerCount());
|
|
109
|
+
|
106
|
110
|
for (size_t i = 0; i < workerCount(); i++) {
|
107
|
111
|
gc->startTask(*tasks[i], lock);
|
108
|
112
|
}
|
js/src/vm/HelperThreadState.h
... |
... |
@@ -333,9 +333,11 @@ class GlobalHelperThreadState { |
333
|
333
|
|
334
|
334
|
GCParallelTaskList& gcParallelWorklist() { return gcParallelWorklist_; }
|
335
|
335
|
|
336
|
|
- size_t getGCParallelThreadCount() const { return gcParallelThreadCount; }
|
|
336
|
+ size_t getGCParallelThreadCount(const AutoLockHelperThreadState& lock) const {
|
|
337
|
+ return gcParallelThreadCount;
|
|
338
|
+ }
|
337
|
339
|
void setGCParallelThreadCount(size_t count,
|
338
|
|
- const AutoLockHelperThreadState&) {
|
|
340
|
+ const AutoLockHelperThreadState& lock) {
|
339
|
341
|
MOZ_ASSERT(count >= 1);
|
340
|
342
|
MOZ_ASSERT(count <= threadCount);
|
341
|
343
|
gcParallelThreadCount = count;
|
|