Merge autoland to mozilla-central. a=merge

This commit is contained in:
criss 2022-03-24 11:35:23 +02:00
Родитель 63c12c5c85 f0ccbd470c
Коммит 0077f22487
127 изменённых файлов: 2209 добавлений и 738 удалений

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

@ -105,26 +105,6 @@ nsresult nsTextEquivUtils::AppendTextEquivFromContent(
nsresult nsTextEquivUtils::AppendTextEquivFromTextContent(nsIContent* aContent,
nsAString* aString) {
if (aContent->IsText()) {
bool isHTMLBlock = false;
nsIContent* parentContent = aContent->GetFlattenedTreeParent();
if (parentContent) {
nsIFrame* frame = parentContent->GetPrimaryFrame();
if (frame) {
// If this text is inside a block level frame (as opposed to span
// level), we need to add spaces around that block's text, so we don't
// get words jammed together in final name.
const nsStyleDisplay* display = frame->StyleDisplay();
if (display->IsBlockOutsideStyle() ||
display->mDisplay == StyleDisplay::TableCell) {
isHTMLBlock = true;
if (!aString->IsEmpty()) {
aString->Append(char16_t(' '));
}
}
}
}
if (aContent->TextLength() > 0) {
nsIFrame* frame = aContent->GetPrimaryFrame();
if (frame) {
@ -136,9 +116,6 @@ nsresult nsTextEquivUtils::AppendTextEquivFromTextContent(nsIContent* aContent,
// If aContent is an object that is display: none, we have no a frame.
aContent->GetAsText()->AppendTextTo(*aString);
}
if (isHTMLBlock && !aString->IsEmpty()) {
aString->Append(char16_t(' '));
}
}
return NS_OK;
@ -184,10 +161,27 @@ nsresult nsTextEquivUtils::AppendFromAccessibleChildren(
nsresult nsTextEquivUtils::AppendFromAccessible(Accessible* aAccessible,
nsAString* aString) {
// XXX: is it necessary to care the accessible is not a document?
bool isHTMLBlock = false;
if (aAccessible->IsLocal() && aAccessible->AsLocal()->IsContent()) {
nsresult rv = AppendTextEquivFromTextContent(
aAccessible->AsLocal()->GetContent(), aString);
nsIContent* content = aAccessible->AsLocal()->GetContent();
nsresult rv = AppendTextEquivFromTextContent(content, aString);
if (rv != NS_OK_NO_NAME_CLAUSE_HANDLED) return rv;
if (!content->IsText()) {
nsIFrame* frame = content->GetPrimaryFrame();
if (frame) {
// If this is a block level frame (as opposed to span level), we need to
// add spaces around that block's text, so we don't get words jammed
// together in final name.
const nsStyleDisplay* display = frame->StyleDisplay();
if (display->IsBlockOutsideStyle() ||
display->mDisplay == StyleDisplay::TableCell) {
isHTMLBlock = true;
if (!aString->IsEmpty()) {
aString->Append(char16_t(' '));
}
}
}
}
}
bool isEmptyTextEquiv = true;
@ -220,9 +214,15 @@ nsresult nsTextEquivUtils::AppendFromAccessible(Accessible* aAccessible,
// Implementation of h. step
if (isEmptyTextEquiv && !text.IsEmpty()) {
AppendString(aString, text);
if (isHTMLBlock) {
aString->Append(char16_t(' '));
}
return NS_OK;
}
if (!isEmptyTextEquiv && isHTMLBlock) {
aString->Append(char16_t(' '));
}
return rv;
}

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

@ -3366,6 +3366,15 @@ already_AddRefed<AccAttributes> LocalAccessible::BundleFieldsForCache(
mStateFlags &= ~eOldFrameHasValidTransformStyle;
}
}
if (IsDoc()) {
if (PresShell* presShell = AsDoc()->PresShellPtr()) {
// Send the initial resolution of the document. When this changes, we
// will ne notified via nsAS::NotifyOfResolutionChange
float resolution = presShell->GetResolution();
fields->SetAttribute(nsGkAtoms::resolution, resolution);
}
}
}
return fields.forget();

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

@ -423,6 +423,7 @@ LayoutDeviceIntRect RemoteAccessibleBase<Derived>::Bounds() const {
// be scaled relative to its parent doc.
res = remoteAcc->AsDoc()->mCachedFields->GetAttribute<float>(
nsGkAtoms::resolution);
MOZ_ASSERT(res, "No cached document resolution found.");
bounds.ScaleRoundOut(res.valueOr(1.0f));
}

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

@ -58,10 +58,9 @@
// spaces)
testName("btn_labelledby_mixed_block", "text more text");
// Gets the name from text nodes contained by html:td (every text node
// value in the name should be devided by spaces).
// XXX: this case is rather a feature than strong wanted behaviour.
testName("btn_labelledby_mixed_table", "text space text");
// Gets the name from text nodes contained by html:td. The text nodes
// should not be divided by spaces.
testName("btn_labelledby_mixed_table", "textTEXTtext");
// Gets the name from image accessible.
testName("btn_labelledby_mixed_img", "text image");
@ -251,6 +250,17 @@
// Name from subtree of grouping labelled by an ancestor.
testName("grouping_labelledby_ancestor", "label");
// Name from subtree of a container containing text nodes and inline
// elements. There should be no spaces because everyhing is inline.
testName("container_text_inline", "abc");
// Name from subtree of a container containing text nodes and block
// elements. There should be a space on both sides of the block.
testName("container_text_block", "a b c");
// Name from subtree of a container containing text nodes and empty
// block elements. There should be space on either side of the blocks, but
// not a double space.
testName("container_text_emptyblock", "a b");
SimpleTest.finish();
}
@ -387,7 +397,7 @@
<!-- the name from subtree, mixed content, table structure -->
<table><tr>
<td id="labelledby_mixed_table">text<span>space</span>text</td>
<td id="labelledby_mixed_table">text<span>TEXT</span>text</td>
</tr></table>
<button id="btn_labelledby_mixed_table"
aria-labelledby="labelledby_mixed_table">5</button>
@ -711,5 +721,12 @@
This content should not be included in the grouping's label.
</div>
</div>
<!-- Text nodes and inline elements. -->
<div id="container_text_inline" role="option">a<strong>b</strong>c</div>
<!-- Text nodes and block elements. -->
<div id="container_text_block" role="option">a<p>b</p>c</div>
<!-- Text nodes and empty block elements. -->
<div id="container_text_emptyblock" role="option">a<p></p><p></p>b</div>
</body>
</html>

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

@ -70,6 +70,8 @@ skip-if =
apple_catalina # platform migration
apple_silicon # bug 1707735
[browser_devices_get_user_media_unprompted_access.js]
skip-if =
os == "linux" && bits == 64 && !debug # Bug 1712012
https_first_disabled = true
[browser_devices_get_user_media_unprompted_access_in_frame.js]
https_first_disabled = true

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

@ -28,7 +28,8 @@ skip-if = (os == 'win' && os_version == '10.0' && ccov) # Bug 1306510
[browser_library_clearall.js]
[browser_download_opens_on_click.js]
[browser_download_spam_protection.js]
skip-if = os == "linux" && bits == 64 && !debug # bug 1743263
skip-if =
os == "linux" && bits == 64 # bug 1743263 & Bug 1742678
support-files = test_spammy_page.html
[browser_download_is_clickable.js]
[browser_downloads_keynav.js]

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

@ -802,6 +802,10 @@ this.tabs = class extends ExtensionAPI {
tabListener.initializingTabs.add(nativeTab);
}
if (createProperties.muted) {
nativeTab.toggleMuteAudio(extension.id);
}
return tabManager.convert(nativeTab, currentTabSize);
});
},

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

@ -612,6 +612,11 @@
"type": "string",
"optional": true,
"description": "The title used for display if the tab is created in discarded mode."
},
"muted": {
"type": "boolean",
"optional": true,
"description": "Whether the tab should be muted when created."
}
}
},

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

