зеркало из https://github.com/mozilla/gecko-dev.git
Merge autoland to mozilla-central. a=merge
This commit is contained in:
Коммит
0077f22487
|
@ -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();
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче