ma1 pushed to branch base-browser-115.1.0esr-13.0-1 at The Tor Project / Applications / Tor Browser
Commits:
-
45b89a93
by Edgar Chen at 2023-08-01T17:39:54+02:00
-
1b031e60
by Edgar Chen at 2023-08-01T17:39:54+02:00
-
33af6b34
by Eitan Isaacson at 2023-08-01T17:39:55+02:00
-
65183e25
by Jon Coppeard at 2023-08-01T17:39:55+02:00
12 changed files:
- accessible/android/SessionAccessibility.cpp
- accessible/android/SessionAccessibility.h
- accessible/ipc/DocAccessibleParent.cpp
- accessible/ipc/DocAccessibleParent.h
- accessible/ipc/moz.build
- browser/base/content/browser-fullScreenAndPointerLock.js
- browser/base/content/fullscreen-and-pointerlock.inc.xhtml
- browser/base/content/test/fullscreen/browser_fullscreen_warning.js
- dom/tests/browser/browser_pointerlock_warning.js
- js/src/gc/GC.cpp
- js/src/gc/ParallelMarking.cpp
- js/src/vm/HelperThreadState.h
Changes:
... | ... | @@ -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);
|
... | ... | @@ -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
|
... | ... | @@ -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
|
... | ... | @@ -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 |
... | ... | @@ -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",
|
... | ... | @@ -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 | };
|
... | ... | @@ -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>
|
... | ... | @@ -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 | }); |
... | ... | @@ -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,
|
... | ... | @@ -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);
|
... | ... | @@ -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 | }
|
... | ... | @@ -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;
|