@ -50,6 +50,11 @@ add_task(async function test_create_options() {
// 'selected' is marked as unsupported in schema, so we've removed it.
// For more details, see bug 1337509
selected: undefined,
mutedInfo: {
muted: false,
extensionId: undefined,
reason: undefined,
},
};
let tests = [
@ -132,6 +137,26 @@ add_task(async function test_create_options() {
)}`,
},
},
{
create: { muted: true },
result: {
mutedInfo: {
muted: true,
extensionId: browser.runtime.id,
reason: "extension",
},
},
},
{
create: { muted: false },
result: {
mutedInfo: {
muted: false,
extensionId: undefined,
reason: undefined,
},
},
},
];
async function nextTest() {
@ -182,11 +207,21 @@ add_task(async function test_create_options() {
continue;
}
browser.test.assertEq(
expected[key],
tab[key],
`Expected value for tab.${key}`
);
if (key === "mutedInfo") {
for (let key of Object.keys(expected.mutedInfo)) {
browser.test.assertEq(
expected.mutedInfo[key],
tab.mutedInfo[key],
`Expected value for tab.mutedInfo.${key}`
);
}
} else {
browser.test.assertEq(
expected[key],
tab[key],
`Expected value for tab.${key}`
);
}
}
let updated = await updatedPromise;

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

@ -11,6 +11,8 @@ prefs =
support-files =
ds_layout.json
topstories.json
skip-if =
socketprocess_networking # Bug 1759035
[test_AboutNewTab.js]
[test_AboutWelcomeAttribution.js]

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

@ -295,7 +295,7 @@ const Snapshots = new (class Snapshots {
* The url up until, but not including, any fragments
*/
stripFragments(url) {
return url.split("#")[0];
return url?.split("#")[0];
}
/**

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

@ -38,6 +38,11 @@ add_setup(async () => {
});
add_task(async function test_stripFragments() {
Assert.equal(
Snapshots.stripFragments(),
undefined,
"stripFragments should handle undefined as an argument"
);
Assert.equal(
Snapshots.stripFragments(TEST_FRAGMENT_URL1),
TEST_URL1,

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

@ -2,8 +2,7 @@
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that we adult sites are correctly filtered from snapshot selections
* when requested.
* Test that we correctly handle urls with fragments in snapshot selection
*/
const TEST_URL1 = "https://example.com/";

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

@ -78,7 +78,7 @@ add_task(async function switchToTab() {
// before the result.
await getResultText(
element,
"Firefox Suggest about: robots— Switch to Tab",
"Firefox Suggest about:robots — Switch to Tab",
"Result a11y text is correct"
);
@ -116,9 +116,8 @@ add_task(async function searchSuggestions() {
);
// The first expected search is the search term itself since the heuristic
// result will come before the search suggestions.
// The extra spaces are here due to bug 1550644.
let searchTerm = "foo ";
let expectedSearches = [searchTerm, "foo foo", "foo bar"];
let searchTerm = "foo";
let expectedSearches = [searchTerm, "foofoo", "foobar"];
for (let i = 0; i < length; i++) {
let result = await UrlbarTestUtils.getDetailsOfResultAt(window, i);
if (result.type === UrlbarUtils.RESULT_TYPE.SEARCH) {
@ -140,7 +139,7 @@ add_task(async function searchSuggestions() {
if (result.searchParams.inPrivateWindow) {
await getResultText(
element,
searchTerm + "— Search in a Private Window",
searchTerm + " — Search in a Private Window",
"Check result label"
);
} else {
@ -148,7 +147,7 @@ add_task(async function searchSuggestions() {
await getResultText(
element,
suggestion +
"— Search with browser_searchSuggestionEngine searchSuggestionEngine.xml",
" — Search with browser_searchSuggestionEngine searchSuggestionEngine.xml",
"Check result label"
);
}

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

@ -609,6 +609,20 @@ const AVAILABLE_INJECTIONS = [
],
},
},
{
id: "bug1739489",
platform: "desktop",
domain: "draft.js",
bug: "1739489",
contentScripts: {
matches: ["*://draftjs.org/*", "*://www.facebook.com/*"],
js: [
{
file: "injections/js/bug1739489-draftjs-beforeinput.js",
},
],
},
},
];
module.exports = AVAILABLE_INJECTIONS;

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

@ -0,0 +1,35 @@
"use strict";
/**
* Bug 1739489 - Entering an emoji using the MacOS IME "crashes" Draft.js editors.
*/
/* globals exportFunction */
console.info(
"textInput event has been remapped to beforeinput for compatibility reasons. See https://bugzilla.mozilla.org/show_bug.cgi?id=1739489 for details."
);
window.wrappedJSObject.TextEvent = window.wrappedJSObject.InputEvent;
const { CustomEvent, Event, EventTarget } = window.wrappedJSObject;
var Remapped = [
[CustomEvent, "constructor"],
[Event, "constructor"],
[Event, "initEvent"],
[EventTarget, "addEventListener"],
[EventTarget, "removeEventListener"],
];
for (const [obj, name] of Remapped) {
const { prototype } = obj;
const orig = prototype[name];
Object.defineProperty(prototype, name, {
value: exportFunction(function(type, b, c, d) {
if (type?.toLowerCase() === "textinput") {
type = "beforeinput";
}
return orig.call(this, type, b, c, d);
}, window),
});
}

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

@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "Web Compatibility Interventions",
"description": "Urgent post-release fixes for web compatibility.",
"version": "31.0.0",
"version": "31.1.0",
"applications": {
"gecko": {
"id": "webcompat@mozilla.org",

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

@ -83,6 +83,7 @@ FINAL_TARGET_FILES.features["webcompat@mozilla.org"]["injections"]["js"] += [
"injections/js/bug1724764-amextravel.com-window-print.js",
"injections/js/bug1724868-news.yahoo.co.jp-ua-override.js",
"injections/js/bug1731825-office365-email-handling-prompt-autohide.js",
"injections/js/bug1739489-draftjs-beforeinput.js",
"injections/js/bug1756692-effectiveType-shim.js",
]

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

@ -64,6 +64,8 @@ skip-if = debug # Window leaks: bug 1575332
[browser_dbg-breakpoints-in-evaled-sources.js]
[browser_dbg-breakpoints-list.js]
[browser_dbg-breakpoints-popup.js]
skip-if =
os == 'linux' && bits == 64 && debug # Bug 1750199
[browser_dbg-browser-content-toolbox.js]
skip-if = !e10s || verify # This test is only valid in e10s
[browser_dbg-continue-to-here.js]

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

@ -211,6 +211,7 @@ skip-if = (os == 'win' && processor == 'aarch64') # bug 1533492
[browser_inspector_picker-shift-key.js]
[browser_inspector_picker-stop-on-eyedropper.js]
[browser_inspector_picker-stop-on-tool-change.js]
[browser_inspector_picker-useragent-widget.js]
[browser_inspector_portrait_mode.js]
[browser_inspector_pseudoclass-lock.js]
[browser_inspector_pseudoclass-menu.js]

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

@ -0,0 +1,73 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const TEST_URI = `data:text/html;charset=utf-8,
<!DOCTYPE html>
<video controls></video>`;
// Test that using the node picker on user agent widgets only selects shadow dom
// elements if `devtools.inspector.showAllAnonymousContent` is true.
// If not, we should only surface the host, in this case, the <video>.
//
// For this test we use a <video controls> tag, which is using shadow dom.
add_task(async function() {
// Run the test for both values for devtools.inspector.showAllAnonymousContent
await runUserAgentWidgetPickerTest({ enableAnonymousContent: false });
await runUserAgentWidgetPickerTest({ enableAnonymousContent: true });
});
async function runUserAgentWidgetPickerTest({ enableAnonymousContent }) {
await pushPref(
"devtools.inspector.showAllAnonymousContent",
enableAnonymousContent
);
const { inspector, toolbox } = await openInspectorForURL(TEST_URI);
info("Use the node picker inside the <video> element");
await startPicker(toolbox);
const onPickerStopped = toolbox.nodePicker.once("picker-stopped");
await pickElement(inspector, "video", 5, 5);
await onPickerStopped;
const selectedNode = inspector.selection.nodeFront;
if (enableAnonymousContent) {
// We do not assert specifically which node was selected, we just want to
// check the node was under the shadow DOM for the <video type=date>
const shadowHost = getShadowHost(selectedNode);
ok(
selectedNode.tagName.toLowerCase() !== "video",
"The selected node is not the <video>"
);
ok(shadowHost, "The selected node is in a shadow root");
is(shadowHost.tagName.toLowerCase(), "video", "The shadowHost is <video>");
} else {
is(
selectedNode.tagName.toLowerCase(),
"video",
"The selected node is the <video>"
);
}
}
/**
* Retrieve the nodeFront for the shadow host containing the provided nodeFront.
* Returns null if the nodeFront is not in a shadow DOM.
*
* @param {NodeFront} nodeFront
* The nodeFront for which we want to retrieve the shadow host.
* @return {NodeFront} The nodeFront corresponding to the shadow host, or null
* if the nodeFront is not in shadow DOM.
*/
function getShadowHost(nodeFront) {
let parent = nodeFront;
while (parent) {
if (parent.isShadowHost) {
return parent;
}
parent = parent.parentOrHost();
}
return null;
}

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

@ -70,6 +70,14 @@ class NodePicker {
node = this._findNodeAtMouseEventPosition(event) || node;
}
// The node picker should only surface elements valid for the current walker
// configuration. UserAgent shadow DOM should only be visible if
// showAllAnonymousContent is set to true. Otherwise, fallback to the host.
const shadowRoot = node.containingShadowRoot;
if (shadowRoot?.isUAWidget() && !this._walker.showAllAnonymousContent) {
node = shadowRoot.host;
}
return this._walker.attachElement(node);
}

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

@ -87,6 +87,16 @@ LabellingEventTarget::DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
LabellingEventTarget::RegisterShutdownTask(nsITargetShutdownTask*) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
LabellingEventTarget::UnregisterShutdownTask(nsITargetShutdownTask*) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
LabellingEventTarget::IsOnCurrentThread(bool* aIsOnCurrentThread) {
*aIsOnCurrentThread = NS_IsMainThread();

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

@ -1927,6 +1927,16 @@ EventSourceImpl::DelayedDispatch(already_AddRefed<nsIRunnable> aEvent,
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
EventSourceImpl::RegisterShutdownTask(nsITargetShutdownTask*) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
EventSourceImpl::UnregisterShutdownTask(nsITargetShutdownTask*) {
return NS_ERROR_NOT_IMPLEMENTED;
}
//-----------------------------------------------------------------------------
// EventSourceImpl::nsIThreadRetargetableStreamListener
//-----------------------------------------------------------------------------

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

@ -6,6 +6,7 @@
#include "RemoteLazyInputStreamThread.h"
#include "ErrorList.h"
#include "mozilla/SchedulerGroup.h"
#include "mozilla/StaticMutex.h"
#include "mozilla/StaticPtr.h"
@ -242,6 +243,16 @@ RemoteLazyInputStreamThread::DelayedDispatch(already_AddRefed<nsIRunnable>,
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
RemoteLazyInputStreamThread::RegisterShutdownTask(nsITargetShutdownTask*) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
RemoteLazyInputStreamThread::UnregisterShutdownTask(nsITargetShutdownTask*) {
return NS_ERROR_NOT_IMPLEMENTED;
}
bool IsOnDOMFileThread() {
StaticMutexAutoLock lock(gRemoteLazyThreadMutex);

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

@ -1195,6 +1195,16 @@ NestedEventTargetWrapper::DelayedDispatch(already_AddRefed<nsIRunnable> aEvent,
"NestedEventTargetWrapper");
}
NS_IMETHODIMP
NestedEventTargetWrapper::RegisterShutdownTask(nsITargetShutdownTask*) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
NestedEventTargetWrapper::UnregisterShutdownTask(nsITargetShutdownTask*) {
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult RequestHelper::StartAndReturnResponse(LSRequestResponse& aResponse) {
AssertIsOnOwningThread();

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

@ -272,7 +272,8 @@ bool WMFDecoderModule::HasH264() {
/* static */
bool WMFDecoderModule::HasVP8() {
return sUsableVPXMFT &&
// Some Intel HW MFTs would crash on VP8 decoding.
return sUsableVPXMFT && gfx::gfxVars::UseVP8HwDecode() &&
CanCreateWMFDecoder<MFT_CATEGORY_VIDEO_DECODER, MFVideoFormat_VP80>();
}

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

@ -37,6 +37,9 @@ class CallWorkerThread final : public AbstractThread,
DelayedDispatch(already_AddRefed<nsIRunnable> aEvent,
uint32_t aDelayMs) override;
NS_IMETHOD RegisterShutdownTask(nsITargetShutdownTask* aTask) override;
NS_IMETHOD UnregisterShutdownTask(nsITargetShutdownTask* aTask) override;
const UniquePtr<TaskQueueWrapper<DeletionPolicy::NonBlocking>>
mWebrtcTaskQueue;
@ -79,6 +82,16 @@ CallWorkerThread::DelayedDispatch(already_AddRefed<nsIRunnable> aEvent,
mWebrtcTaskQueue->CreateTaskRunner(std::move(event)), aDelayMs);
}
NS_IMETHODIMP CallWorkerThread::RegisterShutdownTask(
nsITargetShutdownTask* aTask) {
return mWebrtcTaskQueue->mTaskQueue->RegisterShutdownTask(aTask);
}
NS_IMETHODIMP CallWorkerThread::UnregisterShutdownTask(
nsITargetShutdownTask* aTask) {
return mWebrtcTaskQueue->mTaskQueue->UnregisterShutdownTask(aTask);
}
//-----------------------------------------------------------------------------
// nsIDirectTaskDispatcher
//-----------------------------------------------------------------------------

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

@ -762,6 +762,10 @@ WorkerPrivate* PromiseWorkerProxy::GetWorkerPrivate() const {
return mWorkerRef->Private();
}
bool PromiseWorkerProxy::OnWritingThread() const {
return IsCurrentThreadRunningWorker();
}
Promise* PromiseWorkerProxy::WorkerPromise() const {
MOZ_ASSERT(IsCurrentThreadRunningWorker());
MOZ_ASSERT(mWorkerPromise);

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

@ -117,7 +117,8 @@ class WorkerPrivate;
// references to it are dropped.
class PromiseWorkerProxy : public PromiseNativeHandler,
public StructuredCloneHolderBase {
public StructuredCloneHolderBase,
public SingleWriterLockOwner {
friend class PromiseWorkerProxyRunnable;
NS_DECL_THREADSAFE_ISUPPORTS
@ -132,6 +133,8 @@ class PromiseWorkerProxy : public PromiseNativeHandler,
PromiseWorkerProxy* aProxy,
JS::HandleObject aObj);
bool OnWritingThread() const override;
struct PromiseWorkerProxyStructuredCloneCallbacks {
ReadCallbackOp Read;
WriteCallbackOp Write;
@ -144,7 +147,7 @@ class PromiseWorkerProxy : public PromiseNativeHandler,
// Main thread callers must hold Lock() and check CleanUp() before calling
// this. Worker thread callers, this will assert that the proxy has not been
// cleaned up.
WorkerPrivate* GetWorkerPrivate() const;
WorkerPrivate* GetWorkerPrivate() const NO_THREAD_SAFETY_ANALYSIS;
// This should only be used within WorkerRunnable::WorkerRun() running on the
// worker thread! Do not call this after calling CleanUp().
@ -156,9 +159,9 @@ class PromiseWorkerProxy : public PromiseNativeHandler,
// 2. WorkerPromise() will crash!
void CleanUp();
Mutex& Lock() { return mCleanUpLock; }
Mutex& Lock() RETURN_CAPABILITY(mCleanUpLock) { return mCleanUpLock; }
bool CleanedUp() const {
bool CleanedUp() const REQUIRES(mCleanUpLock) {
mCleanUpLock.AssertCurrentThreadOwns();
return mCleanedUp;
}
@ -202,12 +205,15 @@ class PromiseWorkerProxy : public PromiseNativeHandler,
// Modified on the worker thread.
// It is ok to *read* this without a lock on the worker.
// Main thread must always acquire a lock.
bool mCleanedUp; // To specify if the cleanUp() has been done.
bool mCleanedUp
GUARDED_BY(mCleanUpLock); // To specify if the cleanUp() has been done.
const PromiseWorkerProxyStructuredCloneCallbacks* mCallbacks;
// Ensure the worker and the main thread won't race to access |mCleanedUp|.
Mutex mCleanUpLock MOZ_UNANNOTATED;
// Should be a MutexSingleWriter, but that causes a lot of issues when you
// expose the lock via Lock().
Mutex mCleanUpLock;
};
} // namespace dom
} // namespace mozilla

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

@ -189,6 +189,12 @@ MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> ReadableStreamCancel(
already_AddRefed<ReadableStreamDefaultReader>
AcquireReadableStreamDefaultReader(ReadableStream* aStream, ErrorResult& aRv);
MOZ_CAN_RUN_SCRIPT already_AddRefed<ReadableStream> CreateReadableStream(
JSContext* aCx, nsIGlobalObject* aGlobal,
UnderlyingSourceAlgorithmsBase* aAlgorithms,
mozilla::Maybe<double> aHighWaterMark, QueuingStrategySize* aSizeAlgorithm,
ErrorResult& aRv);
bool ReadableStreamHasBYOBReader(ReadableStream* aStream);
bool ReadableStreamHasDefaultReader(ReadableStream* aStream);

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

@ -6,6 +6,9 @@
#include "mozilla/dom/TransformStream.h"
#include "UnderlyingSourceCallbackHelpers.h"
#include "js/TypeDecls.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/WritableStream.h"
#include "mozilla/dom/ReadableStream.h"
#include "mozilla/dom/RootedDictionary.h"
@ -16,7 +19,9 @@
namespace mozilla::dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TransformStream, mGlobal, mController)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TransformStream, mGlobal,
mBackpressureChangePromise, mController,
mReadable, mWritable)
NS_IMPL_CYCLE_COLLECTING_ADDREF(TransformStream)
NS_IMPL_CYCLE_COLLECTING_RELEASE(TransformStream)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TransformStream)
@ -35,6 +40,216 @@ JSObject* TransformStream::WrapObject(JSContext* aCx,
return TransformStream_Binding::Wrap(aCx, this, aGivenProto);
}
// https://streams.spec.whatwg.org/#initialize-transform-stream
class TransformStreamUnderlyingSinkAlgorithms final
: public UnderlyingSinkAlgorithmsBase {
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(
TransformStreamUnderlyingSinkAlgorithms, UnderlyingSinkAlgorithmsBase)
TransformStreamUnderlyingSinkAlgorithms(Promise* aStartPromise,
TransformStream* aStream)
: mStartPromise(aStartPromise), mStream(aStream) {}
void StartCallback(JSContext* aCx,
WritableStreamDefaultController& aController,
JS::MutableHandle<JS::Value> aRetVal,
ErrorResult& aRv) override {
// Step 1. Let startAlgorithm be an algorithm that returns startPromise.
// (Same as TransformStreamUnderlyingSourceAlgorithms::StartCallback)
aRetVal.setObject(*mStartPromise->PromiseObj());
}
already_AddRefed<Promise> WriteCallback(
JSContext* aCx, JS::Handle<JS::Value> aChunk,
WritableStreamDefaultController& aController, ErrorResult& aRv) override {
// Step 2. Let writeAlgorithm be the following steps, taking a chunk
// argument:
// Step 1. Return ! TransformStreamDefaultSinkWriteAlgorithm(stream,
// chunk).
// TODO
return Promise::CreateResolvedWithUndefined(mStream->GetParentObject(),
aRv);
}
already_AddRefed<Promise> AbortCallback(
JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aReason,
ErrorResult& aRv) override {
// Step 3. Let abortAlgorithm be the following steps, taking a reason
// argument:
// Step 1. Return ! TransformStreamDefaultSinkAbortAlgorithm(stream,
// reason).
// TODO
return Promise::CreateResolvedWithUndefined(mStream->GetParentObject(),
aRv);
}
already_AddRefed<Promise> CloseCallback(JSContext* aCx,
ErrorResult& aRv) override {
// Step 4. Let closeAlgorithm be the following steps:
// Step 1. Return ! TransformStreamDefaultSinkCloseAlgorithm(stream).
// TODO
return Promise::CreateResolvedWithUndefined(mStream->GetParentObject(),
aRv);
}
protected:
~TransformStreamUnderlyingSinkAlgorithms() override = default;
private:
RefPtr<Promise> mStartPromise;
RefPtr<TransformStream> mStream;
};
NS_IMPL_CYCLE_COLLECTION_INHERITED(TransformStreamUnderlyingSinkAlgorithms,
UnderlyingSinkAlgorithmsBase, mStartPromise,
mStream)
NS_IMPL_ADDREF_INHERITED(TransformStreamUnderlyingSinkAlgorithms,
UnderlyingSinkAlgorithmsBase)
NS_IMPL_RELEASE_INHERITED(TransformStreamUnderlyingSinkAlgorithms,
UnderlyingSinkAlgorithmsBase)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TransformStreamUnderlyingSinkAlgorithms)
NS_INTERFACE_MAP_END_INHERITING(TransformStreamUnderlyingSinkAlgorithms)
// https://streams.spec.whatwg.org/#initialize-transform-stream
class TransformStreamUnderlyingSourceAlgorithms final
: public UnderlyingSourceAlgorithmsBase {
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(
TransformStreamUnderlyingSourceAlgorithms, UnderlyingSourceAlgorithmsBase)
TransformStreamUnderlyingSourceAlgorithms(Promise* aStartPromise,
TransformStream* aStream)
: mStartPromise(aStartPromise), mStream(aStream) {}
void StartCallback(JSContext* aCx, ReadableStreamController& aController,
JS::MutableHandle<JS::Value> aRetVal,
ErrorResult& aRv) override {
// Step 1. Let startAlgorithm be an algorithm that returns startPromise.
// (Same as TransformStreamUnderlyingSinkAlgorithms::StartCallback)
aRetVal.setObject(*mStartPromise->PromiseObj());
}
already_AddRefed<Promise> PullCallback(JSContext* aCx,
ReadableStreamController& aController,
ErrorResult& aRv) override {
// Step 6. Let pullAlgorithm be the following steps:
// Step 1. Return ! TransformStreamDefaultSourcePullAlgorithm(stream).
// TODO
return Promise::CreateResolvedWithUndefined(mStream->GetParentObject(),
aRv);
}
already_AddRefed<Promise> CancelCallback(
JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aReason,
ErrorResult& aRv) override {
// Step 7. Let cancelAlgorithm be the following steps, taking a reason
// argument:
// Step 1. Perform ! TransformStreamErrorWritableAndUnblockWrite(stream,
// reason).
// Step 2. Return a promise resolved with undefined.
// TODO
return Promise::CreateResolvedWithUndefined(mStream->GetParentObject(),
aRv);
}
void ErrorCallback() override {}
protected:
~TransformStreamUnderlyingSourceAlgorithms() override = default;
private:
RefPtr<Promise> mStartPromise;
RefPtr<TransformStream> mStream;
};
NS_IMPL_CYCLE_COLLECTION_INHERITED(TransformStreamUnderlyingSourceAlgorithms,
UnderlyingSourceAlgorithmsBase,
mStartPromise, mStream)
NS_IMPL_ADDREF_INHERITED(TransformStreamUnderlyingSourceAlgorithms,
UnderlyingSourceAlgorithmsBase)
NS_IMPL_RELEASE_INHERITED(TransformStreamUnderlyingSourceAlgorithms,
UnderlyingSourceAlgorithmsBase)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
TransformStreamUnderlyingSourceAlgorithms)
NS_INTERFACE_MAP_END_INHERITING(TransformStreamUnderlyingSourceAlgorithms)
// https://streams.spec.whatwg.org/#transform-stream-set-backpressure
static void TransformStreamSetBackpressure(TransformStream* aStream,
bool aBackpressure,
ErrorResult& aRv) {
// Step 1. Assert: stream.[[backpressure]] is not backpressure.
MOZ_ASSERT(aStream->Backpressure() != aBackpressure);
// Step 2. If stream.[[backpressureChangePromise]] is not undefined, resolve
// stream.[[backpressureChangePromise]] with undefined.
if (Promise* promise = aStream->BackpressureChangePromise()) {
promise->MaybeResolveWithUndefined();
}
// Step 3. Set stream.[[backpressureChangePromise]] to a new promise.
RefPtr<Promise> promise = Promise::Create(aStream->GetParentObject(), aRv);
if (aRv.Failed()) {
return;
}
aStream->SetBackpressureChangePromise(promise);
// Step 4. Set stream.[[backpressure]] to backpressure.
aStream->SetBackpressure(aBackpressure);
}
// https://streams.spec.whatwg.org/#initialize-transform-stream
void TransformStream::Initialize(JSContext* aCx, Promise* aStartPromise,
double aWritableHighWaterMark,
QueuingStrategySize* aWritableSizeAlgorithm,
double aReadableHighWaterMark,
QueuingStrategySize* aReadableSizeAlgorithm,
ErrorResult& aRv) {
// Step 1 - 4
auto sinkAlgorithms =
MakeRefPtr<TransformStreamUnderlyingSinkAlgorithms>(aStartPromise, this);
// Step 5. Set stream.[[writable]] to ! CreateWritableStream(startAlgorithm,
// writeAlgorithm, closeAlgorithm, abortAlgorithm, writableHighWaterMark,
// writableSizeAlgorithm).
mWritable =
CreateWritableStream(aCx, MOZ_KnownLive(mGlobal), sinkAlgorithms,
aWritableHighWaterMark, aWritableSizeAlgorithm, aRv);
if (aRv.Failed()) {
return;
}
// Step 6 - 7
auto sourceAlgorithms = MakeRefPtr<TransformStreamUnderlyingSourceAlgorithms>(
aStartPromise, this);
// Step 8. Set stream.[[readable]] to ! CreateReadableStream(startAlgorithm,
// pullAlgorithm, cancelAlgorithm, readableHighWaterMark,
// readableSizeAlgorithm).
mReadable = CreateReadableStream(
aCx, MOZ_KnownLive(mGlobal), sourceAlgorithms,
Some(aReadableHighWaterMark), aReadableSizeAlgorithm, aRv);
if (aRv.Failed()) {
return;
}
// Step 9. Set stream.[[backpressure]] and
// stream.[[backpressureChangePromise]] to undefined.
mBackpressureChangePromise = nullptr;
// Step 10. Perform ! TransformStreamSetBackpressure(stream, true).
TransformStreamSetBackpressure(this, true, aRv);
if (aRv.Failed()) {
return;
}
// Step 11. Set stream.[[controller]] to undefined.
mController = nullptr;
}
// https://streams.spec.whatwg.org/#ts-constructor
already_AddRefed<TransformStream> TransformStream::Constructor(
const GlobalObject& aGlobal,
@ -79,19 +294,35 @@ already_AddRefed<TransformStream> TransformStream::Constructor(
// Step 5. Let readableHighWaterMark be ?
// ExtractHighWaterMark(readableStrategy, 0).
// TODO
double readableHighWaterMark =
ExtractHighWaterMark(aReadableStrategy, 0, aRv);
if (aRv.Failed()) {
return nullptr;
}
// Step 6. Let readableSizeAlgorithm be !
// ExtractSizeAlgorithm(readableStrategy).
// TODO
// Note: Callers should recognize nullptr as a callback that returns 1. See
// also ReadableStream::Constructor for this design decision.
RefPtr<QueuingStrategySize> readableSizeAlgorithm =
aReadableStrategy.mSize.WasPassed() ? &aReadableStrategy.mSize.Value()
: nullptr;
// Step 7. Let writableHighWaterMark be ?
// ExtractHighWaterMark(writableStrategy, 1).
// TODO
double writableHighWaterMark =
ExtractHighWaterMark(aWritableStrategy, 1, aRv);
if (aRv.Failed()) {
return nullptr;
}
// Step 8. Let writableSizeAlgorithm be !
// ExtractSizeAlgorithm(writableStrategy).
// TODO
// Note: Callers should recognize nullptr as a callback that returns 1. See
// also WritableStream::Constructor for this design decision.
RefPtr<QueuingStrategySize> writableSizeAlgorithm =
aWritableStrategy.mSize.WasPassed() ? &aWritableStrategy.mSize.Value()
: nullptr;
// Step 9. Let startPromise be a new promise.
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
@ -104,7 +335,9 @@ already_AddRefed<TransformStream> TransformStream::Constructor(
// writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark,
// readableSizeAlgorithm).
RefPtr<TransformStream> transformStream = new TransformStream(global);
// TODO: Init()
transformStream->Initialize(
aGlobal.Context(), startPromise, writableHighWaterMark,
writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm, aRv);
if (aRv.Failed()) {
return nullptr;
}
@ -118,7 +351,22 @@ already_AddRefed<TransformStream> TransformStream::Constructor(
// Step 12. If transformerDict["start"] exists, then resolve startPromise with
// the result of invoking transformerDict["start"] with argument list «
// this.[[controller]] » and callback this value transformer.
// TODO
if (transformerDict.mStart.WasPassed()) {
RefPtr<TransformerStartCallback> callback = transformerDict.mStart.Value();
RefPtr<TransformStreamDefaultController> controller =
transformStream->Controller();
JS::Rooted<JS::Value> retVal(aGlobal.Context());
callback->Call(transformerObj, *controller, &retVal, aRv,
"Transformer.start", CallbackFunction::eRethrowExceptions);
if (aRv.Failed()) {
return nullptr;
}
startPromise->MaybeResolve(retVal);
} else {
// Step 13. Otherwise, resolve startPromise with undefined.
startPromise->MaybeResolveWithUndefined();
}
return transformStream.forget();
}

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

@ -29,6 +29,13 @@ class TransformStream final : public nsISupports, public nsWrapperCache {
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TransformStream)
// Internal slot accessors
bool Backpressure() const { return mBackpressure; }
void SetBackpressure(bool aBackpressure) { mBackpressure = aBackpressure; }
Promise* BackpressureChangePromise() { return mBackpressureChangePromise; }
void SetBackpressureChangePromise(Promise* aPromise) {
mBackpressureChangePromise = aPromise;
}
TransformStreamDefaultController* Controller() { return mController; }
void SetController(TransformStreamDefaultController* aController) {
mController = aController;
@ -38,6 +45,12 @@ class TransformStream final : public nsISupports, public nsWrapperCache {
~TransformStream();
explicit TransformStream(nsIGlobalObject* aGlobal);
MOZ_CAN_RUN_SCRIPT void Initialize(
JSContext* aCx, Promise* aStartPromise, double aWritableHighWaterMark,
QueuingStrategySize* aWritableSizeAlgorithm,
double aReadableHighWaterMark,
QueuingStrategySize* aReadableSizeAlgorithm, ErrorResult& aRv);
public:
nsIGlobalObject* GetParentObject() const { return mGlobal; }
JSObject* WrapObject(JSContext* aCx,
@ -58,7 +71,11 @@ class TransformStream final : public nsISupports, public nsWrapperCache {
nsCOMPtr<nsIGlobalObject> mGlobal;
// Internal slots
bool mBackpressure = false;
RefPtr<Promise> mBackpressureChangePromise;
RefPtr<TransformStreamDefaultController> mController;
RefPtr<ReadableStream> mReadable;
RefPtr<WritableStream> mWritable;
};
} // namespace mozilla::dom

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

@ -9,16 +9,24 @@
using namespace mozilla::dom;
NS_IMPL_CYCLE_COLLECTION_WITH_JS_MEMBERS(UnderlyingSinkAlgorithms,
(mGlobal, mStartCallback,
mWriteCallback, mCloseCallback,
mAbortCallback),
(mUnderlyingSink))
NS_IMPL_CYCLE_COLLECTING_ADDREF(UnderlyingSinkAlgorithms)
NS_IMPL_CYCLE_COLLECTING_RELEASE(UnderlyingSinkAlgorithms)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(UnderlyingSinkAlgorithms)
NS_IMPL_CYCLE_COLLECTION(UnderlyingSinkAlgorithmsBase)
NS_IMPL_CYCLE_COLLECTING_ADDREF(UnderlyingSinkAlgorithmsBase)
NS_IMPL_CYCLE_COLLECTING_RELEASE(UnderlyingSinkAlgorithmsBase)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(UnderlyingSinkAlgorithmsBase)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(UnderlyingSinkAlgorithmsBase)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTION_INHERITED_WITH_JS_MEMBERS(
UnderlyingSinkAlgorithms, UnderlyingSinkAlgorithmsBase,
(mGlobal, mStartCallback, mWriteCallback, mCloseCallback, mAbortCallback),
(mUnderlyingSink))
NS_IMPL_ADDREF_INHERITED(UnderlyingSinkAlgorithms, UnderlyingSinkAlgorithmsBase)
NS_IMPL_RELEASE_INHERITED(UnderlyingSinkAlgorithms,
UnderlyingSinkAlgorithmsBase)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(UnderlyingSinkAlgorithms)
NS_INTERFACE_MAP_END_INHERITING(UnderlyingSinkAlgorithmsBase)
// https://streams.spec.whatwg.org/#set-up-writable-stream-default-controller-from-underlying-sink
void UnderlyingSinkAlgorithms::StartCallback(

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

@ -11,6 +11,7 @@
#include "mozilla/HoldDropJSObjects.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/UnderlyingSinkBinding.h"
#include "nsCycleCollectionParticipant.h"
#include "nsISupports.h"
#include "nsISupportsImpl.h"
@ -23,11 +24,36 @@ namespace mozilla::dom {
class WritableStreamDefaultController;
// https://streams.spec.whatwg.org/#set-up-writable-stream-default-controller-from-underlying-sink
class UnderlyingSinkAlgorithms : public nsISupports {
class UnderlyingSinkAlgorithmsBase : public nsISupports {
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(UnderlyingSinkAlgorithms)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(UnderlyingSinkAlgorithmsBase)
MOZ_CAN_RUN_SCRIPT virtual void StartCallback(
JSContext* aCx, WritableStreamDefaultController& aController,
JS::MutableHandle<JS::Value> aRetVal, ErrorResult& aRv) = 0;
MOZ_CAN_RUN_SCRIPT virtual already_AddRefed<Promise> WriteCallback(
JSContext* aCx, JS::Handle<JS::Value> aChunk,
WritableStreamDefaultController& aController, ErrorResult& aRv) = 0;
MOZ_CAN_RUN_SCRIPT virtual already_AddRefed<Promise> CloseCallback(
JSContext* aCx, ErrorResult& aRv) = 0;
MOZ_CAN_RUN_SCRIPT virtual already_AddRefed<Promise> AbortCallback(
JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aReason,
ErrorResult& aRv) = 0;
protected:
virtual ~UnderlyingSinkAlgorithmsBase() = default;
};
// https://streams.spec.whatwg.org/#set-up-writable-stream-default-controller-from-underlying-sink
class UnderlyingSinkAlgorithms final : public UnderlyingSinkAlgorithmsBase {
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(
UnderlyingSinkAlgorithms, UnderlyingSinkAlgorithmsBase)
UnderlyingSinkAlgorithms(nsIGlobalObject* aGlobal,
JS::HandleObject aUnderlyingSink,
@ -58,21 +84,21 @@ class UnderlyingSinkAlgorithms : public nsISupports {
MOZ_CAN_RUN_SCRIPT void StartCallback(
JSContext* aCx, WritableStreamDefaultController& aController,
JS::MutableHandle<JS::Value> aRetVal, ErrorResult& aRv);
JS::MutableHandle<JS::Value> aRetVal, ErrorResult& aRv) override;
MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> WriteCallback(
JSContext* aCx, JS::Handle<JS::Value> aChunk,
WritableStreamDefaultController& aController, ErrorResult& aRv);
WritableStreamDefaultController& aController, ErrorResult& aRv) override;
MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> CloseCallback(JSContext* aCx,
ErrorResult& aRv);
MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> CloseCallback(
JSContext* aCx, ErrorResult& aRv) override;
MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> AbortCallback(
JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aReason,
ErrorResult& aRv);
ErrorResult& aRv) override;
protected:
virtual ~UnderlyingSinkAlgorithms() { mozilla::DropJSObjects(this); };
~UnderlyingSinkAlgorithms() override { mozilla::DropJSObjects(this); }
private:
// Virtually const, but are cycle collected

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

@ -699,6 +699,35 @@ AcquireWritableStreamDefaultWriter(WritableStream* aStream, ErrorResult& aRv) {
return writer.forget();
}
// https://streams.spec.whatwg.org/#create-writable-stream
already_AddRefed<WritableStream> CreateWritableStream(
JSContext* aCx, nsIGlobalObject* aGlobal,
UnderlyingSinkAlgorithmsBase* aAlgorithms, double aHighWaterMark,
QueuingStrategySize* aSizeAlgorithm, ErrorResult& aRv) {
// Step 1: Assert: ! IsNonNegativeNumber(highWaterMark) is true.
MOZ_ASSERT(IsNonNegativeNumber(aHighWaterMark));
// Step 2: Let stream be a new WritableStream.
// Step 3: Perform ! InitializeWritableStream(stream).
auto stream = MakeRefPtr<WritableStream>(aGlobal);
// Step 4: Let controller be a new WritableStreamDefaultController.
auto controller =
MakeRefPtr<WritableStreamDefaultController>(aGlobal, *stream);
// Step 5: Perform ? SetUpWritableStreamDefaultController(stream, controller,
// startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm,
// highWaterMark, sizeAlgorithm).
SetUpWritableStreamDefaultController(aCx, stream, controller, aAlgorithms,
aHighWaterMark, aSizeAlgorithm, aRv);
if (aRv.Failed()) {
return nullptr;
}
// Step 6: Return stream.
return stream.forget();
}
already_AddRefed<WritableStreamDefaultWriter> WritableStream::GetWriter(
ErrorResult& aRv) {
return AcquireWritableStreamDefaultWriter(this, aRv);

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

@ -28,6 +28,7 @@ namespace mozilla::dom {
class Promise;
class WritableStreamDefaultController;
class WritableStreamDefaultWriter;
class UnderlyingSinkAlgorithmsBase;
class WritableStream : public nsISupports, public nsWrapperCache {
public:
@ -180,6 +181,11 @@ class WritableStream : public nsISupports, public nsWrapperCache {
nsCOMPtr<nsIGlobalObject> mGlobal;
};
MOZ_CAN_RUN_SCRIPT already_AddRefed<WritableStream> CreateWritableStream(
JSContext* aCx, nsIGlobalObject* aGlobal,
UnderlyingSinkAlgorithmsBase* aAlgorithms, double aHighWaterMark,
QueuingStrategySize* aSizeAlgorithm, ErrorResult& aRv);
inline bool IsWritableStreamLocked(WritableStream* aStream) {
return aStream->Locked();
}

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

@ -91,7 +91,7 @@ already_AddRefed<Promise> WritableStreamDefaultController::AbortSteps(
JSContext* aCx, JS::Handle<JS::Value> aReason, ErrorResult& aRv) {
// Step 1. Let result be the result of performing this.[[abortAlgorithm]],
// passing reason.
RefPtr<UnderlyingSinkAlgorithms> algorithms = mAlgorithms;
RefPtr<UnderlyingSinkAlgorithmsBase> algorithms = mAlgorithms;
Optional<JS::Handle<JS::Value>> optionalReason(aCx, aReason);
RefPtr<Promise> abortPromise =
algorithms->AbortCallback(aCx, optionalReason, aRv);
@ -126,7 +126,7 @@ WritableStreamDefaultControllerAdvanceQueueIfNeeded(
void SetUpWritableStreamDefaultController(
JSContext* aCx, WritableStream* aStream,
WritableStreamDefaultController* aController,
UnderlyingSinkAlgorithms* aAlgorithms, double aHighWaterMark,
UnderlyingSinkAlgorithmsBase* aAlgorithms, double aHighWaterMark,
QueuingStrategySize* aSizeAlgorithm, ErrorResult& aRv) {
// Step 1. Assert: stream implements WritableStream.
// Step 2. Assert: stream.[[controller]] is undefined.
@ -260,7 +260,8 @@ MOZ_CAN_RUN_SCRIPT static void WritableStreamDefaultControllerProcessClose(
// Step 5. Let sinkClosePromise be the result of performing
// controller.[[closeAlgorithm]].
RefPtr<UnderlyingSinkAlgorithms> algorithms = aController->GetAlgorithms();
RefPtr<UnderlyingSinkAlgorithmsBase> algorithms =
aController->GetAlgorithms();
RefPtr<Promise> sinkClosePromise = algorithms->CloseCallback(aCx, aRv);
if (aRv.Failed()) {
return;
@ -303,7 +304,8 @@ MOZ_CAN_RUN_SCRIPT static void WritableStreamDefaultControllerProcessWrite(
// Step 3. Let sinkWritePromise be the result of performing
// controller.[[writeAlgorithm]], passing in chunk.
RefPtr<UnderlyingSinkAlgorithms> algorithms = aController->GetAlgorithms();
RefPtr<UnderlyingSinkAlgorithmsBase> algorithms =
aController->GetAlgorithms();
RefPtr<Promise> sinkWritePromise =
algorithms->WriteCallback(aCx, aChunk, *aController, aRv);
if (aRv.Failed()) {

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

@ -84,8 +84,8 @@ class WritableStreamDefaultController final : public nsISupports,
mStrategySizeAlgorithm = aStrategySizeAlgorithm;
}
UnderlyingSinkAlgorithms* GetAlgorithms() { return mAlgorithms; }
void SetAlgorithms(UnderlyingSinkAlgorithms* aAlgorithms) {
UnderlyingSinkAlgorithmsBase* GetAlgorithms() { return mAlgorithms; }
void SetAlgorithms(UnderlyingSinkAlgorithmsBase* aAlgorithms) {
mAlgorithms = aAlgorithms;
}
@ -128,14 +128,14 @@ class WritableStreamDefaultController final : public nsISupports,
double mStrategyHWM = 0.0;
RefPtr<QueuingStrategySize> mStrategySizeAlgorithm;
RefPtr<UnderlyingSinkAlgorithms> mAlgorithms;
RefPtr<UnderlyingSinkAlgorithmsBase> mAlgorithms;
RefPtr<WritableStream> mStream;
};
MOZ_CAN_RUN_SCRIPT void SetUpWritableStreamDefaultController(
JSContext* aCx, WritableStream* aStream,
WritableStreamDefaultController* aController,
UnderlyingSinkAlgorithms* aSinkCallbacks, double aHighWaterMark,
UnderlyingSinkAlgorithmsBase* aSinkCallbacks, double aHighWaterMark,
QueuingStrategySize* aSizeAlgorithm, ErrorResult& aRv);
MOZ_CAN_RUN_SCRIPT void SetUpWritableStreamDefaultControllerFromUnderlyingSink(

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

@ -2756,6 +2756,16 @@ WebSocketImpl::DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WebSocketImpl::RegisterShutdownTask(nsITargetShutdownTask*) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WebSocketImpl::UnregisterShutdownTask(nsITargetShutdownTask*) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WebSocketImpl::IsOnCurrentThread(bool* aResult) {
*aResult = IsTargetThread();

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

@ -119,6 +119,16 @@ WorkerEventTarget::DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WorkerEventTarget::RegisterShutdownTask(nsITargetShutdownTask*) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WorkerEventTarget::UnregisterShutdownTask(nsITargetShutdownTask*) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP_(bool)
WorkerEventTarget::IsOnCurrentThreadInfallible() {
MutexAutoLock lock(mMutex);

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

@ -5653,6 +5653,17 @@ WorkerPrivate::EventTarget::DelayedDispatch(already_AddRefed<nsIRunnable>,
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WorkerPrivate::EventTarget::RegisterShutdownTask(nsITargetShutdownTask* aTask) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WorkerPrivate::EventTarget::UnregisterShutdownTask(
nsITargetShutdownTask* aTask) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
WorkerPrivate::EventTarget::IsOnCurrentThread(bool* aIsOnCurrentThread) {
// May be called on any thread!

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

@ -17,4 +17,6 @@ firefox-appdir = browser
# Disable plugin loading to make it rr able to record and replay this test.
prefs =
plugin.disable=true
skip-if =
socketprocess_networking # Bug 1759035

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

@ -287,7 +287,7 @@ function promiseAfterPaint() {
// APZ handler on the main thread, the repaints themselves may not have
// occurred by the the returned promise resolves. If you want to wait
// for those repaints, consider using promiseApzFlushedRepaints instead.
function promiseOnlyApzControllerFlushed(aWindow = window) {
function promiseOnlyApzControllerFlushedWithoutSetTimeout(aWindow = window) {
return new Promise(function(resolve, reject) {
var repaintDone = function() {
dump("PromiseApzRepaintsFlushed: APZ flush done\n");
@ -295,7 +295,7 @@ function promiseOnlyApzControllerFlushed(aWindow = window) {
repaintDone,
"apz-repaints-flushed"
);
setTimeout(resolve, 0);
resolve();
};
SpecialPowers.Services.obs.addObserver(repaintDone, "apz-repaints-flushed");
if (SpecialPowers.getDOMWindowUtils(aWindow).flushApzRepaints()) {
@ -311,6 +311,16 @@ function promiseOnlyApzControllerFlushed(aWindow = window) {
});
}
// Another variant of the above promiseOnlyApzControllerFlushedWithoutSetTimeout
// but with a setTimeout(0) callback.
function promiseOnlyApzControllerFlushed(aWindow = window) {
return new Promise(resolve => {
promiseOnlyApzControllerFlushedWithoutSetTimeout(aWindow).then(() => {
setTimeout(resolve, 0);
});
});
}
// Flush repaints, APZ pending repaints, and any repaints resulting from that
// flush. This is particularly useful if the test needs to reach some sort of
// "idle" state in terms of repaints. Usually just waiting for all paints

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

@ -0,0 +1,124 @@
<html>
<head>
<title>Test for bug 1695598</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<script src="/tests/SimpleTest/paint_listener.js"></script>
<script type="application/javascript" src="apz_test_utils.js"></script>
<script type="application/javascript" src="apz_test_native_event_utils.js"></script>
<script type="text/javascript">
let scrollEvents = 100;
let i = 0;
// Scroll points
let numscrolls = 0;
let last_numscrolls = 0;
let start_scrolly = 0;
let missed_events = 0;
let missed_scroll_updates = 0;
let utils = SpecialPowers.getDOMWindowUtils(window);
let timeStamp = document.timeline.currentTime;
async function sendScrollEvent(aRafTimestamp) {
if (i < scrollEvents) {
if (timeStamp == document.timeline.currentTime) {
// If we are in a rAF callback at the same time stamp we've already
// sent a key event, skip it, otherwise we will not get the
// corresponding scroll event for the key event since it will be
// coalesced into a single scroll event.
window.requestAnimationFrame(sendScrollEvent);
return;
}
timeStamp = document.timeline.currentTime;
// Sent a key event in a setTimeout callback so that it will be
// processed in between nsRefreshDriver::Tick calls, thus the async
// scroll triggered by the key event is going to be processed on the
// main-thread before RepaintRequests are processed inside
// nsRefreshDriver::Tick, which results there's an async scroll when
// RepaintRequests are processed.
setTimeout(async () => {
window.synthesizeKey("KEY_ArrowDown");
i++;
// "apz-repaints-flush" is notified in an early runner of
// nsRefreshDriver, which means it will be delivered inside
// a nsRefreshDriver::Tick call before rAF callbacks.
await promiseOnlyApzControllerFlushedWithoutSetTimeout();
// Wait an animationiteration event since animation events are fired
// before rAF callbacks and after scroll events so that it's a good
// place to tell whether the expected scroll event got fired or not.
await promiseOneEvent(document.getElementById("animation"),
"animationiteration", null);
if (numscrolls == last_numscrolls) {
missed_events++;
}
if (window.scrollY <= start_scrolly) {
missed_scroll_updates++;
}
last_numscrolls = numscrolls;
start_scrolly = window.scrollY;
window.requestAnimationFrame(sendScrollEvent);
}, 0);
} else {
// There's a race condition even if we got an "apz-repaints-flush"
// notification but any scroll event isn't fired and scroll position
// isn't updated since the notification was corresponding to a layers
// update triggered by the key event above, which means there was no
// repaint request corresponding to APZ animation sample in the time
// frame. We allow the case here in the half of key events.
ok(missed_events < scrollEvents / 2, `missed event firing ${missed_events} times`);
ok(missed_scroll_updates < scrollEvents / 2, `missed scroll update ${missed_scroll_updates} times`);
endTest();
}
}
async function endTest() {
document.removeEventListener("scroll", gotScroll);
subtestDone();
}
function gotScroll() {
numscrolls++;
}
function startTest() {
document.addEventListener("scroll", gotScroll);
window.requestAnimationFrame(sendScrollEvent);
}
if (!isApzEnabled()) {
SimpleTest.ok(true, "APZ not enabled, skipping test");
subtestDone();
}
waitUntilApzStable()
.then(forceLayerTreeToCompositor)
.then(startTest);
</script>
<style>
#content {
height: 10000vh;
background: repeating-linear-gradient(#EEE, #EEE 100px, #DDD 100px, #DDD 200px);
}
@keyframes anim {
from { opacity: 0; }; /* To avoid churning this scroll test */
to { opacity: 0; };
}
#animation {
position: absolute;
width: 100px;
height: 100px;
visibility: hidden; /* for skipping restyles on the main-thread */
animation-name: anim;
animation-iteration-count: infinite;
animation-duration: 1ms; /* to get an animationiteration event in each tick */
}
</style>
</head>
<body>
<div id="animation"></div>
<div id="content">
</div>
</body>
</html>

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

@ -45,6 +45,7 @@ var subtests = [
prefs: smoothness_prefs },
{"file": "helper_relative_scroll_smoothness.html?input-type=native-key&scroll-method=scrollTop",
prefs: smoothness_prefs },
{"file": "helper_bug1695598.html"},
// Run helper_bug1756529.html twice, first exercising the main-thread keyboard
// scrolling codepaths (e.g. PresShell::ScrollPage()), and once exercising the
// APZ keyboard scrolling codepaths.

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

@ -1133,7 +1133,6 @@ mozilla::ipc::IPCResult CompositorBridgeParent::RecvAdoptChild(
}
oldApzUpdater = sIndirectLayerTrees[child].mParent->mApzUpdater;
}
NotifyChildCreated(child);
if (mWrBridge) {
childWrBridge = sIndirectLayerTrees[child].mWrBridge;
}
@ -1154,6 +1153,13 @@ mozilla::ipc::IPCResult CompositorBridgeParent::RecvAdoptChild(
now, now, now);
}
{
MonitorAutoLock lock(*sIndirectLayerTreesLock);
// Update sIndirectLayerTrees[child].mParent after
// WebRenderBridgeParent::UpdateWebRender().
NotifyChildCreated(child);
}
if (oldApzUpdater) {
// If we are moving a child from an APZ-enabled window to an APZ-disabled
// window (which can happen if e.g. a WebExtension moves a tab into a

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

@ -52,7 +52,8 @@ FT_Face gfxFT2FontBase::LockFTFace()
return mFTFace->GetFace();
}
void gfxFT2FontBase::UnlockFTFace() CAPABILITY_RELEASE(mFTFace) NO_THREAD_SAFETY_ANALYSIS {
void gfxFT2FontBase::UnlockFTFace()
CAPABILITY_RELEASE(mFTFace) NO_THREAD_SAFETY_ANALYSIS {
mFTFace->Unlock();
}

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

@ -549,6 +549,7 @@ struct MappedFontKey {
}
struct FontKeyMapLocked {
namespace: IdNamespace,
next_id: u32,
template_map: FastHashMap<FontTemplate, Arc<MappedFontKey>>,
key_map: FastHashMap<FontKey, Arc<MappedFontKey>>,
@ -561,15 +562,15 @@ struct FontKeyMapLocked {
/// final shared key. The shared key will stay alive so long as there are
/// any strong references to the mapping entry. Care must be taken when
/// clearing namespaces of shared keys as this may trigger shared font keys
/// to expire which require individual processing.
/// to expire which require individual processing. Shared font keys will be
/// created within the provided unique namespace.
#[derive(Clone)]
pub struct FontKeyMap(Arc<RwLock<FontKeyMapLocked>>);
impl FontKeyMap {
const SHARED_NAMESPACE: IdNamespace = IdNamespace(0);
pub fn new() -> Self {
pub fn new(namespace: IdNamespace) -> Self {
FontKeyMap(Arc::new(RwLock::new(FontKeyMapLocked {
namespace,
next_id: 1,
template_map: FastHashMap::default(),
key_map: FastHashMap::default(),
@ -600,7 +601,7 @@ impl FontKeyMap {
locked.key_map.insert(*font_key, mapped);
return None;
}
let shared_key = FontKey::new(Self::SHARED_NAMESPACE, locked.next_id);
let shared_key = FontKey::new(locked.namespace, locked.next_id);
locked.next_id += 1;
let mapped = Arc::new(MappedFontKey {
font_key: shared_key,
@ -717,6 +718,7 @@ impl FontTemplateMap {
}
struct FontInstanceKeyMapLocked {
namespace: IdNamespace,
next_id: u32,
instances: FastHashSet<Arc<BaseFontInstance>>,
key_map: FastHashMap<FontInstanceKey, Weak<BaseFontInstance>>,
@ -729,15 +731,15 @@ struct FontInstanceKeyMapLocked {
/// key to assign to that instance. When the weak count of the mapping is zero,
/// the entry is allowed to expire. Again, care must be taken when clearing
/// a namespace within the key map as it may cause shared key expirations that
/// require individual processing.
/// require individual processing. Shared instance keys will be created within
/// the provided unique namespace.
#[derive(Clone)]
pub struct FontInstanceKeyMap(Arc<RwLock<FontInstanceKeyMapLocked>>);
impl FontInstanceKeyMap {
const SHARED_NAMESPACE: IdNamespace = IdNamespace(0);
pub fn new() -> Self {
pub fn new(namespace: IdNamespace) -> Self {
FontInstanceKeyMap(Arc::new(RwLock::new(FontInstanceKeyMapLocked {
namespace,
next_id: 1,
instances: FastHashSet::default(),
key_map: FastHashMap::default(),
@ -769,7 +771,7 @@ impl FontInstanceKeyMap {
return None;
}
let unmapped_key = instance.instance_key;
instance.instance_key = FontInstanceKey::new(Self::SHARED_NAMESPACE, locked.next_id);
instance.instance_key = FontInstanceKey::new(locked.namespace, locked.next_id);
locked.next_id += 1;
let shared_instance = Arc::new(instance);
locked.instances.insert(shared_instance.clone());
@ -911,12 +913,12 @@ pub struct SharedFontResources {
}
impl SharedFontResources {
pub fn new() -> Self {
pub fn new(namespace: IdNamespace) -> Self {
SharedFontResources {
templates: FontTemplateMap::new(),
instances: FontInstanceMap::new(),
font_keys: FontKeyMap::new(),
instance_keys: FontInstanceKeyMap::new(),
font_keys: FontKeyMap::new(namespace),
instance_keys: FontInstanceKeyMap::new(namespace),
}
}
}

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

@ -733,7 +733,7 @@ impl RenderBackend {
}
}
fn next_namespace_id(&self) -> IdNamespace {
pub fn next_namespace_id() -> IdNamespace {
IdNamespace(NEXT_NAMESPACE_ID.fetch_add(1, Ordering::Relaxed) as u32)
}
@ -908,7 +908,7 @@ impl RenderBackend {
match msg {
ApiMsg::CloneApi(sender) => {
assert!(!self.namespace_alloc_by_client);
sender.send(self.next_namespace_id()).unwrap();
sender.send(Self::next_namespace_id()).unwrap();
}
ApiMsg::CloneApiByClient(namespace_id) => {
assert!(self.namespace_alloc_by_client);

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

@ -1212,7 +1212,9 @@ impl Renderer {
let sampler = options.sampler;
let namespace_alloc_by_client = options.namespace_alloc_by_client;
let fonts = SharedFontResources::new();
// Ensure shared font keys exist within their own unique namespace so
// that they don't accidentally collide across Renderer instances.
let fonts = SharedFontResources::new(RenderBackend::next_namespace_id());
let blob_image_handler = options.blob_image_handler.take();
let scene_builder_hooks = options.scene_builder_hooks;

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

@ -540,7 +540,7 @@ impl ResourceCache {
let workers = Arc::new(ThreadPoolBuilder::new().build().unwrap());
let glyph_rasterizer = GlyphRasterizer::new(workers, true).unwrap();
let cached_glyphs = GlyphCache::new();
let fonts = SharedFontResources::new();
let fonts = SharedFontResources::new(IdNamespace(0));
let picture_textures = PictureTextures::new(
crate::picture::TILE_SIZE_DEFAULT,
TextureFilter::Nearest,

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

@ -16,6 +16,8 @@
#include "mozilla/Atomics.h"
#include "mozilla/Mutex.h"
#include "mozilla/ProfilerRunnable.h"
#include "nsIEventTarget.h"
#include "nsITargetShutdownTask.h"
#include "nsThreadUtils.h"
#if defined(OS_MACOSX)
@ -85,11 +87,29 @@ static LPTOP_LEVEL_EXCEPTION_FILTER GetTopSEHFilter() {
//------------------------------------------------------------------------------
class MessageLoop::EventTarget : public nsISerialEventTarget,
public nsITargetShutdownTask,
public MessageLoop::DestructionObserver {
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIEVENTTARGET_FULL
void TargetShutdown() override {
nsTArray<nsCOMPtr<nsITargetShutdownTask>> shutdownTasks;
{
mozilla::MutexAutoLock lock(mMutex);
if (mShutdownTasksRun) {
return;
}
mShutdownTasksRun = true;
shutdownTasks = std::move(mShutdownTasks);
mShutdownTasks.Clear();
}
for (auto& task : shutdownTasks) {
task->TargetShutdown();
}
}
explicit EventTarget(MessageLoop* aLoop)
: mMutex("MessageLoop::EventTarget"), mLoop(aLoop) {
aLoop->AddDestructionObserver(this);
@ -100,18 +120,25 @@ class MessageLoop::EventTarget : public nsISerialEventTarget,
if (mLoop) {
mLoop->RemoveDestructionObserver(this);
}
MOZ_ASSERT(mShutdownTasks.IsEmpty());
}
void WillDestroyCurrentMessageLoop() override {
mozilla::MutexAutoLock lock(mMutex);
// The MessageLoop is being destroyed and we are called from its destructor
// There's no real need to remove ourselves from the destruction observer
// list. But it makes things look tidier.
mLoop->RemoveDestructionObserver(this);
mLoop = nullptr;
{
mozilla::MutexAutoLock lock(mMutex);
// The MessageLoop is being destroyed and we are called from its
// destructor There's no real need to remove ourselves from the
// destruction observer list. But it makes things look tidier.
mLoop->RemoveDestructionObserver(this);
mLoop = nullptr;
}
TargetShutdown();
}
mozilla::Mutex mMutex;
bool mShutdownTasksRun GUARDED_BY(mMutex) = false;
nsTArray<nsCOMPtr<nsITargetShutdownTask>> mShutdownTasks GUARDED_BY(mMutex);
MessageLoop* mLoop GUARDED_BY(mMutex);
};
@ -165,6 +192,26 @@ MessageLoop::EventTarget::DelayedDispatch(already_AddRefed<nsIRunnable> aEvent,
return NS_OK;
}
NS_IMETHODIMP
MessageLoop::EventTarget::RegisterShutdownTask(nsITargetShutdownTask* aTask) {
mozilla::MutexAutoLock lock(mMutex);
if (!mLoop || mShutdownTasksRun) {
return NS_ERROR_UNEXPECTED;
}
MOZ_ASSERT(!mShutdownTasks.Contains(aTask));
mShutdownTasks.AppendElement(aTask);
return NS_OK;
}
NS_IMETHODIMP
MessageLoop::EventTarget::UnregisterShutdownTask(nsITargetShutdownTask* aTask) {
mozilla::MutexAutoLock lock(mMutex);
if (!mLoop || mShutdownTasksRun) {
return NS_ERROR_UNEXPECTED;
}
return mShutdownTasks.RemoveElement(aTask) ? NS_OK : NS_ERROR_UNEXPECTED;
}
//------------------------------------------------------------------------------
// static
@ -175,7 +222,7 @@ void MessageLoop::set_current(MessageLoop* loop) { get_tls_ptr().Set(loop); }
static mozilla::Atomic<int32_t> message_loop_id_seq(0);
MessageLoop::MessageLoop(Type type, nsIEventTarget* aEventTarget)
MessageLoop::MessageLoop(Type type, nsISerialEventTarget* aEventTarget)
: type_(type),
id_(++message_loop_id_seq),
nestable_tasks_allowed_(true),
@ -257,7 +304,9 @@ MessageLoop::MessageLoop(Type type, nsIEventTarget* aEventTarget)
// We want GetCurrentSerialEventTarget() to return the real nsThread if it
// will be used to dispatch tasks. However, under all other cases; we'll want
// it to return this MessageLoop's EventTarget.
if (!pump_->GetXPCOMThread()) {
if (nsISerialEventTarget* thread = pump_->GetXPCOMThread()) {
MOZ_ALWAYS_SUCCEEDS(thread->RegisterShutdownTask(mEventTarget));
} else {
mozilla::SerialEventTargetGuard::Set(mEventTarget);
}
}
@ -379,7 +428,7 @@ void MessageLoop::PostIdleTask(already_AddRefed<nsIRunnable> task) {
// Possibly called on a background thread!
void MessageLoop::PostTask_Helper(already_AddRefed<nsIRunnable> task,
int delay_ms) {
if (nsIEventTarget* target = pump_->GetXPCOMThread()) {
if (nsISerialEventTarget* target = pump_->GetXPCOMThread()) {
nsresult rv;
if (delay_ms) {
rv = target->DelayedDispatch(std::move(task), delay_ms);

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

@ -30,7 +30,6 @@
#include "nsIRunnable.h"
#include "nsThreadUtils.h"
class nsIEventTarget;
class nsISerialEventTarget;
namespace mozilla {
@ -200,7 +199,7 @@ class MessageLoop : public base::MessagePump::Delegate {
// Normally, it is not necessary to instantiate a MessageLoop. Instead, it
// is typical to make use of the current thread's MessageLoop instance.
explicit MessageLoop(Type type = TYPE_DEFAULT,
nsIEventTarget* aEventTarget = nullptr);
nsISerialEventTarget* aEventTarget = nullptr);
~MessageLoop();
// Returns the type passed to the constructor.

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

@ -9,7 +9,7 @@
#include "nsISupportsImpl.h"
class nsIEventTarget;
class nsISerialEventTarget;
namespace base {
@ -129,7 +129,7 @@ class MessagePump {
virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) = 0;
// If returned, just use the nsThread.
virtual nsIEventTarget* GetXPCOMThread() { return nullptr; }
virtual nsISerialEventTarget* GetXPCOMThread() { return nullptr; }
protected:
virtual ~MessagePump(){};

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

@ -501,6 +501,7 @@ MessageChannel::~MessageChannel() {
MOZ_RELEASE_ASSERT(mPendingResponses.empty());
MOZ_RELEASE_ASSERT(!mChannelErrorTask);
MOZ_RELEASE_ASSERT(mPending.isEmpty());
MOZ_RELEASE_ASSERT(!mShutdownTask);
}
#ifdef DEBUG
@ -590,6 +591,12 @@ void MessageChannel::Clear() {
// through this channel after it's Clear()'ed can cause this process to
// crash.
if (mShutdownTask) {
mShutdownTask->Clear();
mWorkerThread->UnregisterShutdownTask(mShutdownTask);
}
mShutdownTask = nullptr;
if (NS_IsMainThread() && gParentProcessBlocker == this) {
gParentProcessBlocker = nullptr;
}
@ -621,15 +628,34 @@ void MessageChannel::Clear() {
bool MessageChannel::Open(ScopedPort aPort, Side aSide,
nsISerialEventTarget* aEventTarget) {
nsCOMPtr<nsISerialEventTarget> eventTarget =
aEventTarget ? aEventTarget : GetCurrentSerialEventTarget();
MOZ_RELEASE_ASSERT(eventTarget,
"Must open MessageChannel on a nsISerialEventTarget");
MOZ_RELEASE_ASSERT(eventTarget->IsOnCurrentThread(),
"Must open MessageChannel from worker thread");
auto shutdownTask = MakeRefPtr<WorkerTargetShutdownTask>(eventTarget, this);
nsresult rv = eventTarget->RegisterShutdownTask(shutdownTask);
MOZ_ASSERT(rv != NS_ERROR_NOT_IMPLEMENTED,
"target for MessageChannel must support shutdown tasks");
if (rv == NS_ERROR_UNEXPECTED) {
// If shutdown tasks have already started running, dispatch our shutdown
// task manually.
NS_WARNING("Opening MessageChannel on EventTarget in shutdown");
rv = eventTarget->Dispatch(shutdownTask->AsRunnable());
}
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv),
"error registering ShutdownTask for MessageChannel");
{
MonitorAutoLock lock(*mMonitor);
MOZ_RELEASE_ASSERT(!mLink, "Open() called > once");
MOZ_RELEASE_ASSERT(ChannelClosed == mChannelState, "Not currently closed");
MOZ_ASSERT(mSide == UnknownSide);
mWorkerThread = aEventTarget ? aEventTarget : GetCurrentSerialEventTarget();
MOZ_ASSERT(mWorkerThread, "We should always be on a nsISerialEventTarget");
mWorkerThread = eventTarget;
mShutdownTask = shutdownTask;
mLink = MakeUnique<PortLink>(this, std::move(aPort));
mSide = aSide;
}
@ -2300,5 +2326,25 @@ void MessageChannel::SetIsCrossProcess(bool aIsCrossProcess) {
}
}
NS_IMPL_ISUPPORTS(MessageChannel::WorkerTargetShutdownTask,
nsITargetShutdownTask)
MessageChannel::WorkerTargetShutdownTask::WorkerTargetShutdownTask(
nsISerialEventTarget* aTarget, MessageChannel* aChannel)
: mTarget(aTarget), mChannel(aChannel) {}
void MessageChannel::WorkerTargetShutdownTask::TargetShutdown() {
MOZ_RELEASE_ASSERT(mTarget->IsOnCurrentThread());
IPC_LOG("Closing channel due to event target shutdown");
if (MessageChannel* channel = std::exchange(mChannel, nullptr)) {
channel->Close();
}
}
void MessageChannel::WorkerTargetShutdownTask::Clear() {
MOZ_RELEASE_ASSERT(mTarget->IsOnCurrentThread());
mChannel = nullptr;
}
} // namespace ipc
} // namespace mozilla

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

@ -25,6 +25,7 @@
#include "MessageLink.h" // for HasResultCodes
#include "mozilla/ipc/ScopedPort.h"
#include "nsITargetShutdownTask.h"
class MessageLoop;
@ -545,6 +546,24 @@ class MessageChannel : HasResultCodes {
void RunMessage(ActorLifecycleProxy* aProxy, MessageTask& aTask)
REQUIRES(*mMonitor);
class WorkerTargetShutdownTask final : public nsITargetShutdownTask {
public:
NS_DECL_THREADSAFE_ISUPPORTS
WorkerTargetShutdownTask(nsISerialEventTarget* aTarget,
MessageChannel* aChannel);
void TargetShutdown() override;
void Clear();
private:
~WorkerTargetShutdownTask() = default;
const nsCOMPtr<nsISerialEventTarget> mTarget;
// Cleared by MessageChannel before it is destroyed.
MessageChannel* MOZ_NON_OWNING_REF mChannel;
};
typedef LinkedList<RefPtr<MessageTask>> MessageQueue;
typedef std::map<size_t, UniquePtr<UntypedCallbackHolder>> CallbackMap;
typedef IPC::Message::msgid_t msgid_t;
@ -576,6 +595,9 @@ class MessageChannel : HasResultCodes {
// from multiple threads before Open().
nsCOMPtr<nsISerialEventTarget> mWorkerThread;
// Shutdown task to close the channel before mWorkerThread goes away.
RefPtr<WorkerTargetShutdownTask> mShutdownTask GUARDED_BY(*mMonitor);
// Timeout periods are broken up in two to prevent system suspension from
// triggering an abort. This method (called by WaitForEvent with a 'did
// timeout' flag) decides if we should wait again for half of mTimeoutMs

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

@ -58,7 +58,7 @@ class DoWorkRunnable final : public CancelableRunnable,
} /* namespace ipc */
} /* namespace mozilla */
MessagePump::MessagePump(nsIEventTarget* aEventTarget)
MessagePump::MessagePump(nsISerialEventTarget* aEventTarget)
: mEventTarget(aEventTarget) {
mDoWorkEvent = new DoWorkRunnable(this);
}
@ -163,13 +163,13 @@ void MessagePump::ScheduleDelayedWork(const base::TimeTicks& aDelayedTime) {
nsITimer::TYPE_ONE_SHOT);
}
nsIEventTarget* MessagePump::GetXPCOMThread() {
nsISerialEventTarget* MessagePump::GetXPCOMThread() {
if (mEventTarget) {
return mEventTarget;
}
// Main thread
return GetMainThreadEventTarget();
return GetMainThreadSerialEventTarget();
}
void MessagePump::DoDelayedWork(base::MessagePump::Delegate* aDelegate) {

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

@ -30,7 +30,7 @@ class MessagePump : public base::MessagePumpDefault {
friend class DoWorkRunnable;
public:
explicit MessagePump(nsIEventTarget* aEventTarget);
explicit MessagePump(nsISerialEventTarget* aEventTarget);
// From base::MessagePump.
virtual void Run(base::MessagePump::Delegate* aDelegate) override;
@ -45,7 +45,7 @@ class MessagePump : public base::MessagePumpDefault {
virtual void ScheduleDelayedWork(
const base::TimeTicks& aDelayedWorkTime) override;
virtual nsIEventTarget* GetXPCOMThread() override;
virtual nsISerialEventTarget* GetXPCOMThread() override;
protected:
virtual ~MessagePump();
@ -55,7 +55,7 @@ class MessagePump : public base::MessagePumpDefault {
void DoDelayedWork(base::MessagePump::Delegate* aDelegate);
protected:
nsIEventTarget* mEventTarget;
nsISerialEventTarget* mEventTarget;
// mDelayedWorkTimer and mEventTarget are set in Run() by this class or its
// subclasses.
@ -80,7 +80,7 @@ class MessagePumpForChildProcess final : public MessagePump {
class MessagePumpForNonMainThreads final : public MessagePump {
public:
explicit MessagePumpForNonMainThreads(nsIEventTarget* aEventTarget)
explicit MessagePumpForNonMainThreads(nsISerialEventTarget* aEventTarget)
: MessagePump(aEventTarget) {}
virtual void Run(base::MessagePump::Delegate* aDelegate) override;
@ -110,7 +110,7 @@ class MessagePumpForNonMainUIThreads final : public base::MessagePumpForUI,
// The main run loop for this thread.
virtual void DoRunLoop() override;
virtual nsIEventTarget* GetXPCOMThread() override {
virtual nsISerialEventTarget* GetXPCOMThread() override {
return nullptr; // not sure what to do with this one
}
@ -151,20 +151,20 @@ class MessagePumpForNonMainUIThreads final : public base::MessagePumpForUI,
*/
class MessagePumpForAndroidUI : public base::MessagePump {
public:
explicit MessagePumpForAndroidUI(nsIEventTarget* aEventTarget)
explicit MessagePumpForAndroidUI(nsISerialEventTarget* aEventTarget)
: mEventTarget(aEventTarget) {}
virtual void Run(Delegate* delegate);
virtual void Quit();
virtual void ScheduleWork();
virtual void ScheduleDelayedWork(const base::TimeTicks& delayed_work_time);
virtual nsIEventTarget* GetXPCOMThread() { return mEventTarget; }
virtual nsISerialEventTarget* GetXPCOMThread() { return mEventTarget; }
private:
~MessagePumpForAndroidUI() {}
MessagePumpForAndroidUI() {}
nsIEventTarget* mEventTarget;
nsISerialEventTarget* mEventTarget;
};
#endif // defined(MOZ_WIDGET_ANDROID)

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

@ -2448,7 +2448,7 @@ void ScrollFrameHelper::ScrollToCSSPixels(const CSSIntPoint& aScrollPosition,
// Bug 1740164: We will apply it for cases there's no animation in APZ.
if (mCurrentAPZScrollAnimationType ==
APZScrollAnimationType::TriggeredByUserInput &&
!IsScrollAnimating(IncludeApzAnimation::No)) {
!IsScrollAnimating(IncludeApzAnimation::PendingAndRequestedOnly)) {
CSSIntPoint delta = aScrollPosition - currentCSSPixels;
ScrollByCSSPixels(delta, aMode);
return;
@ -7330,10 +7330,11 @@ bool ScrollFrameHelper::IsScrollAnimating(
if (aIncludeApz == IncludeApzAnimation::Yes && IsApzAnimationInProgress()) {
return true;
}
if (IsLastScrollUpdateAnimating()) {
if (aIncludeApz != IncludeApzAnimation::No && IsLastScrollUpdateAnimating()) {
return true;
}
return mApzAnimationRequested || mAsyncScroll || mAsyncSmoothMSDScroll;
return (aIncludeApz != IncludeApzAnimation::No && mApzAnimationRequested) ||
mAsyncScroll || mAsyncSmoothMSDScroll;
}
void ScrollFrameHelper::ResetScrollInfoIfNeeded(
@ -7360,7 +7361,8 @@ UniquePtr<PresState> ScrollFrameHelper::SaveState() const {
// Don't store a scroll state if we never have been scrolled or restored
// a previous scroll state, and we're not in the middle of a smooth scroll.
bool isScrollAnimating = IsScrollAnimating(IncludeApzAnimation::No);
bool isScrollAnimating =
IsScrollAnimating(IncludeApzAnimation::PendingAndRequestedOnly);
if (!mHasBeenScrolled && !mDidHistoryRestore && !isScrollAnimating) {
return nullptr;
}

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

@ -413,12 +413,24 @@ class nsIScrollableFrame : public nsIScrollbarMediator {
/**
* Returns whether there's an async scroll going on.
*
* The argument allows a subtle distinction that's needed for APZ. When
* `IncludeApzAnimation::No` is given, ongoing APZ animations that have
* already been synced to the main thread are not included, which is needed so
* that APZ can keep syncing the scroll offset properly.
* The argument allows a subtle distinction that's needed for APZ. APZ scroll
* animations that are requested from the main thread go through three states:
* 1) pending, when the main thread has recorded that it wants apz to do a
* scroll animation, 2) requested, when the main thread has sent the request
* to the compositor (but it hasn't necessarily arrived yet), and 3) in
* progress, after apz has responded to the main thread that is got the
* request. When `IncludeApzAnimation::No` is given, APZ animations in any of
* the three states are not included, which is needed so that APZ can keep
* syncing the scroll offset properly. When
* `IncludeApzAnimation::PendingAndRequestedOnly` is given, only APZ
* animations in the pending or requested state are included, this is needed
* when saving the state of a scroll frame (we want to save the mDestination
* of the animation, but the repaint request that informs the main thread that
* the animation is in progress will also overwrite mDestination with the
* current scroll position). When `IncludeApzAnimation::Yes` is given, APZ
* animations in any state are included, this is what all other callers use.
*/
enum class IncludeApzAnimation : bool { No, Yes };
enum class IncludeApzAnimation : uint8_t { No, PendingAndRequestedOnly, Yes };
virtual bool IsScrollAnimating(
IncludeApzAnimation = IncludeApzAnimation::Yes) = 0;

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

@ -298,6 +298,18 @@ nsSocketTransportService::DelayedDispatch(already_AddRefed<nsIRunnable>,
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsSocketTransportService::RegisterShutdownTask(nsITargetShutdownTask* task) {
nsCOMPtr<nsIThread> thread = GetThreadSafely();
return thread ? thread->RegisterShutdownTask(task) : NS_ERROR_UNEXPECTED;
}
NS_IMETHODIMP
nsSocketTransportService::UnregisterShutdownTask(nsITargetShutdownTask* task) {
nsCOMPtr<nsIThread> thread = GetThreadSafely();
return thread ? thread->UnregisterShutdownTask(task) : NS_ERROR_UNEXPECTED;
}
NS_IMETHODIMP
nsSocketTransportService::IsOnCurrentThread(bool* result) {
*result = OnSocketThread();

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

@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsStreamTransportService.h"
#include "ErrorList.h"
#include "nsXPCOMCIDInternal.h"
#include "nsNetSegmentUtils.h"
#include "nsTransportUtils.h"
@ -16,7 +17,6 @@
#include "nsITransport.h"
#include "nsIObserverService.h"
#include "nsThreadPool.h"
#include "mozilla/DelayedRunnable.h"
#include "mozilla/Services.h"
namespace mozilla {
@ -242,9 +242,7 @@ nsInputStreamTransport::OnInputStreamReady(nsIAsyncInputStream* aStream) {
// nsStreamTransportService
//-----------------------------------------------------------------------------
nsStreamTransportService::nsStreamTransportService()
: mScheduledDelayedRunnables(
"nsStreamTransportService.mScheduledDelayedRunnables") {}
nsStreamTransportService::nsStreamTransportService() = default;
nsStreamTransportService::~nsStreamTransportService() {
NS_ASSERTION(!mPool, "thread pool wasn't shutdown");
@ -269,25 +267,8 @@ nsresult nsStreamTransportService::Init() {
return NS_OK;
}
void nsStreamTransportService::OnDelayedRunnableCreated(
DelayedRunnable* aRunnable) {}
void nsStreamTransportService::OnDelayedRunnableScheduled(
DelayedRunnable* aRunnable) {
MOZ_ASSERT(IsOnCurrentThread());
auto delayedRunnables = mScheduledDelayedRunnables.Lock();
delayedRunnables->AppendElement(aRunnable);
}
void nsStreamTransportService::OnDelayedRunnableRan(
DelayedRunnable* aRunnable) {
MOZ_ASSERT(IsOnCurrentThread());
auto delayedRunnables = mScheduledDelayedRunnables.Lock();
Unused << delayedRunnables->RemoveElement(aRunnable);
}
NS_IMPL_ISUPPORTS(nsStreamTransportService, nsIStreamTransportService,
nsIEventTarget, nsIDelayedRunnableObserver, nsIObserver)
nsIEventTarget, nsIObserver)
NS_IMETHODIMP
nsStreamTransportService::DispatchFromScript(nsIRunnable* task,
@ -315,15 +296,17 @@ nsStreamTransportService::Dispatch(already_AddRefed<nsIRunnable> task,
NS_IMETHODIMP
nsStreamTransportService::DelayedDispatch(already_AddRefed<nsIRunnable> aEvent,
uint32_t aDelayMs) {
nsCOMPtr<nsIRunnable> event = aEvent;
NS_ENSURE_TRUE(!!aDelayMs, NS_ERROR_UNEXPECTED);
return NS_ERROR_NOT_IMPLEMENTED;
}
RefPtr<DelayedRunnable> r =
new DelayedRunnable(do_AddRef(this), event.forget(), aDelayMs);
nsresult rv = r->Init();
NS_ENSURE_SUCCESS(rv, rv);
NS_IMETHODIMP
nsStreamTransportService::RegisterShutdownTask(nsITargetShutdownTask*) {
return NS_ERROR_NOT_IMPLEMENTED;
}
return Dispatch(r.forget(), NS_DISPATCH_NORMAL);
NS_IMETHODIMP
nsStreamTransportService::UnregisterShutdownTask(nsITargetShutdownTask*) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP_(bool)
@ -380,31 +363,6 @@ nsStreamTransportService::Observe(nsISupports* subject, const char* topic,
pool->Shutdown();
}
}
// Because the DelayedRunnables are run by a thread pool, no guarantee is
// given to which thread they run or get released on. Releasing them on the
// thread pool or on the background target thus doesn't really matter. We are
// forced to do it on the background target after the thread pool has finished
// processing all events, since doing it on the thread pool would allow the
// shutdown task to race with scheduling new DelayedRunnables, possibly
// missing the cleanup of some of them.
nsTArray<RefPtr<DelayedRunnable>> delayedRunnables;
{
auto sdrs = mScheduledDelayedRunnables.Lock();
std::swap(*sdrs, delayedRunnables);
MOZ_ASSERT(sdrs->IsEmpty());
}
if (!delayedRunnables.IsEmpty()) {
NS_DispatchBackgroundTask(
NS_NewRunnableFunction(
"nsStreamTransportService::mScheduledDelayedRunnables Cancel",
[delayedRunnables = std::move(delayedRunnables)] {
for (const auto& r : delayedRunnables) {
r->CancelTimer();
}
}),
NS_DISPATCH_SYNC);
}
return NS_OK;
}

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

@ -5,7 +5,6 @@
#ifndef nsStreamTransportService_h__
#define nsStreamTransportService_h__
#include "nsIDelayedRunnableObserver.h"
#include "nsIStreamTransportService.h"
#include "nsIEventTarget.h"
#include "nsIObserver.h"
@ -14,19 +13,15 @@
#include "nsThreadUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/DataMutex.h"
#include "mozilla/DelayedRunnable.h"
#include "mozilla/Mutex.h"
class nsIThreadPool;
namespace mozilla {
class DelayedRunnable;
namespace net {
class nsStreamTransportService final : public nsIStreamTransportService,
public nsIEventTarget,
public nsIDelayedRunnableObserver,
public nsIObserver {
public:
NS_DECL_THREADSAFE_ISUPPORTS
@ -38,19 +33,13 @@ class nsStreamTransportService final : public nsIStreamTransportService,
nsStreamTransportService();
void OnDelayedRunnableCreated(DelayedRunnable* aRunnable) override;
void OnDelayedRunnableScheduled(DelayedRunnable* aRunnable) override;
void OnDelayedRunnableRan(DelayedRunnable* aRunnable) override;
private:
~nsStreamTransportService();
nsCOMPtr<nsIThreadPool> mPool GUARDED_BY(mShutdownLock);
DataMutex<nsTArray<RefPtr<DelayedRunnable>>> mScheduledDelayedRunnables;
mozilla::Mutex mShutdownLock{"nsStreamTransportService.mShutdownLock"};
bool mIsShutdown GUARDED_BY(mShutdownLock) {false};
bool mIsShutdown GUARDED_BY(mShutdownLock){false};
};
} // namespace net

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

@ -77,6 +77,10 @@ class nsNetworkLinkService : public nsINetworkLinkService,
// time to discover the gateway's MAC address.
nsCOMPtr<nsITimer> mNetworkIdTimer;
// Scheduled timers used to delay querying of the DNS suffix list when
// triggered by a network change. Guarded by mMutex.
nsTArray<nsCOMPtr<nsITimer>> mDNSConfigChangedTimers;
// IP address used to check the route for public traffic.
struct in_addr mRouteCheckIPv4;
};

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

@ -692,10 +692,19 @@ void nsNetworkLinkService::DNSConfigChanged(uint32_t aDelayMs) {
return;
}
if (aDelayMs) {
MOZ_ALWAYS_SUCCEEDS(target->DelayedDispatch(
NS_NewRunnableFunction("nsNetworkLinkService::GetDnsSuffixListInternal",
[self = RefPtr{this}]() { self->GetDnsSuffixListInternal(); }),
aDelayMs));
MutexAutoLock lock(mMutex);
nsCOMPtr<nsITimer> timer;
MOZ_ALWAYS_SUCCEEDS(NS_NewTimerWithCallback(
getter_AddRefs(timer),
[self = RefPtr{this}](nsITimer* aTimer) {
self->GetDnsSuffixListInternal();
MutexAutoLock lock(self->mMutex);
self->mDNSConfigChangedTimers.RemoveElement(aTimer);
},
TimeDuration::FromMilliseconds(aDelayMs), nsITimer::TYPE_ONE_SHOT,
"nsNetworkLinkService::GetDnsSuffixListInternal", target));
mDNSConfigChangedTimers.AppendElement(timer);
} else {
MOZ_ALWAYS_SUCCEEDS(target->Dispatch(
NS_NewRunnableFunction("nsNetworkLinkService::GetDnsSuffixListInternal",
@ -849,6 +858,16 @@ nsresult nsNetworkLinkService::Shutdown() {
mNetworkIdTimer = nullptr;
}
nsTArray<nsCOMPtr<nsITimer>> dnsConfigChangedTimers;
{
MutexAutoLock lock(mMutex);
dnsConfigChangedTimers = std::move(mDNSConfigChangedTimers);
mDNSConfigChangedTimers.Clear();
}
for (const auto& timer : dnsConfigChangedTimers) {
timer->Cancel();
}
return NS_OK;
}

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

@ -12,7 +12,8 @@
if not domstreams: FAIL
[TransformStreamDefaultController interface: self.transformStreamDefaultController must inherit property "terminate()" with the proper type]
expected: FAIL
expected:
if not domstreams: FAIL
[WritableStream interface: new WritableStream() must inherit property "locked" with the proper type]
expected:
@ -35,7 +36,8 @@
if not domstreams: FAIL
[TransformStreamDefaultController interface: self.transformStreamDefaultController must inherit property "desiredSize" with the proper type]
expected: FAIL
expected:
if not domstreams: FAIL
[ReadableStreamBYOBReader interface object length]
expected:
@ -118,7 +120,8 @@
if not domstreams: FAIL
[TransformStreamDefaultController interface: calling error(optional any) on self.transformStreamDefaultController with too few arguments must throw TypeError]
expected: FAIL
expected:
if not domstreams: FAIL
[WritableStream interface: existence and properties of interface prototype object's @@unscopables property]
expected:
@ -177,7 +180,8 @@
if not domstreams: FAIL
[TransformStreamDefaultController interface: calling enqueue(optional any) on self.transformStreamDefaultController with too few arguments must throw TypeError]
expected: FAIL
expected:
if not domstreams: FAIL
[ReadableStreamBYOBReader interface: existence and properties of interface prototype object]
expected:
@ -236,7 +240,8 @@
if not domstreams: FAIL
[Stringification of self.transformStreamDefaultController]
expected: FAIL
expected:
if not domstreams: FAIL
[ReadableStreamDefaultReader interface: operation read()]
expected:
@ -271,10 +276,12 @@
if not domstreams: FAIL
[TransformStreamDefaultController interface: self.transformStreamDefaultController must inherit property "enqueue(optional any)" with the proper type]
expected: FAIL
expected:
if not domstreams: FAIL
[TransformStreamDefaultController interface: self.transformStreamDefaultController must inherit property "error(optional any)" with the proper type]
expected: FAIL
expected:
if not domstreams: FAIL
[ReadableByteStreamController interface: existence and properties of interface prototype object's "constructor" property]
expected:
@ -289,7 +296,8 @@
if not domstreams: FAIL
[TransformStreamDefaultController must be primary interface of self.transformStreamDefaultController]
expected: FAIL
expected:
if not domstreams: FAIL
[ReadableByteStreamController must be primary interface of self.readableByteStreamController]
expected:
@ -689,7 +697,8 @@
if not domstreams: FAIL
[TransformStreamDefaultController interface: self.transformStreamDefaultController must inherit property "terminate()" with the proper type]
expected: FAIL
expected:
if not domstreams: FAIL
[WritableStream interface: new WritableStream() must inherit property "locked" with the proper type]
expected:
@ -712,7 +721,8 @@
if not domstreams: FAIL
[TransformStreamDefaultController interface: self.transformStreamDefaultController must inherit property "desiredSize" with the proper type]
expected: FAIL
expected:
if not domstreams: FAIL
[ReadableStreamBYOBReader interface object length]
expected:
@ -795,7 +805,8 @@
if not domstreams: FAIL
[TransformStreamDefaultController interface: calling error(optional any) on self.transformStreamDefaultController with too few arguments must throw TypeError]
expected: FAIL
expected:
if not domstreams: FAIL
[WritableStream interface: existence and properties of interface prototype object's @@unscopables property]
expected:
@ -854,7 +865,8 @@
if not domstreams: FAIL
[TransformStreamDefaultController interface: calling enqueue(optional any) on self.transformStreamDefaultController with too few arguments must throw TypeError]
expected: FAIL
expected:
if not domstreams: FAIL
[ReadableStreamBYOBReader interface: existence and properties of interface prototype object]
expected:
@ -913,7 +925,8 @@
if not domstreams: FAIL
[Stringification of self.transformStreamDefaultController]
expected: FAIL
expected:
if not domstreams: FAIL
[ReadableStreamDefaultReader interface: operation read()]
expected:
@ -948,10 +961,12 @@
if not domstreams: FAIL
[TransformStreamDefaultController interface: self.transformStreamDefaultController must inherit property "enqueue(optional any)" with the proper type]
expected: FAIL
expected:
if not domstreams: FAIL
[TransformStreamDefaultController interface: self.transformStreamDefaultController must inherit property "error(optional any)" with the proper type]
expected: FAIL
expected:
if not domstreams: FAIL
[ReadableByteStreamController interface: existence and properties of interface prototype object's "constructor" property]
expected:
@ -966,7 +981,8 @@
if not domstreams: FAIL
[TransformStreamDefaultController must be primary interface of self.transformStreamDefaultController]
expected: FAIL
expected:
if not domstreams: FAIL
[ReadableByteStreamController must be primary interface of self.readableByteStreamController]
expected:
@ -1366,7 +1382,8 @@
if not domstreams: FAIL
[TransformStreamDefaultController interface: self.transformStreamDefaultController must inherit property "terminate()" with the proper type]
expected: FAIL
expected:
if not domstreams: FAIL
[WritableStream interface: new WritableStream() must inherit property "locked" with the proper type]
expected:
@ -1389,7 +1406,8 @@
if not domstreams: FAIL
[TransformStreamDefaultController interface: self.transformStreamDefaultController must inherit property "desiredSize" with the proper type]
expected: FAIL
expected:
if not domstreams: FAIL
[ReadableStreamBYOBReader interface object length]
expected:
@ -1472,7 +1490,8 @@
if not domstreams: FAIL
[TransformStreamDefaultController interface: calling error(optional any) on self.transformStreamDefaultController with too few arguments must throw TypeError]
expected: FAIL
expected:
if not domstreams: FAIL
[WritableStream interface: existence and properties of interface prototype object's @@unscopables property]
expected:
@ -1531,7 +1550,8 @@
if not domstreams: FAIL
[TransformStreamDefaultController interface: calling enqueue(optional any) on self.transformStreamDefaultController with too few arguments must throw TypeError]
expected: FAIL
expected:
if not domstreams: FAIL
[ReadableStreamBYOBReader interface: existence and properties of interface prototype object]
expected:
@ -1590,7 +1610,8 @@
if not domstreams: FAIL
[Stringification of self.transformStreamDefaultController]
expected: FAIL
expected:
if not domstreams: FAIL
[ReadableStreamDefaultReader interface: operation read()]
expected:
@ -1625,10 +1646,12 @@
if not domstreams: FAIL
[TransformStreamDefaultController interface: self.transformStreamDefaultController must inherit property "enqueue(optional any)" with the proper type]
expected: FAIL
expected:
if not domstreams: FAIL
[TransformStreamDefaultController interface: self.transformStreamDefaultController must inherit property "error(optional any)" with the proper type]
expected: FAIL
expected:
if not domstreams: FAIL
[ReadableByteStreamController interface: existence and properties of interface prototype object's "constructor" property]
expected:
@ -1643,7 +1666,8 @@
if not domstreams: FAIL
[TransformStreamDefaultController must be primary interface of self.transformStreamDefaultController]
expected: FAIL
expected:
if not domstreams: FAIL
[ReadableByteStreamController must be primary interface of self.readableByteStreamController]
expected:
@ -2043,7 +2067,8 @@
if not domstreams: FAIL
[TransformStreamDefaultController interface: self.transformStreamDefaultController must inherit property "terminate()" with the proper type]
expected: FAIL
expected:
if not domstreams: FAIL
[WritableStream interface: new WritableStream() must inherit property "locked" with the proper type]
expected:
@ -2066,7 +2091,8 @@
if not domstreams: FAIL
[TransformStreamDefaultController interface: self.transformStreamDefaultController must inherit property "desiredSize" with the proper type]
expected: FAIL
expected:
if not domstreams: FAIL
[ReadableStreamBYOBReader interface object length]
expected:
@ -2149,7 +2175,8 @@
if not domstreams: FAIL
[TransformStreamDefaultController interface: calling error(optional any) on self.transformStreamDefaultController with too few arguments must throw TypeError]
expected: FAIL
expected:
if not domstreams: FAIL
[WritableStream interface: existence and properties of interface prototype object's @@unscopables property]
expected:
@ -2208,7 +2235,8 @@
if not domstreams: FAIL
[TransformStreamDefaultController interface: calling enqueue(optional any) on self.transformStreamDefaultController with too few arguments must throw TypeError]
expected: FAIL
expected:
if not domstreams: FAIL
[ReadableStreamBYOBReader interface: existence and properties of interface prototype object]
expected:
@ -2267,7 +2295,8 @@
if not domstreams: FAIL
[Stringification of self.transformStreamDefaultController]
expected: FAIL
expected:
if not domstreams: FAIL
[ReadableStreamDefaultReader interface: operation read()]
expected:
@ -2302,10 +2331,12 @@
if not domstreams: FAIL
[TransformStreamDefaultController interface: self.transformStreamDefaultController must inherit property "enqueue(optional any)" with the proper type]
expected: FAIL
expected:
if not domstreams: FAIL
[TransformStreamDefaultController interface: self.transformStreamDefaultController must inherit property "error(optional any)" with the proper type]
expected: FAIL
expected:
if not domstreams: FAIL
[ReadableByteStreamController interface: existence and properties of interface prototype object's "constructor" property]
expected:
@ -2320,7 +2351,8 @@
if not domstreams: FAIL
[TransformStreamDefaultController must be primary interface of self.transformStreamDefaultController]
expected: FAIL
expected:
if not domstreams: FAIL
[ReadableByteStreamController must be primary interface of self.readableByteStreamController]
expected:

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

@ -11,9 +11,6 @@
[when controller.error is followed by a rejection, the error reason should come from controller.error]
expected: FAIL
[TransformStream constructor should throw when start does]
expected: FAIL
[when strategy.size throws inside start(), the constructor should throw the same error]
expected: FAIL
@ -56,6 +53,9 @@
[the readable should be errored with the reason passed to the writable abort() method]
expected: FAIL
[errored TransformStream should not enqueue new chunks]
expected: FAIL
[errors.any.serviceworker.html]
[TransformStream errors thrown in transform put the writable and readable in an errored state]
@ -70,9 +70,6 @@
[when controller.error is followed by a rejection, the error reason should come from controller.error]
expected: FAIL
[TransformStream constructor should throw when start does]
expected: FAIL
[when strategy.size throws inside start(), the constructor should throw the same error]
expected: FAIL
@ -115,6 +112,9 @@
[the readable should be errored with the reason passed to the writable abort() method]
expected: FAIL
[errored TransformStream should not enqueue new chunks]
expected: FAIL
[errors.any.worker.html]
[TransformStream errors thrown in transform put the writable and readable in an errored state]
@ -129,9 +129,6 @@
[when controller.error is followed by a rejection, the error reason should come from controller.error]
expected: FAIL
[TransformStream constructor should throw when start does]
expected: FAIL
[when strategy.size throws inside start(), the constructor should throw the same error]
expected: FAIL
@ -174,6 +171,9 @@
[the readable should be errored with the reason passed to the writable abort() method]
expected: FAIL
[errored TransformStream should not enqueue new chunks]
expected: FAIL
[errors.any.html]
[TransformStream errors thrown in transform put the writable and readable in an errored state]
@ -188,9 +188,6 @@
[when controller.error is followed by a rejection, the error reason should come from controller.error]
expected: FAIL
[TransformStream constructor should throw when start does]
expected: FAIL
[when strategy.size throws inside start(), the constructor should throw the same error]
expected: FAIL
@ -232,3 +229,6 @@
[the readable should be errored with the reason passed to the writable abort() method]
expected: FAIL
[errored TransformStream should not enqueue new chunks]
expected: FAIL

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

@ -50,10 +50,13 @@
[terminate() should do nothing after readable.cancel()]
expected: FAIL
[start() should not be called twice]
[Subclassing TransformStream should work]
expected: FAIL
[Subclassing TransformStream should work]
[enqueue() should throw after controller.terminate()]
expected: FAIL
[controller.terminate() should do nothing the second time it is called]
expected: FAIL
@ -109,10 +112,13 @@
[terminate() should do nothing after readable.cancel()]
expected: FAIL
[start() should not be called twice]
[Subclassing TransformStream should work]
expected: FAIL
[Subclassing TransformStream should work]
[enqueue() should throw after controller.terminate()]
expected: FAIL
[controller.terminate() should do nothing the second time it is called]
expected: FAIL
@ -168,10 +174,13 @@
[terminate() should do nothing after readable.cancel()]
expected: FAIL
[start() should not be called twice]
[Subclassing TransformStream should work]
expected: FAIL
[Subclassing TransformStream should work]
[enqueue() should throw after controller.terminate()]
expected: FAIL
[controller.terminate() should do nothing the second time it is called]
expected: FAIL
@ -227,8 +236,11 @@
[terminate() should do nothing after readable.cancel()]
expected: FAIL
[start() should not be called twice]
expected: FAIL
[Subclassing TransformStream should work]
expected: FAIL
[enqueue() should throw after controller.terminate()]
expected: FAIL
[controller.terminate() should do nothing the second time it is called]
expected: FAIL

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

@ -1,10 +1,4 @@
[properties.any.worker.html]
[transformer method start should be called with the right number of arguments]
expected: FAIL
[transformer method start should be called even when it's located on the prototype chain]
expected: FAIL
[transformer method transform should be called with the right number of arguments]
expected: FAIL
@ -19,12 +13,6 @@
[properties.any.html]
[transformer method start should be called with the right number of arguments]
expected: FAIL
[transformer method start should be called even when it's located on the prototype chain]
expected: FAIL
[transformer method transform should be called with the right number of arguments]
expected: FAIL
@ -39,12 +27,6 @@
[properties.any.sharedworker.html]
[transformer method start should be called with the right number of arguments]
expected: FAIL
[transformer method start should be called even when it's located on the prototype chain]
expected: FAIL
[transformer method transform should be called with the right number of arguments]
expected: FAIL
@ -59,12 +41,6 @@
[properties.any.serviceworker.html]
[transformer method start should be called with the right number of arguments]
expected: FAIL
[transformer method start should be called even when it's located on the prototype chain]
expected: FAIL
[transformer method transform should be called with the right number of arguments]
expected: FAIL

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

@ -14,9 +14,6 @@
[default readable strategy should be equivalent to { highWaterMark: 0 }]
expected: FAIL
[a RangeError should be thrown for an invalid highWaterMark]
expected: FAIL
[writableStrategy highWaterMark should be converted to a number]
expected: FAIL
@ -26,6 +23,9 @@
[a bad readableStrategy size function should error the stream on enqueue even when transformer.transform() catches the exception]
expected: FAIL
[readableStrategy highWaterMark should be converted to a number]
expected: FAIL
[strategies.any.serviceworker.html]
[writableStrategy highWaterMark should work]
@ -43,9 +43,6 @@
[default readable strategy should be equivalent to { highWaterMark: 0 }]
expected: FAIL
[a RangeError should be thrown for an invalid highWaterMark]
expected: FAIL
[writableStrategy highWaterMark should be converted to a number]
expected: FAIL
@ -55,6 +52,9 @@
[a bad readableStrategy size function should error the stream on enqueue even when transformer.transform() catches the exception]
expected: FAIL
[readableStrategy highWaterMark should be converted to a number]
expected: FAIL
[strategies.any.sharedworker.html]
[writableStrategy highWaterMark should work]
@ -72,9 +72,6 @@
[default readable strategy should be equivalent to { highWaterMark: 0 }]
expected: FAIL
[a RangeError should be thrown for an invalid highWaterMark]
expected: FAIL
[writableStrategy highWaterMark should be converted to a number]
expected: FAIL
@ -84,6 +81,9 @@
[a bad readableStrategy size function should error the stream on enqueue even when transformer.transform() catches the exception]
expected: FAIL
[readableStrategy highWaterMark should be converted to a number]
expected: FAIL
[strategies.any.worker.html]
[writableStrategy highWaterMark should work]
@ -101,9 +101,6 @@
[default readable strategy should be equivalent to { highWaterMark: 0 }]
expected: FAIL
[a RangeError should be thrown for an invalid highWaterMark]
expected: FAIL
[writableStrategy highWaterMark should be converted to a number]
expected: FAIL
@ -112,3 +109,6 @@
[a bad readableStrategy size function should error the stream on enqueue even when transformer.transform() catches the exception]
expected: FAIL
[readableStrategy highWaterMark should be converted to a number]
expected: FAIL

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

@ -14,6 +14,9 @@
[controller.terminate() inside flush() should not prevent writer.close() from succeeding]
expected: FAIL
[controller.enqueue() should throw after controller.terminate()]
expected: FAIL
[terminate.any.worker.html]
[controller.terminate() should error pipeTo()]
@ -31,6 +34,9 @@
[controller.terminate() inside flush() should not prevent writer.close() from succeeding]
expected: FAIL
[controller.enqueue() should throw after controller.terminate()]
expected: FAIL
[terminate.any.serviceworker.html]
[controller.terminate() should error pipeTo()]
@ -48,6 +54,9 @@
[controller.terminate() inside flush() should not prevent writer.close() from succeeding]
expected: FAIL
[controller.enqueue() should throw after controller.terminate()]
expected: FAIL
[terminate.any.html]
[controller.terminate() should error pipeTo()]
@ -64,3 +73,6 @@
[controller.terminate() inside flush() should not prevent writer.close() from succeeding]
expected: FAIL
[controller.enqueue() should throw after controller.terminate()]
expected: FAIL

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

@ -0,0 +1,4 @@
[seamlessly-updating-the-playback-rate-of-an-animation.html]
[Updating the negative playback rate with the unresolved current time and a positive infinite associated effect end should not throw an exception]
expected:
if release_or_beta: FAIL

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

@ -386,18 +386,6 @@ bool VideoCaptureModuleV4L2::CaptureProcess() {
rSet.revents = 0;
retVal = poll(&rSet, 1, 1000);
if (retVal < 0 && errno != EINTR) // continue if interrupted
{
// poll failed
return false;
} else if (retVal == 0) {
// poll timed out
return true;
} else if (!(rSet.revents & POLLIN)) {
// not event on camera handle
return true;
}
{
MutexLock lock(&capture_lock_);
@ -405,6 +393,18 @@ bool VideoCaptureModuleV4L2::CaptureProcess() {
return false;
}
if (retVal < 0 && errno != EINTR) // continue if interrupted
{
// poll failed
return false;
} else if (retVal == 0) {
// poll timed out
return true;
} else if (!(rSet.revents & POLLIN)) {
// not event on camera handle
return true;
}
if (_captureStarted) {
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(struct v4l2_buffer));

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

@ -5,12 +5,16 @@ prefs =
[test_cookie_behavior.js]
[test_getPartitionKeyFromURL.js]
skip-if =
socketprocess_networking # Bug 1759035
[test_purge_trackers.js]
skip-if = win10_2004 # Bug 1718292
[test_purge_trackers_telemetry.js]
[test_tracking_db_service.js]
skip-if = toolkit == "android" # Bug 1697936
[test_rejectForeignAllowList.js]
skip-if =
socketprocess_networking # Bug 1759035
[test_staticPartition_clientAuthRemember.js]
[test_staticPartition_font.js]
support-files =
@ -19,9 +23,20 @@ skip-if =
apple_silicon # bug 1729551
os == "mac" && bits == 64 && !debug # Bug 1652119
os == "win" && bits == 64 && !debug # Bug 1652119
socketprocess_networking # Bug 1759035
[test_staticPartition_image.js]
skip-if =
socketprocess_networking # Bug 1759035
[test_staticPartition_authhttp.js]
skip-if =
socketprocess_networking # Bug 1759035
[test_staticPartition_prefetch.js]
skip-if =
socketprocess_networking # Bug 1759035
[test_staticPartition_preload.js]
skip-if =
socketprocess_networking # Bug 1759035
[test_ExceptionListService.js]
[test_view_source.js]
skip-if =
socketprocess_networking # Bug 1759035 (not as common on win, perma on linux/osx)

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

@ -2540,9 +2540,14 @@ class EventManager {
return false;
};
let { extension } = this.context;
const resetIdle = () => extension?.emit("background-script-reset-idle");
let fire = {
// Bug 1754866 fire.sync doesn't match documentation.
sync: (...args) => {
if (shouldFire()) {
resetIdle();
let result = this.context.applySafe(callback, args);
this.context.logActivity("api_event", this.name, { args, result });
return result;
@ -2551,6 +2556,7 @@ class EventManager {
async: (...args) => {
return Promise.resolve().then(() => {
if (shouldFire()) {
resetIdle();
let result = this.context.applySafe(callback, args);
this.context.logActivity("api_event", this.name, { args, result });
return result;
@ -2561,6 +2567,7 @@ class EventManager {
if (!shouldFire()) {
throw new Error("Called raw() on unloaded/inactive context");
}
resetIdle();
let result = Reflect.apply(callback, null, args);
this.context.logActivity("api_event", this.name, { args, result });
return result;
@ -2568,6 +2575,7 @@ class EventManager {
asyncWithoutClone: (...args) => {
return Promise.resolve().then(() => {
if (shouldFire()) {
resetIdle();
let result = this.context.applySafeWithoutClone(callback, args);
this.context.logActivity("api_event", this.name, { args, result });
return result;
@ -2576,7 +2584,6 @@ class EventManager {
},
};
let { extension } = this.context;
let { module, event } = this;
let unregister = null;

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

@ -30,6 +30,16 @@ XPCOMUtils.defineLazyGetter(this, "serviceWorkerManager", () => {
);
});
XPCOMUtils.defineLazyPreferenceGetter(
this,
"backgroundIdleTimeout",
"extensions.background.idle.timeout",
30000,
null,
// Minimum 100ms, max 5min
delay => Math.min(Math.max(delay, 100), 5 * 60 * 1000)
);
// Responsible for the background_page section of the manifest.
class BackgroundPage extends HiddenExtensionPage {
constructor(extension, options) {
@ -303,6 +313,26 @@ this.backgroundPage = class extends ExtensionAPI {
return this.bgInstance.build();
}
observe(subject, topic, data) {
if (topic == "timer-callback") {
let { extension } = this;
this.clearIdleTimer();
extension?.terminateBackground();
}
}
clearIdleTimer() {
this.backgroundTimer?.cancel();
this.backgroundTimer = null;
}
resetIdleTimer() {
this.clearIdleTimer();
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
timer.init(this, backgroundIdleTimeout, Ci.nsITimer.TYPE_ONE_SHOT);
this.backgroundTimer = timer;
}
async primeBackground(isInStartup = true) {
let { extension } = this;
@ -344,7 +374,34 @@ this.backgroundPage = class extends ExtensionAPI {
return bgStartupPromise;
};
let resetBackgroundIdle = () => {
this.clearIdleTimer();
if (!this.extension || extension.persistentBackground) {
// Extension was already shut down or is persistent and
// does not idle timout.
return;
}
// TODO remove at an appropriate point in the future prior
// to general availability. There may be some racy conditions
// with idle timeout between an event starting and the event firing
// but we still want testing with an idle timeout.
if (
!Services.prefs.getBoolPref("extensions.background.idle.enabled", true)
) {
return;
}
this.resetIdleTimer();
};
// Listen for events from the EventManager
extension.on("background-script-reset-idle", resetBackgroundIdle);
// After the background is started, initiate the first timer
extension.once("background-script-started", resetBackgroundIdle);
extension.terminateBackground = async () => {
this.clearIdleTimer();
extension.off("background-script-reset-idle", resetBackgroundIdle);
await bgStartupPromise;
this.onShutdown(false);
EventManager.clearPrimedListeners(this.extension, false);
@ -398,6 +455,9 @@ this.backgroundPage = class extends ExtensionAPI {
}
onShutdown(isAppShutdown) {
// Ensure there is no backgroundTimer running
this.clearIdleTimer();
if (this.bgInstance) {
this.bgInstance.shutdown(isAppShutdown);
this.bgInstance = null;

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

@ -2,11 +2,18 @@
const global = this;
var { BaseContext, EventManager } = ExtensionCommon;
var { BaseContext, EventManager, EventEmitter } = ExtensionCommon;
class FakeExtension extends EventEmitter {
constructor(id) {
super();
this.id = id;
}
}
class StubContext extends BaseContext {
constructor() {
let fakeExtension = { id: "test@web.extension" };
let fakeExtension = new FakeExtension("test@web.extension");
super("testEnv", fakeExtension);
this.sandbox = Cu.Sandbox(global);
}
@ -112,7 +119,7 @@ add_task(async function test_post_unload_listeners() {
class Context extends BaseContext {
constructor(principal) {
let fakeExtension = { id: "test@web.extension" };
let fakeExtension = new FakeExtension("test@web.extension");
super("testEnv", fakeExtension);
Object.defineProperty(this, "principal", {
value: principal,

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

@ -0,0 +1,69 @@
"use strict";
AddonTestUtils.init(this);
AddonTestUtils.overrideCertDB();
AddonTestUtils.createAppInfo(
"xpcshell@tests.mozilla.org",
"XPCShell",
"42",
"42"
);
Services.prefs.setBoolPref("extensions.eventPages.enabled", true);
// Set minimum idle timeout for testing
Services.prefs.setIntPref("extensions.background.idle.timeout", 0);
function promiseExtensionEvent(extension, event) {
return new Promise(resolve => extension.extension.once(event, resolve));
}
add_setup(async () => {
await AddonTestUtils.promiseStartupManager();
});
add_task(async function test_eventpage_idle() {
let extension = ExtensionTestUtils.loadExtension({
useAddonManager: "permanent",
manifest: {
permissions: ["browserSettings"],
background: { persistent: false },
},
background() {
browser.browserSettings.homepageOverride.onChange.addListener(() => {
browser.test.sendMessage("homepageOverride");
});
},
});
await extension.startup();
assertPersistentListeners(extension, "browserSettings", "homepageOverride", {
primed: false,
});
info(`test idle timeout after startup`);
await promiseExtensionEvent(extension, "shutdown-background-script");
assertPersistentListeners(extension, "browserSettings", "homepageOverride", {
primed: true,
});
Services.prefs.setStringPref(
"browser.startup.homepage",
"http://homepage.example.com"
);
await extension.awaitMessage("homepageOverride");
ok(true, "homepageOverride.onChange fired");
// again after the event is fired
info(`test idle timeout after wakeup`);
await promiseExtensionEvent(extension, "shutdown-background-script");
assertPersistentListeners(extension, "browserSettings", "homepageOverride", {
primed: true,
});
Services.prefs.setStringPref(
"browser.startup.homepage",
"http://test.example.com"
);
await extension.awaitMessage("homepageOverride");
ok(true, "homepageOverride.onChange fired");
await extension.unload();
});

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

@ -115,6 +115,7 @@ skip-if = os == "android" || tsan # tsan: bug 1612707
[test_ext_downloads_urlencoded.js]
skip-if = os == "android"
[test_ext_error_location.js]
[test_ext_eventpage_idle.js]
[test_ext_eventpage_warning.js]
[test_ext_eventpage_settings.js]
[test_ext_experiments.js]

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

@ -1,20 +1,46 @@
[test_ext_i18n.js]
skip-if = os == "android" || (os == "win" && debug) || (os == "linux")
[test_ext_i18n_css.js]
skip-if =
(socketprocess_networking || fission) && (os == "linux" && debug) # Bug 1759035
[test_ext_contentscript.js]
skip-if =
socketprocess_networking # Bug 1759035
[test_ext_contentscript_about_blank_start.js]
[test_ext_contentscript_canvas_tainting.js]
skip-if =
os == "linux" && socketprocess_networking && !fission && debug # Bug 1759035
[test_ext_contentscript_scriptCreated.js]
skip-if =
os == "linux" && socketprocess_networking && !fission && debug # Bug 1759035
[test_ext_contentscript_triggeringPrincipal.js]
skip-if = os == "android" || (os == "win" && debug) || tsan # Windows: Bug 1438796, tsan: bug 1612707, Android: Bug 1680132
skip-if =
os == "android" # Bug 1680132
(os == "win" && debug) # Bug 1438796
tsan # Bug 1612707
os == "linux" && socketprocess_networking && !fission && debug # Bug 1759035
[test_ext_contentscript_xrays.js]
skip-if =
os == "linux" && socketprocess_networking && !fission && debug # Bug 1759035
[test_ext_contentScripts_register.js]
skip-if =
os == "linux" && socketprocess_networking && !fission && debug # Bug 1759035
[test_ext_contexts_gc.js]
skip-if =
os == "linux" && socketprocess_networking && !fission && debug # Bug 1759035
[test_ext_adoption_with_xrays.js]
skip-if =
os == "linux" && socketprocess_networking && !fission && debug # Bug 1759035
[test_ext_adoption_with_private_field_xrays.js]
skip-if = !nightly_build
os == "linux" && socketprocess_networking && !fission && debug # Bug 1759035
[test_ext_shadowdom.js]
skip-if = ccov && os == 'linux' # bug 1607581
os == "linux" && socketprocess_networking && !fission && debug # Bug 1759035
[test_ext_web_accessible_resources.js]
skip-if = apple_silicon # Disabled due to bleedover with other tests when run in regular suites; passes in "failures" jobs
skip-if =
apple_silicon # Disabled due to bleedover with other tests when run in regular suites; passes in "failures" jobs
os == "linux" && socketprocess_networking && !fission && debug # Bug 1759035
[test_ext_web_accessible_resources_matches.js]
skip-if =
os == "linux" && socketprocess_networking && !fission && debug # Bug 1759035

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

@ -19,7 +19,11 @@ prefs =
services.settings.default_bucket=nonexistent-bucket-foo
[include:xpcshell-common-e10s.ini]
skip-if =
socketprocess_networking # Bug 1759035
[include:xpcshell-content.ini]
skip-if =
socketprocess_networking && fission # Bug 1759035
# Tests that need to run with e10s only must NOT be placed here,
# but in xpcshell-common-e10s.ini.

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

@ -2,7 +2,11 @@
head = head.js head_remote.js head_e10s.js head_telemetry.js head_sync.js head_storage.js
tail =
firefox-appdir = browser
skip-if = os == "android"
skip-if =
os == "android"
os == "win" && socketprocess_networking && fission # Bug 1759035
os == "mac" && socketprocess_networking && fission # Bug 1759035
# I would put linux here, but debug has too many chunks and only runs this manifest, so I need 1 test to pass
dupe-manifest =
support-files =
data/**
@ -19,12 +23,21 @@ prefs =
services.settings.default_bucket=nonexistent-bucket-foo
[include:xpcshell-common.ini]
skip-if =
os == "linux" && socketprocess_networking # Bug 1759035
[include:xpcshell-common-e10s.ini]
skip-if =
os == "linux" && socketprocess_networking # Bug 1759035
[include:xpcshell-content.ini]
skip-if =
os == "linux" && socketprocess_networking # Bug 1759035
[test_ext_contentscript_perf_observers.js] # Inexplicably, PerformanceObserver used in the test doesn't fire in non-e10s mode.
skip-if = tsan
os == "linux" && socketprocess_networking # Bug 1759035
[test_ext_contentscript_xorigin_frame.js]
skip-if =
os == "linux" && socketprocess_networking # Bug 1759035
[test_WebExtensionContentScript.js]
[test_ext_ipcBlob.js]
skip-if = os == 'android' && processor == 'x86_64'
os == "linux" && socketprocess_networking # Bug 1759035

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

@ -71,6 +71,8 @@ head = head.js head_schemas.js
[test_ext_schemas_versioned.js]
head = head.js head_schemas.js
[test_ext_secfetch.js]
skip-if =
socketprocess_networking # Bug 1759035
[test_ext_shared_array_buffer.js]
[test_ext_test_mock.js]
[test_ext_test_wrapper.js]

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

@ -70,7 +70,13 @@ support-files =
method-extensions/post/manifest.json
method-extensions/engines.json
[test_defaultEngine_fallback.js]
skip-if =
debug && socketprocess_networking # Bug 1759035
(os == "mac" || os == "win") && socketprocess_networking # Bug 1759035
[test_defaultEngine.js]
skip-if =
debug && socketprocess_networking # Bug 1759035
(os == "mac" || os == "win") && socketprocess_networking # Bug 1759035
[test_defaultPrivateEngine.js]
[test_engine_alias.js]
[test_engine_multiple_alias.js]
@ -86,32 +92,65 @@ tag = remotesettings searchmain
[test_getSubmission_encoding.js]
[test_getSubmission_params.js]
[test_identifiers.js]
skip-if =
debug && socketprocess_networking # Bug 1759035
(os == "mac" || os == "win") && socketprocess_networking # Bug 1759035
[test_ignorelist_update.js]
[test_ignorelist.js]
[test_initialization.js]
[test_initialization_with_region.js]
skip-if =
debug && socketprocess_networking # Bug 1759035
(os == "mac" || os == "win") && socketprocess_networking # Bug 1759035
[test_list_json_locale.js]
[test_list_json_no_private_default.js]
[test_list_json_searchdefault.js]
[test_list_json_searchorder.js]
[test_maybereloadengine_order.js]
skip-if =
debug && socketprocess_networking # Bug 1759035
(os == "mac" || os == "win") && socketprocess_networking # Bug 1759035
[test_migrateWebExtensionEngine.js]
skip-if =
debug && socketprocess_networking # Bug 1759035
(os == "mac" || os == "win") && socketprocess_networking # Bug 1759035
[test_missing_engine.js]
[test_multipleIcons.js]
skip-if =
debug && socketprocess_networking # Bug 1759035
(os == "mac" || os == "win") && socketprocess_networking # Bug 1759035
[test_nodb_pluschanges.js]
skip-if =
debug && socketprocess_networking # Bug 1759035
(os == "mac" || os == "win") && socketprocess_networking # Bug 1759035
[test_notifications.js]
skip-if =
debug && socketprocess_networking # Bug 1759035
(os == "mac" || os == "win") && socketprocess_networking # Bug 1759035
[test_opensearch_icon.js]
support-files =
data/bigIcon.ico
data/remoteIcon.ico
data/svgIcon.svg
skip-if =
debug && socketprocess_networking # Bug 1759035
(os == "mac" || os == "win") && socketprocess_networking # Bug 1759035
[test_opensearch_icons_invalid.js]
support-files =
opensearch/chromeicon.xml
opensearch/resourceicon.xml
skip-if =
debug && socketprocess_networking # Bug 1759035
(os == "mac" || os == "win") && socketprocess_networking # Bug 1759035
[test_opensearch_install_errors.js]
support-files = opensearch/invalid.xml
skip-if =
debug && socketprocess_networking # Bug 1759035
(os == "mac" || os == "win") && socketprocess_networking # Bug 1759035
[test_opensearch_update.js]
skip-if =
debug && socketprocess_networking # Bug 1759035
(os == "mac" || os == "win") && socketprocess_networking # Bug 1759035
[test_opensearch.js]
support-files =
opensearch/mozilla-ns.xml
@ -119,9 +158,15 @@ support-files =
opensearch/simple.xml
opensearch/suggestion.xml
opensearch/suggestion-alternate.xml
skip-if =
debug && socketprocess_networking # Bug 1759035
(os == "mac" || os == "win") && socketprocess_networking # Bug 1759035
[test_originalDefaultEngine.js]
[test_override_allowlist.js]
[test_parseSubmissionURL.js]
skip-if =
debug && socketprocess_networking # Bug 1759035
(os == "mac" || os == "win") && socketprocess_networking # Bug 1759035
[test_pref.js]
[test_purpose.js]
[test_region_params.js]
@ -131,11 +176,26 @@ support-files =
[test_remove_engine_notification_box.js]
[test_resultDomain.js]
[test_save_sorted_engines.js]
skip-if =
debug && socketprocess_networking # Bug 1759035
(os == "mac" || os == "win") && socketprocess_networking # Bug 1759035
[test_SearchStaticData.js]
[test_searchSuggest_cookies.js]
skip-if =
debug && socketprocess_networking # Bug 1759035
(os == "mac" || os == "win") && socketprocess_networking # Bug 1759035
[test_searchSuggest_private.js]
skip-if =
debug && socketprocess_networking # Bug 1759035
(os == "mac" || os == "win") && socketprocess_networking # Bug 1759035
[test_searchSuggest.js]
skip-if =
debug && socketprocess_networking # Bug 1759035
(os == "mac" || os == "win") && socketprocess_networking # Bug 1759035
[test_selectedEngine.js]
skip-if =
debug && socketprocess_networking # Bug 1759035
(os == "mac" || os == "win") && socketprocess_networking # Bug 1759035
[test_sendSubmissionURL.js]
[test_settings_broken.js]
[test_settings_duplicate.js]
@ -143,6 +203,9 @@ support-files =
[test_settings_ignorelist.js]
support-files = data/search_ignorelist.json
[test_settings_none.js]
skip-if =
debug && socketprocess_networking # Bug 1759035
(os == "mac" || os == "win") && socketprocess_networking # Bug 1759035
[test_settings_obsolete.js]
[test_settings_persist.js]
[test_settings.js]
@ -152,9 +215,15 @@ support-files = data/search_ignorelist.json
[test_validate_manifests.js]
[test_webextensions_builtin_upgrade.js]
[test_webextensions_install.js]
skip-if =
debug && socketprocess_networking # Bug 1759035
(os == "mac" || os == "win") && socketprocess_networking # Bug 1759035
[test_webextensions_migrate_to.js]
support-files = data/search-migration.json
[test_webextensions_normandy_upgrade.js]
skip-if =
debug && socketprocess_networking # Bug 1759035
(os == "mac" || os == "win") && socketprocess_networking # Bug 1759035
[test_webextensions_startup_remove.js]
[test_webextensions_upgrade.js]
[test_webextensions_valid.js]

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

@ -19,8 +19,12 @@ support-files =
[ausReadStrings.js]
[canCheckForAndCanApplyUpdates.js]
[urlConstruction.js]
skip-if =
socketprocess_networking # Bug 1759035
[updateManagerXML.js]
[remoteUpdateXML.js]
skip-if =
socketprocess_networking # Bug 1759035
[cleanupDownloadingForOlderAppVersion.js]
[cleanupDownloadingForDifferentChannel.js]
[cleanupDownloadingForSameVersionAndBuildID.js]
@ -29,10 +33,18 @@ support-files =
[cleanupSuccessLogMove.js]
[cleanupSuccessLogsFIFO.js]
[downloadInterruptedOffline.js]
skip-if =
socketprocess_networking # Bug 1759035
[downloadInterruptedNoRecovery.js]
skip-if =
socketprocess_networking # Bug 1759035
[downloadInterruptedRecovery.js]
skip-if =
socketprocess_networking # Bug 1759035
[downloadResumeForSameAppVersion.js]
[languagePackUpdates.js]
skip-if =
socketprocess_networking # Bug 1759035
[updateSyncManager.js]
[updateAutoPrefMigrate.js]
skip-if = os != 'win'
@ -41,10 +53,18 @@ reason = Update pref migration is currently Windows only
skip-if = os != 'win'
reason = Update directory migration is currently Windows only
[multiUpdate.js]
skip-if =
socketprocess_networking # Bug 1759035
[perInstallationPrefs.js]
[onlyDownloadUpdatesThisSession.js]
skip-if =
socketprocess_networking # Bug 1759035
[disableBackgroundUpdatesBackgroundTask.js]
skip-if =
socketprocess_networking # Bug 1759035
[disableBackgroundUpdatesNonBackgroundTask.js]
skip-if =
socketprocess_networking # Bug 1759035
[ensureExperimentToRolloutTransitionPerformed.js]
run-if = os == 'win' && appname == 'firefox'
reason = Feature is Firefox-specific and Windows-specific.

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

@ -35,7 +35,7 @@ skip-if =
# and no allocation markers are gathered. Skip this test in that configuration.
[test_feature_nativeallocations.js]
skip-if =
toolkit == 'android' # bug 1757528
os == "android" && verify # bug 1757528
asan
tsan
socketprocess_networking

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

@ -433,6 +433,10 @@ const GfxDeviceFamily* GfxDriverInfo::GetDeviceFamily(DeviceFamily id) {
APPEND_DEVICE(0xa011);
APPEND_DEVICE(0xa012);
break;
case DeviceFamily::Bug1760464:
APPEND_DEVICE(0x0a16); // Intel HD Graphics Family on Haswell Ultrabooks
APPEND_DEVICE(0x041e); // Intel HD Graphics 4400
break;
case DeviceFamily::AmdR600:
// AMD R600 generation GPUs
// R600
@ -473,8 +477,8 @@ const GfxDeviceFamily* GfxDriverInfo::GetDeviceFamily(DeviceFamily id) {
APPEND_RANGE(0x9710, 0x9715);
break;
case DeviceFamily::NvidiaWebRenderBlocked:
APPEND_RANGE(0x0190, 0x019e); // early tesla
APPEND_RANGE(0x0500, 0x05df); // C67-C68
APPEND_RANGE(0x0190, 0x019e); // early tesla
APPEND_RANGE(0x0500, 0x05df); // C67-C68
break;
case DeviceFamily::NvidiaRolloutWebRender:
APPEND_RANGE(0x0400, 0x04ff);
@ -950,6 +954,7 @@ const nsAString& GfxDriverInfo::GetDeviceVendor(DeviceFamily id) {
case DeviceFamily::Bug1116812:
case DeviceFamily::Bug1155608:
case DeviceFamily::Bug1207665:
case DeviceFamily::Bug1760464:
vendor = DeviceVendor::Intel;
break;
case DeviceFamily::NvidiaAll:

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

@ -197,6 +197,7 @@ enum class DeviceFamily : uint8_t {
Bug1155608,
Bug1207665,
Bug1447141,
Bug1760464,
AmdR600,
NvidiaRolloutWebRender,
IntelRolloutWebRender,

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

@ -1555,6 +1555,15 @@ const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION,
DRIVER_BUILD_ID_LESS_THAN_OR_EQUAL, 4578,
"FEATURE_FAILURE_BUG_1432610");
/**
* Disable VP8 HW decoding on Windows 8.1 on Intel Haswel for some devices.
* See bug 1760464 comment 6.
*/
APPEND_TO_DRIVER_BLOCKLIST2(
OperatingSystem::Windows8_1, DeviceFamily::Bug1760464,
nsIGfxInfo::FEATURE_VP8_HW_DECODE, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions,
"FEATURE_FAILURE_BUG_1760464");
/* Disable D2D on Win7 on Intel HD Graphics on driver <= 8.15.10.2302
* See bug 806786
@ -1848,8 +1857,7 @@ const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
APPEND_TO_DRIVER_BLOCKLIST2(
OperatingSystem::Windows, DeviceFamily::NvidiaWebRenderBlocked,
nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions,
"EARLY_NVIDIA");
DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions, "EARLY_NVIDIA");
////////////////////////////////////
// FEATURE_WEBRENDER - ALLOWLIST

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

@ -59,13 +59,12 @@ nsConsoleService::MessageElement::~MessageElement() = default;
nsConsoleService::nsConsoleService()
: mCurrentSize(0),
// XXX grab this from a pref!
// hm, but worry about circularity, bc we want to be able to report
// prefs errs...
mMaximumSize(250),
mDeliveringMessage(false),
mLock("nsConsoleService.mLock") {
// XXX grab this from a pref!
// hm, but worry about circularity, bc we want to be able to report
// prefs errs...
mMaximumSize = 250;
#ifdef XP_WIN
// This environment variable controls whether the console service
// should be prevented from putting output to the attached debugger.

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

@ -87,26 +87,27 @@ class nsConsoleService final : public nsIConsoleService, public nsIObserver {
nsresult MaybeForwardScriptError(nsIConsoleMessage* aMessage, bool* sent);
void ClearMessagesForWindowID(const uint64_t innerID);
void ClearMessages();
void ClearMessages() REQUIRES(mLock);
mozilla::LinkedList<MessageElement> mMessages;
mozilla::LinkedList<MessageElement> mMessages GUARDED_BY(mLock);
// The current size of mMessages.
uint32_t mCurrentSize;
uint32_t mCurrentSize GUARDED_BY(mLock);
// The maximum size of mMessages.
uint32_t mMaximumSize;
const uint32_t mMaximumSize;
// Are we currently delivering a console message on the main thread? If
// so, we suppress incoming messages on the main thread only, to avoid
// infinite repitition.
// Only touched on MainThread
bool mDeliveringMessage;
// Listeners to notify whenever a new message is logged.
ListenerHash mListeners;
ListenerHash mListeners GUARDED_BY(mLock);
// To serialize interesting methods.
mozilla::Mutex mLock MOZ_UNANNOTATED;
mozilla::Mutex mLock;
};
#endif /* __nsconsoleservice_h__ */

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

@ -125,8 +125,8 @@ class FifoWatcher : public FdWatcher {
explicit FifoWatcher(nsCString aPath)
: mDirPath(aPath), mFifoInfoLock("FifoWatcher.mFifoInfoLock") {}
mozilla::Mutex mFifoInfoLock MOZ_UNANNOTATED; // protects mFifoInfo
FifoInfoArray mFifoInfo;
mozilla::Mutex mFifoInfoLock; // protects mFifoInfo
FifoInfoArray mFifoInfo GUARDED_BY(mFifoInfoLock);
};
typedef void (*PipeCallback)(const uint8_t aRecvSig);
@ -159,8 +159,8 @@ class SignalPipeWatcher : public FdWatcher {
MOZ_ASSERT(NS_IsMainThread());
}
mozilla::Mutex mSignalInfoLock MOZ_UNANNOTATED; // protects mSignalInfo
SignalInfoArray mSignalInfo;
mozilla::Mutex mSignalInfoLock; // protects mSignalInfo
SignalInfoArray mSignalInfo GUARDED_BY(mSignalInfoLock);
};
#endif // XP_UNIX }

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

@ -166,7 +166,7 @@ class SmallArrayLRUCache {
#endif // SMALLARRAYLRUCACHE_STATS
private:
void Clear(const mozilla::OffTheBooksMutexAutoLock&) {
void Clear(const mozilla::OffTheBooksMutexAutoLock&) REQUIRES(mMutex) {
for (KeyAndValue* item = &mLRUArray[0]; item != &mLRUArray[mSize]; ++item) {
item->mValue = Value{};
}
@ -186,11 +186,11 @@ class SmallArrayLRUCache {
constexpr static unsigned ShutdownSize = unsigned(-1);
mozilla::OffTheBooksMutex mMutex{"LRU cache"};
unsigned mSize = 0;
KeyAndValue mLRUArray[LRUCapacity];
unsigned mSize GUARDED_BY(mMutex) = 0;
KeyAndValue mLRUArray[LRUCapacity] GUARDED_BY(mMutex);
#ifdef SMALLARRAYLRUCACHE_STATS
// Hit count for each position in the case. +1 for counting not-found cases.
unsigned mCacheFoundAt[LRUCapacity + 1] = {0u};
unsigned mCacheFoundAt[LRUCapacity + 1] GUARDED_BY(mMutex) = {0u};
#endif // SMALLARRAYLRUCACHE_STATS
};

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

@ -636,7 +636,6 @@ nsresult ShutdownXPCOM(nsIServiceManager* aServMgr) {
mozilla::AppShutdown::AdvanceShutdownPhase(
mozilla::ShutdownPhase::XPCOMShutdownThreads);
nsThreadManager::get().CancelBackgroundDelayedRunnables();
gXPCOMThreadsShutDown = true;
NS_ProcessPendingEvents(thread);

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

@ -186,19 +186,19 @@ static AtomCache sRecentlyUsedMainThreadAtoms;
// ConcurrentHashTable.
class nsAtomSubTable {
friend class nsAtomTable;
Mutex mLock MOZ_UNANNOTATED;
Mutex mLock;
PLDHashTable mTable;
nsAtomSubTable();
void GCLocked(GCKind aKind);
void GCLocked(GCKind aKind) REQUIRES(mLock);
void AddSizeOfExcludingThisLocked(MallocSizeOf aMallocSizeOf,
AtomsSizes& aSizes);
AtomsSizes& aSizes) REQUIRES(mLock);
AtomTableEntry* Search(AtomTableKey& aKey) const {
AtomTableEntry* Search(AtomTableKey& aKey) const REQUIRES(mLock) {
mLock.AssertCurrentThreadOwns();
return static_cast<AtomTableEntry*>(mTable.Search(&aKey));
}
AtomTableEntry* Add(AtomTableKey& aKey) {
AtomTableEntry* Add(AtomTableKey& aKey) REQUIRES(mLock) {
mLock.AssertCurrentThreadOwns();
return static_cast<AtomTableEntry*>(mTable.Add(&aKey)); // Infallible
}

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

@ -65,7 +65,7 @@ class NonBlockingAsyncInputStream final : public nsIAsyncInputStream,
nsISeekableStream* MOZ_NON_OWNING_REF mWeakSeekableInputStream;
nsITellableStream* MOZ_NON_OWNING_REF mWeakTellableInputStream;
Mutex mLock MOZ_UNANNOTATED;
Mutex mLock;
struct WaitClosureOnly {
WaitClosureOnly(AsyncWaitRunnable* aRunnable, nsIEventTarget* aEventTarget);
@ -77,13 +77,13 @@ class NonBlockingAsyncInputStream final : public nsIAsyncInputStream,
// This is set when AsyncWait is called with a callback and with
// WAIT_CLOSURE_ONLY as flag.
// This is protected by mLock.
Maybe<WaitClosureOnly> mWaitClosureOnly;
Maybe<WaitClosureOnly> mWaitClosureOnly GUARDED_BY(mLock);
// This is protected by mLock.
RefPtr<AsyncWaitRunnable> mAsyncWaitCallback;
RefPtr<AsyncWaitRunnable> mAsyncWaitCallback GUARDED_BY(mLock);
// This is protected by mLock.
bool mClosed;
bool mClosed GUARDED_BY(mLock);
};
} // namespace mozilla

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

@ -66,7 +66,8 @@ class nsMultiplexInputStream final : public nsIMultiplexInputStream,
void AsyncWaitCompleted();
// This is used for nsIAsyncInputStreamLength::AsyncLengthWait
void AsyncWaitCompleted(int64_t aLength, const MutexAutoLock& aProofOfLock);
void AsyncWaitCompleted(int64_t aLength, const MutexAutoLock& aProofOfLock)
REQUIRES(mLock);
struct StreamData {
nsresult Initialize(nsIInputStream* aOriginalStream) {
@ -103,7 +104,7 @@ class nsMultiplexInputStream final : public nsIMultiplexInputStream,
uint64_t mCurrentPos;
};
Mutex& GetLock() { return mLock; }
Mutex& GetLock() RETURN_CAPABILITY(mLock) { return mLock; }
private:
~nsMultiplexInputStream() = default;
@ -112,7 +113,7 @@ class nsMultiplexInputStream final : public nsIMultiplexInputStream,
// This method updates mSeekableStreams, mTellableStreams,
// mIPCSerializableStreams and mCloneableStreams values.
void UpdateQIMap(StreamData& aStream);
void UpdateQIMap(StreamData& aStream) REQUIRES(mLock);
struct MOZ_STACK_CLASS ReadSegmentsState {
nsCOMPtr<nsIInputStream> mThisStream;
@ -139,25 +140,26 @@ class nsMultiplexInputStream final : public nsIMultiplexInputStream,
bool IsInputStreamLength() const;
bool IsAsyncInputStreamLength() const;
Mutex mLock MOZ_UNANNOTATED; // Protects access to all data members.
Mutex mLock; // Protects access to all data members.
nsTArray<StreamData> mStreams;
nsTArray<StreamData> mStreams GUARDED_BY(mLock);
uint32_t mCurrentStream;
bool mStartedReadingCurrent;
nsresult mStatus;
nsCOMPtr<nsIInputStreamCallback> mAsyncWaitCallback;
uint32_t mAsyncWaitFlags;
uint32_t mAsyncWaitRequestedCount;
nsCOMPtr<nsIEventTarget> mAsyncWaitEventTarget;
nsCOMPtr<nsIInputStreamLengthCallback> mAsyncWaitLengthCallback;
uint32_t mCurrentStream GUARDED_BY(mLock);
bool mStartedReadingCurrent GUARDED_BY(mLock);
nsresult mStatus GUARDED_BY(mLock);
nsCOMPtr<nsIInputStreamCallback> mAsyncWaitCallback GUARDED_BY(mLock);
uint32_t mAsyncWaitFlags GUARDED_BY(mLock);
uint32_t mAsyncWaitRequestedCount GUARDED_BY(mLock);
nsCOMPtr<nsIEventTarget> mAsyncWaitEventTarget GUARDED_BY(mLock);
nsCOMPtr<nsIInputStreamLengthCallback> mAsyncWaitLengthCallback
GUARDED_BY(mLock);
class AsyncWaitLengthHelper;
RefPtr<AsyncWaitLengthHelper> mAsyncWaitLengthHelper;
RefPtr<AsyncWaitLengthHelper> mAsyncWaitLengthHelper GUARDED_BY(mLock);
uint32_t mSeekableStreams;
uint32_t mIPCSerializableStreams;
uint32_t mCloneableStreams;
uint32_t mSeekableStreams GUARDED_BY(mLock);
uint32_t mIPCSerializableStreams GUARDED_BY(mLock);
uint32_t mCloneableStreams GUARDED_BY(mLock);
// These are Atomics so that we can check them in QueryInterface without
// taking a lock (to look at mStreams.Length() and the numbers above)

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

@ -237,6 +237,7 @@ TEST(Synchronization, AutoLock)
//-----------------------------------------------------------------------------
// AutoTryLock tests
//
// The thread owns assertions make mutex analysis throw spurious warnings
TEST(Synchronization, AutoTryLock)
NO_THREAD_SAFETY_ANALYSIS {
Mutex l1 MOZ_UNANNOTATED("autotrylock");

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

@ -4,10 +4,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <memory>
#include "gtest/gtest.h"
#include "mozilla/SharedThreadPool.h"
#include "mozilla/SyncRunnable.h"
#include "mozilla/TaskQueue.h"
#include "mozilla/Unused.h"
#include "nsITargetShutdownTask.h"
#include "VideoUtils.h"
namespace TestTaskQueue {
@ -100,6 +103,100 @@ TEST(TaskQueue, GetCurrentSerialEventTarget)
tq1->AwaitShutdownAndIdle();
}
namespace {
class TestShutdownTask final : public nsITargetShutdownTask {
public:
NS_DECL_THREADSAFE_ISUPPORTS
explicit TestShutdownTask(std::function<void()> aCallback)
: mCallback(std::move(aCallback)) {}
void TargetShutdown() override {
if (mCallback) {
mCallback();
}
}
private:
~TestShutdownTask() = default;
std::function<void()> mCallback;
};
NS_IMPL_ISUPPORTS(TestShutdownTask, nsITargetShutdownTask)
} // namespace
TEST(TaskQueue, ShutdownTask)
{
auto shutdownTaskRun = std::make_shared<bool>();
auto runnableFromShutdownRun = std::make_shared<bool>();
RefPtr<TaskQueue> tq = new TaskQueue(
GetMediaThreadPool(MediaThreadType::SUPERVISOR), "Testing TaskQueue");
nsCOMPtr<nsITargetShutdownTask> shutdownTask = new TestShutdownTask([=] {
EXPECT_TRUE(tq->IsOnCurrentThread());
ASSERT_FALSE(*shutdownTaskRun);
*shutdownTaskRun = true;
nsCOMPtr<nsITargetShutdownTask> dummyTask = new TestShutdownTask([] {});
nsresult rv = tq->RegisterShutdownTask(dummyTask);
EXPECT_TRUE(rv == NS_ERROR_UNEXPECTED);
MOZ_ALWAYS_SUCCEEDS(
tq->Dispatch(NS_NewRunnableFunction("afterShutdownTask", [=] {
EXPECT_TRUE(tq->IsOnCurrentThread());
nsCOMPtr<nsITargetShutdownTask> dummyTask =
new TestShutdownTask([] {});
nsresult rv = tq->RegisterShutdownTask(dummyTask);
EXPECT_TRUE(rv == NS_ERROR_UNEXPECTED);
ASSERT_FALSE(*runnableFromShutdownRun);
*runnableFromShutdownRun = true;
})));
});
MOZ_ALWAYS_SUCCEEDS(tq->RegisterShutdownTask(shutdownTask));
ASSERT_FALSE(*shutdownTaskRun);
ASSERT_FALSE(*runnableFromShutdownRun);
RefPtr<mozilla::SyncRunnable> syncWithThread =
new mozilla::SyncRunnable(NS_NewRunnableFunction("dummy", [] {}));
MOZ_ALWAYS_SUCCEEDS(syncWithThread->DispatchToThread(tq));
ASSERT_FALSE(*shutdownTaskRun);
ASSERT_FALSE(*runnableFromShutdownRun);
tq->BeginShutdown();
tq->AwaitShutdownAndIdle();
ASSERT_TRUE(*shutdownTaskRun);
ASSERT_TRUE(*runnableFromShutdownRun);
}
TEST(TaskQueue, UnregisteredShutdownTask)
{
RefPtr<TaskQueue> tq = new TaskQueue(
GetMediaThreadPool(MediaThreadType::SUPERVISOR), "Testing TaskQueue");
nsCOMPtr<nsITargetShutdownTask> shutdownTask =
new TestShutdownTask([=] { MOZ_CRASH("should not be run"); });
MOZ_ALWAYS_SUCCEEDS(tq->RegisterShutdownTask(shutdownTask));
RefPtr<mozilla::SyncRunnable> syncWithThread =
new mozilla::SyncRunnable(NS_NewRunnableFunction("dummy", [] {}));
MOZ_ALWAYS_SUCCEEDS(syncWithThread->DispatchToThread(tq));
MOZ_ALWAYS_SUCCEEDS(tq->UnregisterShutdownTask(shutdownTask));
tq->BeginShutdown();
tq->AwaitShutdownAndIdle();
}
TEST(AbstractThread, GetCurrentSerialEventTarget)
{
RefPtr<AbstractThread> mainThread = AbstractThread::GetCurrent();

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше