icecat: add release icecat-140.10.1-1gnu1 for ecne
This commit is contained in:
parent
a5f93cb214
commit
ff85d7c623
1256 changed files with 63469 additions and 24141 deletions
|
|
@ -85,9 +85,9 @@ git = "https://github.com/mozilla/audioipc"
|
|||
rev = "e6f44a2bd1e57d11dfc737632a9e849077632330"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=579b75af21c040700eee6a1d8520e222699fe4cd"]
|
||||
[source."git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=bebaa23317332c95734df76e25193c24a83a6840"]
|
||||
git = "https://github.com/mozilla/cubeb-coreaudio-rs"
|
||||
rev = "579b75af21c040700eee6a1d8520e222699fe4cd"
|
||||
rev = "bebaa23317332c95734df76e25193c24a83a6840"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."git+https://github.com/mozilla/cubeb-pulse-rs?rev=8678dcab1c287de79c4c184ccc2e065bc62b70e2"]
|
||||
|
|
|
|||
3
icecat/.gitignore
vendored
3
icecat/.gitignore
vendored
|
|
@ -373,3 +373,6 @@ toolkit/crashreporter/minidump-analyzer/analyzer-test/target/
|
|||
|
||||
# Ignore mozperftest artifacts folder
|
||||
/artifacts/
|
||||
|
||||
# Ignore personal preferences files
|
||||
CLAUDE.local.md
|
||||
|
|
|
|||
|
|
@ -22,4 +22,4 @@
|
|||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Merge day clobber 2026-02-23
|
||||
Merge day clobber 2026-03-23
|
||||
4
icecat/Cargo.lock
generated
4
icecat/Cargo.lock
generated
|
|
@ -1086,7 +1086,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "coreaudio-sys-utils"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=579b75af21c040700eee6a1d8520e222699fe4cd#579b75af21c040700eee6a1d8520e222699fe4cd"
|
||||
source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=bebaa23317332c95734df76e25193c24a83a6840#bebaa23317332c95734df76e25193c24a83a6840"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"coreaudio-sys",
|
||||
|
|
@ -1398,7 +1398,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "cubeb-coreaudio"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=579b75af21c040700eee6a1d8520e222699fe4cd#579b75af21c040700eee6a1d8520e222699fe4cd"
|
||||
source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=bebaa23317332c95734df76e25193c24a83a6840#bebaa23317332c95734df76e25193c24a83a6840"
|
||||
dependencies = [
|
||||
"atomic",
|
||||
"audio-mixer",
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ using namespace mozilla::a11y;
|
|||
// AccIterator
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AccIterator::AccIterator(const LocalAccessible* aAccessible,
|
||||
AccIterator::AccIterator(LocalAccessible* aAccessible,
|
||||
filters::FilterFuncPtr aFilterFunc)
|
||||
: mFilterFunc(aFilterFunc) {
|
||||
mState = new IteratorState(aAccessible);
|
||||
|
|
@ -63,7 +63,7 @@ LocalAccessible* AccIterator::Next() {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsAccIterator::IteratorState
|
||||
|
||||
AccIterator::IteratorState::IteratorState(const LocalAccessible* aParent,
|
||||
AccIterator::IteratorState::IteratorState(LocalAccessible* aParent,
|
||||
IteratorState* mParentState)
|
||||
: mParent(aParent), mIndex(0), mParentState(mParentState) {}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ class AccIterable {
|
|||
*/
|
||||
class AccIterator : public AccIterable {
|
||||
public:
|
||||
AccIterator(const LocalAccessible* aRoot, filters::FilterFuncPtr aFilterFunc);
|
||||
AccIterator(LocalAccessible* aRoot, filters::FilterFuncPtr aFilterFunc);
|
||||
virtual ~AccIterator();
|
||||
|
||||
/**
|
||||
|
|
@ -57,10 +57,10 @@ class AccIterator : public AccIterable {
|
|||
AccIterator& operator=(const AccIterator&);
|
||||
|
||||
struct IteratorState {
|
||||
explicit IteratorState(const LocalAccessible* aParent,
|
||||
explicit IteratorState(LocalAccessible* aParent,
|
||||
IteratorState* mParentState = nullptr);
|
||||
|
||||
const LocalAccessible* mParent;
|
||||
RefPtr<LocalAccessible> mParent;
|
||||
int32_t mIndex;
|
||||
IteratorState* mParentState;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -71,10 +71,14 @@ void CachedTableAccessible::Invalidate(Accessible* aAcc) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (Accessible* table = nsAccUtils::TableFor(aAcc)) {
|
||||
Accessible* table = nsAccUtils::TableFor(aAcc);
|
||||
while (table && table->IsTable()) {
|
||||
// Destroy the instance (if any). We'll create a new one the next time it
|
||||
// is requested.
|
||||
// is requested. Climb up the heirarcy to invalidate parent tables as well.
|
||||
sCachedTables->Remove(table);
|
||||
// The table may be a direct child of another table, invalidate that one as
|
||||
// well.
|
||||
table = table->Parent();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -536,7 +536,7 @@ static dom::Selection* GetDOMSelection(const nsIContent* aStartContent,
|
|||
return startFrameSel ? &startFrameSel->NormalSelection() : nullptr;
|
||||
}
|
||||
|
||||
std::pair<nsIContent*, uint32_t> TextLeafPoint::ToDOMPoint(
|
||||
std::pair<RefPtr<nsIContent>, uint32_t> TextLeafPoint::ToDOMPoint(
|
||||
bool aIncludeGenerated) const {
|
||||
if (!(*this) || !mAcc->IsLocal()) {
|
||||
MOZ_ASSERT_UNREACHABLE("Invalid point");
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ class TextLeafPoint final {
|
|||
/**
|
||||
* Translate given TextLeafPoint into a DOM point.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT std::pair<nsIContent*, uint32_t> ToDOMPoint(
|
||||
MOZ_CAN_RUN_SCRIPT std::pair<RefPtr<nsIContent>, uint32_t> ToDOMPoint(
|
||||
bool aIncludeGenerated = true) const;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -859,16 +859,15 @@ void HyperTextAccessible::ReplaceText(const nsAString& aText) {
|
|||
return;
|
||||
}
|
||||
|
||||
RefPtr<EditorBase> editorBase = GetEditor();
|
||||
|
||||
SetSelectionBoundsAt(TextLeafRange::kRemoveAllExistingSelectedRanges, 0,
|
||||
CharacterCount());
|
||||
|
||||
RefPtr<EditorBase> editorBase = GetEditor();
|
||||
if (!editorBase) {
|
||||
return;
|
||||
if (editorBase) {
|
||||
DebugOnly<nsresult> rv = editorBase->InsertTextAsAction(aText);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to insert the new text");
|
||||
}
|
||||
|
||||
DebugOnly<nsresult> rv = editorBase->InsertTextAsAction(aText);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to insert the new text");
|
||||
}
|
||||
|
||||
void HyperTextAccessible::InsertText(const nsAString& aText,
|
||||
|
|
|
|||
|
|
@ -118,6 +118,11 @@ mozilla::ipc::IPCResult DocAccessibleParent::ProcessShowEvent(
|
|||
return IPC_OK();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (parent->IsOuterDoc()) {
|
||||
return IPC_FAIL(this, "Cannot attach non-doc to OuterDoc");
|
||||
}
|
||||
|
||||
lastParent = parent;
|
||||
lastParentID = accData.ParentID();
|
||||
|
||||
|
|
@ -223,6 +228,11 @@ mozilla::ipc::IPCResult DocAccessibleParent::ProcessShowEvent(
|
|||
|
||||
RemoteAccessible* DocAccessibleParent::CreateAcc(
|
||||
const AccessibleData& aAccData) {
|
||||
if (aAccData.ID() == 0) {
|
||||
MOZ_ASSERT_UNREACHABLE("An ID of 0 is reserved for the document itself");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RemoteAccessible* newProxy;
|
||||
if ((newProxy = GetAccessible(aAccData.ID()))) {
|
||||
// This is a move. Reuse the Accessible; don't destroy it.
|
||||
|
|
@ -906,7 +916,10 @@ mozilla::ipc::IPCResult DocAccessibleParent::RecvBindChildDoc(
|
|||
MOZ_ASSERT(CheckDocTree());
|
||||
|
||||
auto childDoc = static_cast<DocAccessibleParent*>(aChildDoc.get());
|
||||
childDoc->Unbind();
|
||||
if (childDoc->IsShutdown()) {
|
||||
return IPC_FAIL(this, "Attempt to bind a shutdown child doc");
|
||||
}
|
||||
|
||||
ipc::IPCResult result = AddChildDoc(childDoc, aID, false);
|
||||
MOZ_ASSERT(result);
|
||||
MOZ_ASSERT(CheckDocTree());
|
||||
|
|
@ -929,6 +942,10 @@ ipc::IPCResult DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc,
|
|||
"Attempt to add child doc which already has a parent");
|
||||
}
|
||||
|
||||
if (aChildDoc->IsShutdown()) {
|
||||
return IPC_FAIL(this, "Attempt to add a shutdown child doc");
|
||||
}
|
||||
|
||||
// We do not use GetAccessible here because we want to be sure to not get the
|
||||
// document it self.
|
||||
ProxyEntry* e = mAccessibles.GetEntry(aParentID);
|
||||
|
|
@ -1031,6 +1048,9 @@ void DocAccessibleParent::Destroy() {
|
|||
// If we are already shutdown that is because our containing tab parent is
|
||||
// shutting down in which case we don't need to do anything.
|
||||
if (mShutdown) {
|
||||
// Just in case there is a cycle in the document heirarchy.
|
||||
mParent = nullptr;
|
||||
mIndexInParent = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1068,6 +1088,8 @@ void DocAccessibleParent::Destroy() {
|
|||
RemoteAccessible* acc = iter.Get()->mProxy;
|
||||
MOZ_ASSERT(acc != this);
|
||||
if (acc->IsTable()) {
|
||||
// Prevents the invalidation code from trying to walk up the tree.
|
||||
acc->SetParent(nullptr);
|
||||
CachedTableAccessible::Invalidate(acc);
|
||||
}
|
||||
ProxyDestroyed(acc);
|
||||
|
|
@ -1113,6 +1135,9 @@ void DocAccessibleParent::ActorDestroy(ActorDestroyReason aWhy) {
|
|||
if (!mShutdown) {
|
||||
ACQUIRE_ANDROID_LOCK
|
||||
Destroy();
|
||||
} else if (RemoteParent()) {
|
||||
ACQUIRE_ANDROID_LOCK
|
||||
Unbind();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,25 +16,9 @@ function getSiteBlockedErrorDetails(docShell) {
|
|||
Ci.nsIClassifiedChannel
|
||||
);
|
||||
if (classifiedChannel) {
|
||||
let httpChannel = docShell.failedChannel.QueryInterface(
|
||||
Ci.nsIHttpChannel
|
||||
);
|
||||
|
||||
let reportUri = httpChannel.URI;
|
||||
|
||||
// Remove the query to avoid leaking sensitive data
|
||||
if (reportUri instanceof Ci.nsIURL) {
|
||||
reportUri = reportUri.mutate().setQuery("").finalize();
|
||||
}
|
||||
|
||||
let triggeringPrincipal = docShell.failedChannel.loadInfo
|
||||
? docShell.failedChannel.loadInfo.triggeringPrincipal
|
||||
: null;
|
||||
blockedInfo = {
|
||||
list: classifiedChannel.matchedList,
|
||||
triggeringPrincipal,
|
||||
provider: classifiedChannel.matchedProvider,
|
||||
uri: reportUri.asciiSpec,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -177,8 +177,11 @@ export class BlockedSiteParent extends EscapablePageParent {
|
|||
// site, so that they don't lose track after, e.g., tab switching.
|
||||
// We can't use browser.contentPrincipal which is principal of about:blocked
|
||||
// Create one from uri with current principal origin attributes
|
||||
|
||||
// Remove the query to avoid leaking sensitive data
|
||||
let uri = browsingContext.currentURI.mutate().setQuery("").finalize();
|
||||
let principal = Services.scriptSecurityManager.createContentPrincipal(
|
||||
Services.io.newURI(blockedInfo.uri),
|
||||
uri,
|
||||
browsingContext.currentWindowGlobal.documentPrincipal.originAttributes
|
||||
);
|
||||
Services.perms.addFromPrincipal(
|
||||
|
|
@ -206,10 +209,10 @@ export class BlockedSiteParent extends EscapablePageParent {
|
|||
let title;
|
||||
let chromeWin = browsingContext.topChromeWindow;
|
||||
if (reason === "malware") {
|
||||
let reportUrl = lazy.SafeBrowsing.getReportURL(
|
||||
"MalwareMistake",
|
||||
blockedInfo
|
||||
);
|
||||
let reportUrl = lazy.SafeBrowsing.getReportURL("MalwareMistake", {
|
||||
...blockedInfo,
|
||||
uri: uri.asciiSpec,
|
||||
});
|
||||
title = lazy.browserBundle.GetStringFromName(
|
||||
"safebrowsing.reportedAttackSite"
|
||||
);
|
||||
|
|
@ -233,10 +236,10 @@ export class BlockedSiteParent extends EscapablePageParent {
|
|||
};
|
||||
}
|
||||
} else if (reason === "phishing") {
|
||||
let reportUrl = lazy.SafeBrowsing.getReportURL(
|
||||
"PhishMistake",
|
||||
blockedInfo
|
||||
);
|
||||
let reportUrl = lazy.SafeBrowsing.getReportURL("PhishMistake", {
|
||||
...blockedInfo,
|
||||
uri: uri.asciiSpec,
|
||||
});
|
||||
title = lazy.browserBundle.GetStringFromName(
|
||||
"safebrowsing.deceptiveSite"
|
||||
);
|
||||
|
|
@ -281,16 +284,15 @@ export class BlockedSiteParent extends EscapablePageParent {
|
|||
buttons
|
||||
);
|
||||
|
||||
// Allow users to override and continue through to the site.
|
||||
// Note that we have to use the passed URI info and can't just
|
||||
// rely on the document URI, because the latter contains
|
||||
// additional query parameters that should be stripped.
|
||||
let triggeringPrincipal =
|
||||
blockedInfo.triggeringPrincipal ||
|
||||
Services.scriptSecurityManager.createNullPrincipal({});
|
||||
let activeSHEntry = browsingContext.activeSessionHistoryEntry;
|
||||
if (!activeSHEntry) {
|
||||
console.error("No active session history entry found");
|
||||
return;
|
||||
}
|
||||
|
||||
browsingContext.fixupAndLoadURIString(blockedInfo.uri, {
|
||||
triggeringPrincipal,
|
||||
// Allow users to override and continue through to the site.
|
||||
browsingContext.loadURI(uri, {
|
||||
triggeringPrincipal: activeSHEntry.triggeringPrincipal,
|
||||
loadFlags: Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CLASSIFIER,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,9 +142,7 @@ export class DOMFullscreenParent extends JSWindowActorParent {
|
|||
case "DOMFullscreen:NewOrigin": {
|
||||
// Don't show the warning if we've already exited fullscreen.
|
||||
if (window.document.fullscreen) {
|
||||
window.PointerlockFsWarning.showFullScreen(
|
||||
aMessage.data.originNoSuffix
|
||||
);
|
||||
window.PointerlockFsWarning.showFullScreen(topBrowsingContext);
|
||||
}
|
||||
this.updateFullscreenWindowReference(window);
|
||||
break;
|
||||
|
|
@ -222,7 +220,7 @@ export class DOMFullscreenParent extends JSWindowActorParent {
|
|||
|
||||
if (!this.hasBeenDestroyed() && this.requestOrigin) {
|
||||
window.PointerlockFsWarning.showFullScreen(
|
||||
this.requestOrigin.manager.documentPrincipal.originNoSuffix
|
||||
this.requestOrigin.browsingContext
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -49,10 +49,16 @@ var PointerlockFsWarning = {
|
|||
}
|
||||
},
|
||||
|
||||
showFullScreen(aOrigin) {
|
||||
// Show info that top level has entered fullscreen. Ultimately, it is always
|
||||
// ancestors who are in control and can with various means make the user believe
|
||||
// a site has entered fullscreen while displaying it's own content.
|
||||
// We try to make it clear to the user that it's the top level that is actually in fullscreen
|
||||
showFullScreen(browsingContext) {
|
||||
const origin =
|
||||
browsingContext.top.currentWindowGlobal.documentPrincipal.originNoSuffix;
|
||||
let timeout = Services.prefs.getIntPref("full-screen-api.warning.timeout");
|
||||
let delay = Services.prefs.getIntPref("full-screen-api.warning.delay");
|
||||
this.show(aOrigin, "fullscreen-warning", timeout, delay);
|
||||
this.show(origin, "fullscreen-warning", timeout, delay);
|
||||
},
|
||||
|
||||
// Shows a warning that the site has entered fullscreen or
|
||||
|
|
|
|||
|
|
@ -60,6 +60,9 @@ skip-if = [
|
|||
"os == 'linux' && os_version == '18.04' && processor == 'x86_64' && swgl", # Bug 1949995
|
||||
]
|
||||
|
||||
["browser_fullscreen_toplevel_warning.js"]
|
||||
support-files = ["fullscreen.html"]
|
||||
|
||||
["browser_fullscreen_warning.js"]
|
||||
support-files = ["fullscreen.html"]
|
||||
skip-if = [
|
||||
|
|
|
|||
|
|
@ -0,0 +1,184 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const FULLSCREEN_PATH =
|
||||
"/browser/browser/base/content/test/fullscreen/fullscreen.html";
|
||||
|
||||
function getWarningDomain(warning) {
|
||||
let textElem = warning.querySelector(".pointerlockfswarning-domain-text");
|
||||
if (textElem.hidden) {
|
||||
return null;
|
||||
}
|
||||
let args = textElem.getAttribute("data-l10n-args");
|
||||
return args ? JSON.parse(args).domain : null;
|
||||
}
|
||||
|
||||
async function waitForWarningState(aWarningElement, aExpectedState) {
|
||||
await BrowserTestUtils.waitForAttribute(aExpectedState, aWarningElement, "");
|
||||
}
|
||||
|
||||
add_setup(async function init() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["test.wait300msAfterTabSwitch", true],
|
||||
["full-screen-api.enabled", true],
|
||||
["full-screen-api.allow-trusted-requests-only", false],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
// Bug 2021080 - Verify the fullscreen warning always displays the top-level domain,
|
||||
// not the origin of the cross-origin frame that requested fullscreen.
|
||||
add_task(async function test_fullscreen_warning_cross_origin_shows_toplevel() {
|
||||
await BrowserTestUtils.withNewTab("https://example.com", async browser => {
|
||||
let warning = document.getElementById("fullscreen-warning");
|
||||
|
||||
await SpecialPowers.spawn(browser, [FULLSCREEN_PATH], async path => {
|
||||
let iframe = content.document.createElement("iframe");
|
||||
iframe.allow = "fullscreen";
|
||||
iframe.src = `https://example.org${path}`;
|
||||
let loaded = new Promise(r =>
|
||||
iframe.addEventListener("load", r, { once: true })
|
||||
);
|
||||
content.document.body.appendChild(iframe);
|
||||
await loaded;
|
||||
});
|
||||
|
||||
let warningShown = waitForWarningState(warning, "onscreen");
|
||||
await SpecialPowers.spawn(browser, [], async () => {
|
||||
let frame = content.document.querySelector("iframe");
|
||||
frame.focus();
|
||||
await SpecialPowers.spawn(frame, [], () => {
|
||||
content.document.getElementById("request").click();
|
||||
});
|
||||
});
|
||||
await warningShown;
|
||||
|
||||
let activeOrigin = await SpecialPowers.spawn(browser, [], async () => {
|
||||
let frame = content.document.querySelector("iframe");
|
||||
return SpecialPowers.spawn(frame, [], () => content.location.hostname);
|
||||
});
|
||||
is(
|
||||
activeOrigin,
|
||||
"example.org",
|
||||
"Cross-origin frame (example.org) is the active fullscreen document"
|
||||
);
|
||||
is(
|
||||
getWarningDomain(warning),
|
||||
"example.com",
|
||||
"Warning shows top-level domain, not the active fullscreen frame's domain"
|
||||
);
|
||||
|
||||
let warningHidden = waitForWarningState(warning, "hidden");
|
||||
let exitPromise = BrowserTestUtils.waitForEvent(
|
||||
document,
|
||||
"fullscreenchange",
|
||||
false,
|
||||
() => !document.fullscreenElement
|
||||
);
|
||||
document.getElementById("fullscreen-exit-button").click();
|
||||
await Promise.all([exitPromise, warningHidden]);
|
||||
});
|
||||
});
|
||||
|
||||
// Bug 2021080 - Verify the fullscreen warning shows the top-level domain when each
|
||||
// of three nested cross-origin frames (top, middle, inner) requests fullscreen.
|
||||
add_task(async function test_fullscreen_warning_three_nested_origins() {
|
||||
await BrowserTestUtils.withNewTab("https://example.com", async browser => {
|
||||
let warning = document.getElementById("fullscreen-warning");
|
||||
|
||||
// Build a 3-level nested structure:
|
||||
// example.com (div > iframe[example.org (div > iframe[example.net])])
|
||||
await SpecialPowers.spawn(browser, [FULLSCREEN_PATH], async path => {
|
||||
let topDiv = content.document.createElement("div");
|
||||
content.document.body.appendChild(topDiv);
|
||||
|
||||
let middleFrame = content.document.createElement("iframe");
|
||||
middleFrame.allow = "fullscreen";
|
||||
middleFrame.src = `https://example.org${path}`;
|
||||
let loaded = new Promise(r =>
|
||||
middleFrame.addEventListener("load", r, { once: true })
|
||||
);
|
||||
topDiv.appendChild(middleFrame);
|
||||
await loaded;
|
||||
|
||||
await SpecialPowers.spawn(middleFrame, [path], async innerPath => {
|
||||
let middleDiv = content.document.createElement("div");
|
||||
content.document.body.appendChild(middleDiv);
|
||||
|
||||
let innerFrame = content.document.createElement("iframe");
|
||||
innerFrame.allow = "fullscreen";
|
||||
innerFrame.src = `https://example.net${innerPath}`;
|
||||
let innerLoaded = new Promise(r =>
|
||||
innerFrame.addEventListener("load", r, { once: true })
|
||||
);
|
||||
middleDiv.appendChild(innerFrame);
|
||||
await innerLoaded;
|
||||
});
|
||||
});
|
||||
|
||||
async function exitFullscreen() {
|
||||
let warningHidden = waitForWarningState(warning, "hidden");
|
||||
let exitPromise = BrowserTestUtils.waitForEvent(
|
||||
document,
|
||||
"fullscreenchange",
|
||||
false,
|
||||
() => !document.fullscreenElement
|
||||
);
|
||||
document.getElementById("fullscreen-exit-button").click();
|
||||
await Promise.all([exitPromise, warningHidden]);
|
||||
}
|
||||
|
||||
// Step 1: Top-level (example.com) requests fullscreen on its div.
|
||||
let warningShown = waitForWarningState(warning, "onscreen");
|
||||
await SpecialPowers.spawn(browser, [], () => {
|
||||
content.document.querySelector("div").requestFullscreen();
|
||||
});
|
||||
await warningShown;
|
||||
is(
|
||||
getWarningDomain(warning),
|
||||
"example.com",
|
||||
"Top-level fullscreen: warning shows top-level domain"
|
||||
);
|
||||
await exitFullscreen();
|
||||
|
||||
// Step 2: Middle frame (example.org) requests fullscreen on its div.
|
||||
warningShown = waitForWarningState(warning, "onscreen");
|
||||
await SpecialPowers.spawn(browser, [], async () => {
|
||||
let middleFrame = content.document.querySelector("iframe");
|
||||
middleFrame.focus();
|
||||
await SpecialPowers.spawn(middleFrame, [], () => {
|
||||
content.document.querySelector("div").requestFullscreen();
|
||||
});
|
||||
});
|
||||
await warningShown;
|
||||
is(
|
||||
getWarningDomain(warning),
|
||||
"example.com",
|
||||
"Middle frame fullscreen: warning shows top-level domain"
|
||||
);
|
||||
await exitFullscreen();
|
||||
|
||||
// Step 3: Inner frame (example.net) requests fullscreen on an element.
|
||||
warningShown = waitForWarningState(warning, "onscreen");
|
||||
await SpecialPowers.spawn(browser, [], async () => {
|
||||
let middleFrame = content.document.querySelector("iframe");
|
||||
await SpecialPowers.spawn(middleFrame, [], async () => {
|
||||
let innerFrame = content.document.querySelector("iframe");
|
||||
innerFrame.focus();
|
||||
await SpecialPowers.spawn(innerFrame, [], () => {
|
||||
content.document.getElementById("request").click();
|
||||
});
|
||||
});
|
||||
});
|
||||
await warningShown;
|
||||
is(
|
||||
getWarningDomain(warning),
|
||||
"example.com",
|
||||
"Inner frame fullscreen: warning shows top-level domain"
|
||||
);
|
||||
await exitFullscreen();
|
||||
});
|
||||
});
|
||||
|
|
@ -551,11 +551,8 @@ async function getAutofillRecords(data) {
|
|||
// JSActors, but that would import a lot of code for a targeting attribute.
|
||||
return 0;
|
||||
}
|
||||
let records = await actor?.receiveMessage({
|
||||
name: "FormAutofill:GetRecords",
|
||||
data,
|
||||
});
|
||||
return records?.records?.length ?? 0;
|
||||
let records = await actor?.getRecords(data);
|
||||
return records?.length ?? 0;
|
||||
}
|
||||
|
||||
// Attribution data can be encoded multiple times so we need this function to
|
||||
|
|
|
|||
|
|
@ -1418,15 +1418,10 @@ add_task(async function test_creditCardsSaved() {
|
|||
gBrowser.selectedBrowser.browsingContext.currentWindowGlobal.getActor(
|
||||
"FormAutofill"
|
||||
),
|
||||
"receiveMessage"
|
||||
"getRecords"
|
||||
)
|
||||
.withArgs(
|
||||
sandbox.match({
|
||||
name: "FormAutofill:GetRecords",
|
||||
data: { collectionName: "creditCards" },
|
||||
})
|
||||
)
|
||||
.resolves({ records: [creditcard] })
|
||||
.withArgs(sandbox.match({ collectionName: "creditCards" }))
|
||||
.resolves([creditcard])
|
||||
.callThrough();
|
||||
|
||||
is(
|
||||
|
|
@ -1435,8 +1430,8 @@ add_task(async function test_creditCardsSaved() {
|
|||
"Should return 1 when 1 credit card is saved"
|
||||
);
|
||||
ok(
|
||||
stub.calledWithMatch({ name: "FormAutofill:GetRecords" }),
|
||||
"Targeting called FormAutofill:GetRecords"
|
||||
stub.calledWithMatch({ collectionName: "creditCards" }),
|
||||
"Targeting called getRecords"
|
||||
);
|
||||
|
||||
sandbox.restore();
|
||||
|
|
|
|||
|
|
@ -60,5 +60,5 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"required": ["providerId", "searchPageRegexp", "includeParams"]
|
||||
"required": ["providerId", "searchPageRegexp"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
140.9.0
|
||||
140.10.1
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
140.9.0esr
|
||||
140.10.1esr
|
||||
|
|
|
|||
|
|
@ -13,5 +13,5 @@ MOZ_BRANDING_DIRECTORY=browser/branding/unofficial
|
|||
MOZ_OFFICIAL_BRANDING_DIRECTORY=browser/branding/official
|
||||
# IceCat settings
|
||||
MOZ_APP_BASENAME=IceCat
|
||||
MOZ_APP_VERSION=140.9.0
|
||||
MOZ_APP_VERSION=140.10.1
|
||||
MOZ_DATA_REPORTING=0
|
||||
|
|
|
|||
|
|
@ -10,4 +10,4 @@
|
|||
# hardcoded milestones in the tree from these two files.
|
||||
#--------------------------------------------------------
|
||||
|
||||
140.9.0
|
||||
140.10.1
|
||||
|
|
|
|||
|
|
@ -1,3 +1,15 @@
|
|||
icecat (140.10.1-1gnu1+build1-0.12.0) ecne; urgency=medium
|
||||
|
||||
* New upstream stable release (icecat-140.10.1-1gnu1)
|
||||
|
||||
-- Capitulo Mexicano de Software Libre <devel@cmxsl.org> Mon, 04 May 2026 16:44:54 -0600
|
||||
|
||||
icecat (140.10.0-1gnu1+build1-0.12.0) ecne; urgency=medium
|
||||
|
||||
* New upstream stable release (icecat-140.10.0-1gnu1)
|
||||
|
||||
-- Capitulo Mexicano de Software Libre <devel@cmxsl.org> Tue, 28 Apr 2026 03:08:30 -0600
|
||||
|
||||
icecat (140.9.0-1gnu1+build1-0.12.0) ecne; urgency=medium
|
||||
|
||||
* New upstream stable release (icecat-140.9.0-1gnu1)
|
||||
|
|
|
|||
|
|
@ -190,6 +190,7 @@ fail-if = ["a11y_checks"] # Bug 1849028 clicked element may not be focusable and
|
|||
|
||||
["browser_aboutdebugging_serviceworker_start.js"]
|
||||
skip-if = [
|
||||
"os == 'linux' && os_version == '18.04' && processor == 'x86_64' && tsan", # Bug 1947358, Bug 2030884
|
||||
"os == 'linux' && os_version == '24.04' && processor == 'x86_64' && display == 'x11' && tsan", # Bug 1947358
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -96,8 +96,11 @@ fail-if = ["a11y_checks"] # Bug 1849028 clicked element may not be focusable and
|
|||
["browser_application_panel_start-service-worker.js"]
|
||||
fail-if = ["a11y_checks"] # Bug 1849028 clicked element may not be focusable and/or labeled
|
||||
skip-if = [
|
||||
"os == 'linux' && os_version == '18.04' && processor == 'x86_64' && tsan", # Bug 1608640
|
||||
"os == 'linux' && os_version == '24.04' && processor == 'x86_64' && display == 'x11' && tsan", # Bug 1608640
|
||||
"os == 'linux' && processor == 'x86_64' && tsan", # Bug 1608640, Bug 2030884
|
||||
"os == 'linux' && processor == 'x86_64' && asan", # Bug 1781479, Bug 2030884
|
||||
"os == 'mac' && os_version == '14.70' && processor == 'x86_64'", # Bug 1980084, Bug 2030884
|
||||
"os == 'win' && os_version == '11.26100' && processor == 'x86_64' && asan", # Bug 1781479, Bug 2030884
|
||||
"os == 'win' && os_version == '11.26200' && processor == 'x86_64' && asan", # Bug 1781479, Bug 2030884
|
||||
]
|
||||
|
||||
["browser_application_panel_target-switching.js"]
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ export default [
|
|||
process: true,
|
||||
global: true,
|
||||
L10N: true,
|
||||
// TODO: Add this to the main ESlint globals Bug 2025542
|
||||
Sanitizer: true,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@
|
|||
* 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/>. */
|
||||
|
||||
import React, { Component } from "devtools/client/shared/vendor/react";
|
||||
import { div } from "devtools/client/shared/vendor/react-dom-factories";
|
||||
import React, {
|
||||
Component,
|
||||
createRef,
|
||||
} from "devtools/client/shared/vendor/react";
|
||||
import PropTypes from "devtools/client/shared/vendor/react-prop-types";
|
||||
import { connect } from "devtools/client/shared/vendor/react-redux";
|
||||
import { basename } from "../utils/path";
|
||||
import { createLocation } from "../utils/location";
|
||||
|
||||
const fuzzyAldrin = require("resource://devtools/client/shared/vendor/fuzzaldrin-plus.js");
|
||||
|
|
@ -59,6 +60,7 @@ export class QuickOpenModal extends Component {
|
|||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { results: null, selectedIndex: 0 };
|
||||
this.resultListRef = createRef();
|
||||
}
|
||||
|
||||
static get propTypes() {
|
||||
|
|
@ -223,20 +225,14 @@ export class QuickOpenModal extends Component {
|
|||
|
||||
if (query == "" && !this.isShortcutQuery()) {
|
||||
this.showTopSources();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isSymbolSearch()) {
|
||||
} else if (this.isSymbolSearch()) {
|
||||
await this.searchSymbols(query);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isShortcutQuery()) {
|
||||
} else if (this.isShortcutQuery()) {
|
||||
this.searchShortcuts(query);
|
||||
return;
|
||||
} else {
|
||||
this.searchSources(query);
|
||||
}
|
||||
|
||||
this.searchSources(query);
|
||||
this.highlightQueryMatches(this.props.query);
|
||||
} catch (e) {
|
||||
// Due to throttling this might get scheduled after the component and the
|
||||
// toolbox are destroyed.
|
||||
|
|
@ -394,23 +390,35 @@ export class QuickOpenModal extends Component {
|
|||
isSourcesQuery = () => this.props.searchType === "sources";
|
||||
isSourceSearch = () => this.isSourcesQuery() || this.isGotoSourceQuery();
|
||||
|
||||
/* eslint-disable react/no-danger */
|
||||
renderHighlight(candidateString, query) {
|
||||
highlightQueryMatches(query) {
|
||||
const options = {
|
||||
wrap: {
|
||||
tagOpen: '<mark class="highlight">',
|
||||
tagClose: "</mark>",
|
||||
},
|
||||
};
|
||||
const html = fuzzyAldrin.wrap(candidateString, query, options);
|
||||
return div({
|
||||
dangerouslySetInnerHTML: {
|
||||
__html: html,
|
||||
},
|
||||
});
|
||||
if (this.resultListRef.current) {
|
||||
const domEl = this.resultListRef.current.ref.current;
|
||||
for (const titleNode of domEl.querySelectorAll(".title")) {
|
||||
const htmlString = fuzzyAldrin.wrap(
|
||||
titleNode.innerText,
|
||||
query,
|
||||
options
|
||||
);
|
||||
// Sanitizer API not supported in ESR 140
|
||||
// Should remove at ESR 153
|
||||
if ("Sanitizer" in window) {
|
||||
const sanitizer = new Sanitizer({
|
||||
elements: ["mark"],
|
||||
attributes: ["class"],
|
||||
});
|
||||
titleNode.setHTML(htmlString, { sanitizer });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
highlightMatching = (query, results) => {
|
||||
renderResults = (query, results) => {
|
||||
let newQuery = query;
|
||||
if (newQuery === "") {
|
||||
return results;
|
||||
|
|
@ -421,11 +429,7 @@ export class QuickOpenModal extends Component {
|
|||
if (typeof result.title == "string") {
|
||||
return {
|
||||
...result,
|
||||
title: this.renderHighlight(
|
||||
result.title,
|
||||
basename(newQuery),
|
||||
"title"
|
||||
),
|
||||
title: result.title,
|
||||
};
|
||||
}
|
||||
return result;
|
||||
|
|
@ -454,7 +458,7 @@ export class QuickOpenModal extends Component {
|
|||
const { query } = this.props;
|
||||
const { selectedIndex, results } = this.state;
|
||||
|
||||
const items = this.highlightMatching(query, results || []);
|
||||
const items = this.renderResults(query, results || []);
|
||||
const expanded = !!items && !!items.length;
|
||||
return React.createElement(
|
||||
Modal,
|
||||
|
|
@ -487,7 +491,7 @@ export class QuickOpenModal extends Component {
|
|||
items,
|
||||
selected: selectedIndex,
|
||||
selectItem: this.selectResultItem,
|
||||
ref: "resultList",
|
||||
ref: this.resultListRef,
|
||||
expanded,
|
||||
...(this.isSourceSearch() ? SIZE_BIG : SIZE_DEFAULT),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -115,6 +115,9 @@ skip-if = [
|
|||
["browser_dbg-call-stack.js"]
|
||||
|
||||
["browser_dbg-chrome-create.js"]
|
||||
skip-if = [
|
||||
"os == 'linux' && os_version == '18.04' && processor == 'x86_64' && asan", # Bug 2030884
|
||||
]
|
||||
|
||||
["browser_dbg-console-async.js"]
|
||||
|
||||
|
|
@ -286,6 +289,7 @@ skip-if = [
|
|||
["browser_dbg-javascript-tracer-values-preview.js"]
|
||||
skip-if = [
|
||||
"os == 'linux' && os_version == '18.04' && processor == 'x86_64' && opt && a11y_checks", # Bug The tracer tree isn't yet accessible
|
||||
"os == 'linux' && os_version == '18.04' && processor == 'x86_64' && tsan", # Bug 1959018, Bug 2030884
|
||||
"os == 'linux' && os_version == '24.04' && processor == 'x86_64' && display == 'x11' && opt && a11y_checks", # Bug The tracer tree isn't yet accessible
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -94,6 +94,18 @@ add_task(async function () {
|
|||
pressKey(dbg, "Escape");
|
||||
assertQuickOpenDisabled(dbg);
|
||||
|
||||
info("Test that the highlighted result matches match the query");
|
||||
await quickOpen(dbg, "sw");
|
||||
await waitForResults(dbg, [
|
||||
"script-switching-01.js",
|
||||
"script-switching-02.js",
|
||||
]);
|
||||
await assertHighlightMatches(dbg, 1, "sw");
|
||||
await assertHighlightMatches(dbg, 2, "sw");
|
||||
EventUtils.sendString("i");
|
||||
await assertHighlightMatches(dbg, 1, "swi");
|
||||
pressKey(dbg, "Escape");
|
||||
|
||||
info("Testing goto line:column");
|
||||
assertLine(dbg, 0);
|
||||
assertColumn(dbg, 1);
|
||||
|
|
@ -170,3 +182,19 @@ async function assertResultIsTab(dbg, index) {
|
|||
"Result should be a tab"
|
||||
);
|
||||
}
|
||||
|
||||
async function assertHighlightMatches(dbg, resultIndex, expectedMatchText) {
|
||||
// Sanitizer API not supported in ESR 140
|
||||
// Should remove at ESR 153
|
||||
if ("Sanitizer" in dbg.win) {
|
||||
const el = await findResultEl(dbg, resultIndex);
|
||||
const highlight = await waitForElementWithSelector(dbg, "mark.highlight");
|
||||
ok(el && !!highlight, "The query match is highlighted");
|
||||
await waitUntil(
|
||||
() => el.querySelector("mark.highlight").innerText == expectedMatchText
|
||||
);
|
||||
ok(true, "The highlighted text matches the query text");
|
||||
} else {
|
||||
ok(true, "The text is not highlighted");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,6 +112,12 @@ skip-if = [
|
|||
["browser_tab_commands_factory.js"]
|
||||
|
||||
["browser_tab_descriptor_fission.js"]
|
||||
skip-if = [
|
||||
"os == 'linux' && processor == 'x86_64' && asan", # Bug 1966872, Bug 2030884
|
||||
"os == 'linux' && processor == 'x86_64' && tsan", # Bug 1966872, Bug 2030884
|
||||
"os == 'win' && os_version == '11.26100' && processor == 'x86_64' && asan", # Bug 1966872, Bug 2030884
|
||||
"os == 'win' && os_version == '11.26200' && processor == 'x86_64' && asan", # Bug 1966872, Bug 2030884
|
||||
]
|
||||
|
||||
["browser_target_cached-front.js"]
|
||||
|
||||
|
|
@ -291,6 +297,9 @@ fail-if = ["a11y_checks"] # Bug 1849028 clicked element may not be focusable and
|
|||
["browser_toolbox_watchedByDevTools.js"]
|
||||
|
||||
["browser_toolbox_window_global_debugging.js"]
|
||||
skip-if = [
|
||||
"os == 'linux' && processor == 'x86_64' && tsan", # Bug 1950845, Bug 2030884
|
||||
]
|
||||
|
||||
["browser_toolbox_window_reload_target.js"]
|
||||
|
||||
|
|
|
|||
|
|
@ -150,8 +150,11 @@ fail-if = ["a11y_checks"] # Bug 1849028 clicked element may not be focusable and
|
|||
|
||||
["browser_animation_logic_mutations_fast.js"]
|
||||
skip-if = [
|
||||
"os == 'linux' && os_version == '18.04' && processor == 'x86_64' && debug", # Bug 1567800
|
||||
"os == 'linux' && os_version == '24.04' && processor == 'x86_64' && display == 'x11' && debug", # Bug 1567800
|
||||
"os == 'linux' && processor == 'x86_64' && asan", # Bug 1980142, Bug 2030884
|
||||
"os == 'linux' && processor == 'x86_64' && debug", # Bug 1567800, Bug 2030884
|
||||
"os == 'linux' && processor == 'x86_64' && tsan", # Bug 1980142, Bug 2030884
|
||||
"os == 'win' && os_version == '11.26100' && processor == 'x86_64' && debug", # Bug 1980142, Bug 2030884
|
||||
"os == 'win' && os_version == '11.26200' && processor == 'x86_64' && debug", # Bug 1980142, Bug 2030884
|
||||
]
|
||||
|
||||
["browser_animation_logic_mutations_properties.js"]
|
||||
|
|
|
|||
|
|
@ -587,7 +587,9 @@ support-files = ["browser_webconsole_object_inspector_entries.snapshot.mjs"]
|
|||
https_first_disabled = true # JS HttpServer doesn't support https
|
||||
skip-if = [
|
||||
"http3", # JS HttpServer doesn't support http3
|
||||
"os == 'linux' && os_version == '18.04' && processor == 'x86_64' && opt", # Bug 1965340, Bug 2030884
|
||||
"os == 'linux' && os_version == '24.04' && processor == 'x86_64' && display == 'x11' && opt", # Bug 1965340
|
||||
"os == 'mac' && os_version == '14.70' && processor == 'x86_64'", # Bug 1965340, Bug 2030884
|
||||
]
|
||||
|
||||
["browser_webconsole_object_inspector_getters.js"]
|
||||
|
|
|
|||
|
|
@ -179,17 +179,17 @@ function getCleanedPacket(key, packet) {
|
|||
res.startedDateTime = existingPacket.startedDateTime;
|
||||
}
|
||||
|
||||
if (res.totalTime && existingPacket.totalTime) {
|
||||
res.totalTime = existingPacket.totalTime;
|
||||
}
|
||||
|
||||
if (res.securityState && existingPacket.securityState) {
|
||||
res.securityState = existingPacket.securityState;
|
||||
}
|
||||
|
||||
// waitingTime can be very small and rounded to 0. However this is still a
|
||||
// valid waiting time, so check isNaN instead of a simple truthy check.
|
||||
if (!isNaN(res.waitingTime) && existingPacket.waitingTime) {
|
||||
// totalTime and waitingTime can be very small and rounded to 0. However this
|
||||
// is still a valid time value, so check isNaN instead of a simple truthy check.
|
||||
if (!isNaN(res.totalTime) && !isNaN(existingPacket.totalTime)) {
|
||||
res.totalTime = existingPacket.totalTime;
|
||||
}
|
||||
|
||||
if (!isNaN(res.waitingTime) && !isNaN(existingPacket.waitingTime)) {
|
||||
res.waitingTime = existingPacket.waitingTime;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1937,6 +1937,19 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(BrowsingContext)
|
|||
return IsCertainlyAliveForCC(tmp);
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
|
||||
|
||||
/* static */
|
||||
void BrowsingContext::SweepWindowProxies(JSTracer* aTrc) {
|
||||
if (!sBrowsingContexts) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (BrowsingContext* bc : sBrowsingContexts->Values()) {
|
||||
if (bc->mWindowProxy) {
|
||||
JS_UpdateWeakPointerAfterGC(aTrc, &bc->mWindowProxy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RemoteLocationProxy
|
||||
: public RemoteObjectProxy<BrowsingContext::LocationProxy,
|
||||
Location_Binding::sCrossOriginProperties> {
|
||||
|
|
|
|||
|
|
@ -734,6 +734,9 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
|||
mWindowProxy = aWindowProxy;
|
||||
}
|
||||
|
||||
// Since mWindowProxy is a weak pointer it has to be updated during sweeping.
|
||||
static void SweepWindowProxies(JSTracer* aTrc);
|
||||
|
||||
Nullable<WindowProxyHolder> GetWindow();
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
|
|
@ -1378,10 +1381,8 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
|||
|
||||
RefPtr<nsGeolocationService> mGeolocationServiceOverride;
|
||||
|
||||
// This is not a strong reference, but using a JS::Heap for that should be
|
||||
// fine. The JSObject stored in here should be a proxy with a
|
||||
// nsOuterWindowProxy handler, which will update the pointer from its
|
||||
// objectMoved hook and clear it from its finalize hook.
|
||||
// This is a weak reference. It will be updated automatically during sweeping
|
||||
// by SweepWindowProxies.
|
||||
JS::Heap<JSObject*> mWindowProxy;
|
||||
LocationProxy mLocation;
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,11 @@ void AbortSignalImpl::GetReason(JSContext* aCx,
|
|||
}
|
||||
MaybeAssignAbortError(aCx);
|
||||
aReason.set(mReason);
|
||||
if (NS_WARN_IF(!JS_WrapValue(aCx, aReason))) {
|
||||
aReason.setUndefined();
|
||||
// TODO(Bug 2026137) - AbortSignalImpl::GetReason should be made fallible
|
||||
JS_ClearPendingException(aCx);
|
||||
}
|
||||
}
|
||||
|
||||
JS::Value AbortSignalImpl::RawReason() const { return mReason.get(); }
|
||||
|
|
@ -75,7 +80,7 @@ void AbortSignalImpl::RunAbortSteps() {
|
|||
// https://dom.spec.whatwg.org/#abortsignal-remove could be invoked in an
|
||||
// earlier algorithm to remove a later algorithm, so |mFollowers| must be a
|
||||
// |nsTObserverArray| to defend against mutation.
|
||||
for (RefPtr<AbortFollower>& follower : mFollowers.ForwardRange()) {
|
||||
for (RefPtr<AbortFollower> follower : mFollowers.ForwardRange()) {
|
||||
MOZ_ASSERT(follower->mFollowingSignal == this);
|
||||
follower->RunAbortAlgorithm();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -386,11 +386,9 @@ void Animation::SetStartTime(const Nullable<TimeDuration>& aNewStartTime) {
|
|||
}
|
||||
|
||||
CancelPendingTasks();
|
||||
if (mReady) {
|
||||
// We may have already resolved mReady, but in that case calling
|
||||
// MaybeResolve is a no-op, so that's okay.
|
||||
mReady->MaybeResolve(this);
|
||||
}
|
||||
// We may have already resolved mReady, but in that case calling
|
||||
// MaybeResolve is a no-op, so that's okay.
|
||||
MaybeResolvePromiseWithThis(mReady);
|
||||
|
||||
UpdateTiming(SeekFlag::DidSeek, SyncNotifyFlag::Async);
|
||||
if (IsRelevant()) {
|
||||
|
|
@ -449,9 +447,7 @@ void Animation::SetCurrentTimeNoUpdate(const TimeDuration& aSeekTime) {
|
|||
ApplyPendingPlaybackRate();
|
||||
mStartTime.SetNull();
|
||||
|
||||
if (mReady) {
|
||||
mReady->MaybeResolve(this);
|
||||
}
|
||||
MaybeResolvePromiseWithThis(mReady);
|
||||
CancelPendingTasks();
|
||||
}
|
||||
|
||||
|
|
@ -608,11 +604,25 @@ Promise* Animation::GetReady(ErrorResult& aRv) {
|
|||
return nullptr;
|
||||
}
|
||||
if (!Pending()) {
|
||||
mReady->MaybeResolve(this);
|
||||
MaybeResolvePromiseWithThis(mReady);
|
||||
}
|
||||
return mReady;
|
||||
}
|
||||
|
||||
void Animation::MaybeResolvePromiseWithThis(Promise* aPromise) {
|
||||
if (!aPromise) {
|
||||
return;
|
||||
}
|
||||
if (!nsContentUtils::IsSafeToRunScript()) {
|
||||
nsContentUtils::AddScriptRunner(NewRunnableMethod<RefPtr<Promise>>(
|
||||
"MaybeResolvePromiseWithThis", this,
|
||||
&Animation::MaybeResolvePromiseWithThis, aPromise));
|
||||
return;
|
||||
}
|
||||
RefPtr promise = aPromise;
|
||||
promise->MaybeResolve(this);
|
||||
}
|
||||
|
||||
Promise* Animation::GetFinished(ErrorResult& aRv) {
|
||||
nsCOMPtr<nsIGlobalObject> global = GetOwnerGlobal();
|
||||
if (!mFinished && global) {
|
||||
|
|
@ -714,9 +724,7 @@ void Animation::Finish(ErrorResult& aRv) {
|
|||
}
|
||||
CancelPendingTasks();
|
||||
didChange = true;
|
||||
if (mReady) {
|
||||
mReady->MaybeResolve(this);
|
||||
}
|
||||
MaybeResolvePromiseWithThis(mReady);
|
||||
}
|
||||
UpdateTiming(SeekFlag::DidSeek, SyncNotifyFlag::Sync);
|
||||
if (didChange && IsRelevant()) {
|
||||
|
|
@ -1607,9 +1615,7 @@ void Animation::ResumeAt(const TimeDuration& aReadyTime) {
|
|||
MutationObservers::NotifyAnimationChanged(this);
|
||||
}
|
||||
|
||||
if (mReady) {
|
||||
mReady->MaybeResolve(this);
|
||||
}
|
||||
MaybeResolvePromiseWithThis(mReady);
|
||||
}
|
||||
|
||||
void Animation::PauseAt(const TimeDuration& aReadyTime) {
|
||||
|
|
@ -1626,9 +1632,7 @@ void Animation::PauseAt(const TimeDuration& aReadyTime) {
|
|||
|
||||
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
|
||||
|
||||
if (mReady) {
|
||||
mReady->MaybeResolve(this);
|
||||
}
|
||||
MaybeResolvePromiseWithThis(mReady);
|
||||
}
|
||||
|
||||
void Animation::UpdateTiming(SeekFlag aSeekFlag,
|
||||
|
|
@ -1877,10 +1881,8 @@ void Animation::ResetFinishedPromise() {
|
|||
}
|
||||
|
||||
void Animation::MaybeResolveFinishedPromise() {
|
||||
if (mFinished) {
|
||||
mFinished->MaybeResolve(this);
|
||||
}
|
||||
mFinishedIsResolved = true;
|
||||
MaybeResolvePromiseWithThis(mFinished);
|
||||
}
|
||||
|
||||
void Animation::DoFinishNotificationImmediately(MicroTaskRunnable* aAsync) {
|
||||
|
|
|
|||
|
|
@ -466,6 +466,7 @@ class Animation : public DOMEventTargetHelper,
|
|||
friend class AsyncFinishNotification;
|
||||
void DoFinishNotificationImmediately(MicroTaskRunnable* aAsync = nullptr);
|
||||
void QueuePlaybackEvent(nsAtom* aOnEvent, TimeStamp&& aScheduledEventTime);
|
||||
void MaybeResolvePromiseWithThis(Promise*);
|
||||
|
||||
/**
|
||||
* Remove this animation from the pending animation tracker and reset
|
||||
|
|
|
|||
|
|
@ -10664,23 +10664,25 @@ void nsDOMAttributeMap::BlastSubtreeToPieces(nsINode* aNode) {
|
|||
|
||||
mozilla::DebugOnly<nsresult> rv =
|
||||
element->UnsetAttr(attr->NodeInfo()->NamespaceID(),
|
||||
attr->NodeInfo()->NameAtom(), false);
|
||||
attr->NodeInfo()->NameAtom(), true);
|
||||
|
||||
// XXX Should we abort here?
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Uh-oh, UnsetAttr shouldn't fail!");
|
||||
}
|
||||
}
|
||||
|
||||
if (mozilla::dom::ShadowRoot* shadow = element->GetShadowRoot()) {
|
||||
// Hold the strong reference to be sure, since we may notify
|
||||
if (RefPtr<mozilla::dom::ShadowRoot> shadow = element->GetShadowRoot()) {
|
||||
BlastSubtreeToPieces(shadow);
|
||||
element->UnattachShadow();
|
||||
}
|
||||
}
|
||||
|
||||
while (aNode->HasChildren()) {
|
||||
nsIContent* node = aNode->GetFirstChild();
|
||||
// Hold the strong reference to be sure, since we are notifying.
|
||||
nsCOMPtr<nsIContent> node = aNode->GetFirstChild();
|
||||
BlastSubtreeToPieces(node);
|
||||
aNode->RemoveChildNode(node, false);
|
||||
aNode->RemoveChildNode(node, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -16275,11 +16277,16 @@ void Document::RequestFullscreenInParentProcess(
|
|||
|
||||
/* static */
|
||||
bool Document::HandlePendingFullscreenRequests(Document* aDoc) {
|
||||
AutoTArray<UniquePtr<FullscreenRequest>, 1> requests;
|
||||
{
|
||||
PendingFullscreenChangeList::Iterator<FullscreenRequest> iter(
|
||||
aDoc, PendingFullscreenChangeList::eDocumentsWithSameRoot);
|
||||
while (!iter.AtEnd()) {
|
||||
requests.AppendElement(iter.TakeAndNext());
|
||||
}
|
||||
}
|
||||
bool handled = false;
|
||||
PendingFullscreenChangeList::Iterator<FullscreenRequest> iter(
|
||||
aDoc, PendingFullscreenChangeList::eDocumentsWithSameRoot);
|
||||
while (!iter.AtEnd()) {
|
||||
UniquePtr<FullscreenRequest> request = iter.TakeAndNext();
|
||||
for (UniquePtr<FullscreenRequest>& request : requests) {
|
||||
Document* doc = request->Document();
|
||||
if (doc->ApplyFullscreen(std::move(request))) {
|
||||
handled = true;
|
||||
|
|
|
|||
|
|
@ -5732,7 +5732,7 @@ class MOZ_RAII IgnoreOpensDuringUnload final {
|
|||
}
|
||||
|
||||
private:
|
||||
Document* mDoc;
|
||||
RefPtr<Document> mDoc;
|
||||
};
|
||||
|
||||
bool IsInFocusedTab(Document* aDoc);
|
||||
|
|
|
|||
|
|
@ -279,8 +279,9 @@ nsIFrame* nsIContent::GetPrimaryFrame(mozilla::FlushType aType) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<mozilla::PresShell> presShell = frame->PresShell();
|
||||
if (aType == mozilla::FlushType::Layout) {
|
||||
frame->PresShell()->EnsureReflowIfFrameHasHiddenContent(frame);
|
||||
presShell->EnsureReflowIfFrameHasHiddenContent(frame);
|
||||
frame = GetPrimaryFrame();
|
||||
}
|
||||
|
||||
|
|
@ -2807,6 +2808,7 @@ bool Element::OnlyNotifySameValueSet(int32_t aNamespaceID, nsAtom* aName,
|
|||
}
|
||||
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
OnAttrSetButNotChanged(aNamespaceID, aName, aValue, aNotify);
|
||||
MutationObservers::NotifyAttributeSetToCurrentValue(this, aNamespaceID,
|
||||
aName);
|
||||
return true;
|
||||
|
|
@ -2856,7 +2858,6 @@ nsresult Element::SetAttr(int32_t aNamespaceID, nsAtom* aName, nsAtom* aPrefix,
|
|||
if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
|
||||
oldValue, &modType, &hasListeners,
|
||||
&oldValueSet)) {
|
||||
OnAttrSetButNotChanged(aNamespaceID, aName, value, aNotify);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
|
@ -2906,7 +2907,6 @@ nsresult Element::SetParsedAttr(int32_t aNamespaceID, nsAtom* aName,
|
|||
if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
|
||||
oldValue, &modType, &hasListeners,
|
||||
&oldValueSet)) {
|
||||
OnAttrSetButNotChanged(aNamespaceID, aName, value, aNotify);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -341,8 +341,8 @@ nsresult ImageEncoder::ExtractDataInternal(
|
|||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
auto size = data->GetSize();
|
||||
rv = aEncoder->InitFromData(map.mData, size.width * size.height * 4,
|
||||
size.width, size.height, size.width * 4,
|
||||
rv = aEncoder->InitFromData(map.mData, map.mStride * size.height,
|
||||
size.width, size.height, map.mStride,
|
||||
imgIEncoder::INPUT_FORMAT_HOSTARGB, aOptions);
|
||||
data->Unmap();
|
||||
}
|
||||
|
|
@ -374,8 +374,8 @@ nsresult ImageEncoder::ExtractDataInternal(
|
|||
}
|
||||
|
||||
rv = aEncoder->InitFromData(data.Elements(),
|
||||
aSize.width * aSize.height * 4, aSize.width,
|
||||
aSize.height, aSize.width * 4,
|
||||
length, aSize.width,
|
||||
aSize.height, stride,
|
||||
imgIEncoder::INPUT_FORMAT_HOSTARGB, aOptions);
|
||||
} else {
|
||||
if (BufferSizeFromDimensions(aSize.width, aSize.height, 4) == 0) {
|
||||
|
|
@ -391,8 +391,8 @@ nsresult ImageEncoder::ExtractDataInternal(
|
|||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
auto size = dataSurface->GetSize();
|
||||
rv = aEncoder->InitFromData(map.mData, size.width * size.height * 4,
|
||||
size.width, size.height, size.width * 4,
|
||||
rv = aEncoder->InitFromData(map.mData, map.mStride * size.height,
|
||||
size.width, size.height, map.mStride,
|
||||
imgIEncoder::INPUT_FORMAT_HOSTARGB, aOptions);
|
||||
dataSurface->Unmap();
|
||||
}
|
||||
|
|
@ -421,13 +421,13 @@ nsresult ImageEncoder::ExtractDataInternal(
|
|||
if (!emptyCanvas->Map(DataSourceSurface::MapType::WRITE, &map)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
auto size = map.mStride * aSize.height;
|
||||
if (aUsePlaceholder) {
|
||||
auto size = 4 * aSize.width * aSize.height;
|
||||
auto* data = map.mData;
|
||||
GeneratePlaceholderCanvasData(size, data);
|
||||
}
|
||||
rv = aEncoder->InitFromData(map.mData, aSize.width * aSize.height * 4,
|
||||
aSize.width, aSize.height, aSize.width * 4,
|
||||
rv = aEncoder->InitFromData(map.mData, size, aSize.width, aSize.height,
|
||||
map.mStride,
|
||||
imgIEncoder::INPUT_FORMAT_HOSTARGB, aOptions);
|
||||
emptyCanvas->Unmap();
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
|
|
|||
|
|
@ -70,15 +70,24 @@ ScreenOrientation::ScreenOrientation(nsPIDOMWindowInner* aWindow,
|
|||
: DOMEventTargetHelper(aWindow), mScreen(aScreen) {
|
||||
MOZ_ASSERT(aWindow);
|
||||
MOZ_ASSERT(aScreen);
|
||||
}
|
||||
|
||||
mAngle = aScreen->GetOrientationAngle();
|
||||
mType = InternalOrientationToType(aScreen->GetOrientationType());
|
||||
/* static */ already_AddRefed<ScreenOrientation> ScreenOrientation::Create(
|
||||
nsPIDOMWindowInner* aWindow, nsScreen* aScreen) {
|
||||
RefPtr screenOrientation = new ScreenOrientation(aWindow, aScreen);
|
||||
|
||||
Document* doc = GetResponsibleDocument();
|
||||
screenOrientation->mAngle = aScreen->GetOrientationAngle();
|
||||
screenOrientation->mType =
|
||||
InternalOrientationToType(aScreen->GetOrientationType());
|
||||
|
||||
Document* doc = screenOrientation->GetResponsibleDocument();
|
||||
BrowsingContext* bc = doc ? doc->GetBrowsingContext() : nullptr;
|
||||
if (bc && !bc->IsDiscarded() && !bc->InRDMPane()) {
|
||||
MOZ_ALWAYS_SUCCEEDS(bc->SetCurrentOrientation(mType, mAngle));
|
||||
MOZ_ALWAYS_SUCCEEDS(bc->SetCurrentOrientation(screenOrientation->mType,
|
||||
screenOrientation->mAngle));
|
||||
}
|
||||
|
||||
return screenOrientation.forget();
|
||||
}
|
||||
|
||||
ScreenOrientation::~ScreenOrientation() {
|
||||
|
|
|
|||
|
|
@ -33,8 +33,13 @@ class ScreenOrientation final : public DOMEventTargetHelper {
|
|||
// Called when the orientation may have changed.
|
||||
void MaybeChanged();
|
||||
|
||||
private:
|
||||
ScreenOrientation(nsPIDOMWindowInner* aWindow, nsScreen* aScreen);
|
||||
|
||||
public:
|
||||
static already_AddRefed<ScreenOrientation> Create(nsPIDOMWindowInner* aWindow,
|
||||
nsScreen* aScreen);
|
||||
|
||||
already_AddRefed<Promise> Lock(OrientationLockType aOrientation,
|
||||
ErrorResult& aRv);
|
||||
|
||||
|
|
@ -107,8 +112,8 @@ class ScreenOrientation final : public DOMEventTargetHelper {
|
|||
RefPtr<nsScreen> mScreen;
|
||||
RefPtr<FullscreenEventListener> mFullscreenListener;
|
||||
RefPtr<VisibleEventListener> mVisibleListener;
|
||||
OrientationType mType;
|
||||
uint16_t mAngle;
|
||||
OrientationType mType{};
|
||||
uint16_t mAngle{};
|
||||
// Whether we've tried to call into hal to lock the device orientation. This
|
||||
// is needed because you don't want calling UnlockDeviceOrientation() during
|
||||
// shutdown to initialize PHal if it hasn't been initialized earlier. Also,
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ void ShadowRoot::Unattach() {
|
|||
|
||||
void ShadowRoot::InvalidateStyleAndLayoutOnSubtree(Element* aElement) {
|
||||
MOZ_ASSERT(aElement);
|
||||
Document* doc = GetComposedDoc();
|
||||
Document* doc = aElement->GetComposedDoc();
|
||||
if (!doc) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ class ShadowRoot final : public DocumentFragment, public DocumentOrShadowRoot {
|
|||
* It is important that this runs _before_ actually shuffling the flat tree
|
||||
* around, so that layout knows the actual tree that it needs to invalidate.
|
||||
*/
|
||||
void InvalidateStyleAndLayoutOnSubtree(Element*);
|
||||
static void InvalidateStyleAndLayoutOnSubtree(Element*);
|
||||
|
||||
private:
|
||||
void InsertSheetIntoAuthorData(size_t aIndex, StyleSheet&,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include "js/Wrapper.h"
|
||||
#include "jsapi.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Span.h"
|
||||
|
|
@ -214,8 +215,13 @@ bool StructuredCloneBlob::WriteStructuredClone(JSContext* aCx,
|
|||
bool StructuredCloneBlob::Holder::WriteStructuredClone(
|
||||
JSContext* aCx, JSStructuredCloneWriter* aWriter,
|
||||
StructuredCloneHolder* aHolder) {
|
||||
auto& data = mBuffer->data();
|
||||
if (!JS_WriteUint32Pair(aWriter, data.Size(), JS_STRUCTURED_CLONE_VERSION) ||
|
||||
const auto& data = mBuffer->data();
|
||||
CheckedUint32 dataSize(data.Size());
|
||||
if (!dataSize.isValid()) {
|
||||
return false;
|
||||
}
|
||||
if (!JS_WriteUint32Pair(aWriter, dataSize.value(),
|
||||
JS_STRUCTURED_CLONE_VERSION) ||
|
||||
!JS_WriteUint32Pair(aWriter, aHolder->BlobImpls().Length(),
|
||||
BlobImpls().Length())) {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -938,9 +938,8 @@ TextInputProcessor::NotifyIME(TextEventDispatcher* aTextEventDispatcher,
|
|||
NS_IMETHODIMP_(IMENotificationRequests)
|
||||
TextInputProcessor::GetIMENotificationRequests() {
|
||||
// TextInputProcessor should support all change notifications.
|
||||
return IMENotificationRequests(
|
||||
IMENotificationRequests::NOTIFY_TEXT_CHANGE |
|
||||
IMENotificationRequests::NOTIFY_POSITION_CHANGE);
|
||||
return {IMENotificationRequest::TextChange,
|
||||
IMENotificationRequest::PositionChange};
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
|
|
|
|||
|
|
@ -27,9 +27,10 @@ class KeyboardEvent;
|
|||
|
||||
class TextInputProcessor final : public nsITextInputProcessor,
|
||||
public widget::TextEventDispatcherListener {
|
||||
typedef mozilla::widget::IMENotification IMENotification;
|
||||
typedef mozilla::widget::IMENotificationRequests IMENotificationRequests;
|
||||
typedef mozilla::widget::TextEventDispatcher TextEventDispatcher;
|
||||
using IMENotification = mozilla::widget::IMENotification;
|
||||
using IMENotificationRequest = mozilla::widget::IMENotificationRequest;
|
||||
using IMENotificationRequests = mozilla::widget::IMENotificationRequests;
|
||||
using TextEventDispatcher = mozilla::widget::TextEventDispatcher;
|
||||
|
||||
public:
|
||||
TextInputProcessor();
|
||||
|
|
|
|||
|
|
@ -1333,7 +1333,11 @@ void nsAttrValue::ParseAtom(const nsAString& aValue) {
|
|||
void nsAttrValue::ParseAtomArray(nsAtom* aValue) {
|
||||
if (MiscContainer* cont = AtomArrayCache::Lookup(aValue)) {
|
||||
// Set our MiscContainer to the cached one.
|
||||
// AddRef must happen before ResetIfSet: the cache does not hold a strong
|
||||
// reference, and ResetIfSet could release the last reference to cont if
|
||||
// this nsAttrValue is already holding it.
|
||||
NS_ADDREF(cont);
|
||||
ResetIfSet();
|
||||
SetPtrValueAndType(cont, eOtherBase);
|
||||
return;
|
||||
}
|
||||
|
|
@ -1933,7 +1937,11 @@ bool nsAttrValue::ParseStyleAttribute(const nsAString& aString,
|
|||
if (cachingAllowed) {
|
||||
if (MiscContainer* cont = attrStyles->LookupStyleAttr(aString)) {
|
||||
// Set our MiscContainer to the cached one.
|
||||
// AddRef must happen before ResetIfSet: the cache does not hold a strong
|
||||
// reference, and ResetIfSet could release the last reference to cont if
|
||||
// this nsAttrValue is already holding it.
|
||||
NS_ADDREF(cont);
|
||||
ResetIfSet();
|
||||
SetPtrValueAndType(cont, eOtherBase);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -592,7 +592,8 @@ Element* nsContentList::NamedItem(const nsAString& aName, bool aDoFlush) {
|
|||
return mNamedItemsCache->Get(name);
|
||||
}
|
||||
|
||||
void nsContentList::GetSupportedNames(nsTArray<nsString>& aNames) {
|
||||
void nsContentList::GetSupportedNames(nsTArray<nsString>& aNames,
|
||||
FilterElementWithName aFilter) {
|
||||
BringSelfUpToDate(true);
|
||||
|
||||
AutoTArray<nsAtom*, 8> atoms;
|
||||
|
|
@ -606,14 +607,14 @@ void nsContentList::GetSupportedNames(nsTArray<nsString>& aNames) {
|
|||
}
|
||||
}
|
||||
|
||||
nsGenericHTMLElement* el = nsGenericHTMLElement::FromNode(content);
|
||||
if (el) {
|
||||
if (nsGenericHTMLElement* el = nsGenericHTMLElement::FromNode(content)) {
|
||||
// XXXbz should we be checking for particular tags here? How
|
||||
// stable is this part of the spec?
|
||||
// Note: nsINode::HasName means the name is exposed on the document,
|
||||
// which is false for options, so we don't check it here.
|
||||
const nsAttrValue* val = el->GetParsedAttr(nsGkAtoms::name);
|
||||
if (val && val->Type() == nsAttrValue::eAtom) {
|
||||
if (val && val->Type() == nsAttrValue::eAtom &&
|
||||
(!aFilter || aFilter(el))) {
|
||||
nsAtom* name = val->GetAtomValue();
|
||||
MOZ_ASSERT(name != nsGkAtoms::_empty, "Empty names don't get atomized");
|
||||
if (!atoms.Contains(name)) {
|
||||
|
|
|
|||
|
|
@ -296,13 +296,21 @@ class nsContentList : public nsBaseContentList,
|
|||
aFound = !!item;
|
||||
return item;
|
||||
}
|
||||
void GetSupportedNames(nsTArray<nsString>& aNames) override;
|
||||
void GetSupportedNames(nsTArray<nsString>& aNames) override {
|
||||
GetSupportedNames(aNames, nullptr);
|
||||
}
|
||||
|
||||
// nsContentList public methods
|
||||
uint32_t Length(bool aDoFlush);
|
||||
nsIContent* Item(uint32_t aIndex, bool aDoFlush);
|
||||
Element* NamedItem(const nsAString& aName, bool aDoFlush);
|
||||
|
||||
// Used by HTMLAllCollection to limit the elements whose name attribute is
|
||||
// considered. The filter MUST NOT cause any flushes.
|
||||
using FilterElementWithName = bool (*)(nsIContent*);
|
||||
void GetSupportedNames(nsTArray<nsString>& aNames,
|
||||
FilterElementWithName aFilter);
|
||||
|
||||
// nsIMutationObserver
|
||||
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
||||
|
|
|
|||
|
|
@ -4533,10 +4533,9 @@ nsDOMWindowUtils::WrCapture() {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::WrStartCaptureSequence(const nsACString& aPath,
|
||||
uint32_t aFlags) {
|
||||
nsDOMWindowUtils::WrStartCaptureSequence(uint32_t aFlags) {
|
||||
if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) {
|
||||
wrbc->StartCaptureSequence(nsCString(aPath), aFlags);
|
||||
wrbc->StartCaptureSequence(aFlags);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ void nsFrameLoaderOwner::ChangeRemotenessCommon(
|
|||
// no other blockers. Since we're going to be adding a new blocker as soon as
|
||||
// we recreate the frame loader, this is not what we want, so add our own
|
||||
// blocker until the process is complete.
|
||||
Document* doc = owner->OwnerDoc();
|
||||
RefPtr<Document> doc = owner->OwnerDoc();
|
||||
doc->BlockOnload();
|
||||
auto cleanup = MakeScopeExit([&]() { doc->UnblockOnload(false); });
|
||||
|
||||
|
|
|
|||
|
|
@ -2459,7 +2459,7 @@ VisualViewport* nsGlobalWindowInner::VisualViewport() {
|
|||
|
||||
nsScreen* nsGlobalWindowInner::Screen() {
|
||||
if (!mScreen) {
|
||||
mScreen = new nsScreen(this);
|
||||
mScreen = nsScreen::Create(this);
|
||||
}
|
||||
return mScreen;
|
||||
}
|
||||
|
|
@ -2535,6 +2535,10 @@ Maybe<ServiceWorkerDescriptor> nsPIDOMWindowInner::GetController() const {
|
|||
return nsGlobalWindowInner::Cast(this)->GetController();
|
||||
}
|
||||
|
||||
ClientSource* nsPIDOMWindowInner::GetClientSource() const {
|
||||
return nsGlobalWindowInner::Cast(this)->GetClientSource();
|
||||
}
|
||||
|
||||
void nsPIDOMWindowInner::SetCsp(nsIContentSecurityPolicy* aCsp) {
|
||||
return nsGlobalWindowInner::Cast(this)->SetCsp(aCsp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1286,6 +1286,10 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
|
|||
void SetCurrentPasteDataTransfer(mozilla::dom::DataTransfer* aDataTransfer);
|
||||
mozilla::dom::DataTransfer* GetCurrentPasteDataTransfer() const;
|
||||
|
||||
mozilla::dom::ClientSource* GetClientSource() const {
|
||||
return mClientSource.get();
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<mozilla::dom::ContentMediaController> mContentMediaController;
|
||||
|
||||
|
|
|
|||
|
|
@ -1105,11 +1105,7 @@ void nsINode::Normalize() {
|
|||
const nsTextFragment* text = node->GetText();
|
||||
if (text->GetLength()) {
|
||||
nsIContent* target = node->GetPreviousSibling();
|
||||
NS_ASSERTION(
|
||||
(target && target->NodeType() == TEXT_NODE) || hasRemoveListeners,
|
||||
"Should always have a previous text sibling unless "
|
||||
"mutation events messed us up");
|
||||
if (!hasRemoveListeners || (target && target->NodeType() == TEXT_NODE)) {
|
||||
if (target && target->NodeType() == TEXT_NODE) {
|
||||
nsTextNode* t = static_cast<nsTextNode*>(target);
|
||||
if (text->Is2b()) {
|
||||
t->AppendTextForNormalize(text->Get2b(), text->GetLength(), true,
|
||||
|
|
@ -3721,8 +3717,10 @@ already_AddRefed<nsINode> nsINode::CloneAndAdopt(
|
|||
JSAutoRealm ar(cx, wrapper);
|
||||
UpdateReflectorGlobal(cx, wrapper, aError);
|
||||
if (aError.Failed()) {
|
||||
bool needsRollBack = false;
|
||||
if (wasRegistered) {
|
||||
newDoc->UnregisterActivityObserver(aNode->AsElement());
|
||||
needsRollBack =
|
||||
newDoc->UnregisterActivityObserver(aNode->AsElement());
|
||||
}
|
||||
if (hadProperties) {
|
||||
// NOTE: When it fails it removes all properties for the node
|
||||
|
|
@ -3732,7 +3730,7 @@ already_AddRefed<nsINode> nsINode::CloneAndAdopt(
|
|||
}
|
||||
aNode->mNodeInfo.swap(newNodeInfo);
|
||||
aNode->NodeInfoChanged(newDoc);
|
||||
if (wasRegistered) {
|
||||
if (needsRollBack) {
|
||||
oldDoc->RegisterActivityObserver(aNode->AsElement());
|
||||
}
|
||||
return nullptr;
|
||||
|
|
|
|||
|
|
@ -214,8 +214,8 @@ already_AddRefed<nsIDocShell> nsObjectLoadingContent::SetupDocShell(
|
|||
}
|
||||
|
||||
if (!docShell) {
|
||||
mFrameLoader->Destroy();
|
||||
mFrameLoader = nullptr;
|
||||
RefPtr<nsFrameLoader> loader = std::move(mFrameLoader);
|
||||
loader->Destroy();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -1284,8 +1284,8 @@ nsresult nsObjectLoadingContent::LoadObject(bool aNotify, bool aForceLoad,
|
|||
nsCOMPtr<nsIURILoader> uriLoader(components::URILoader::Service());
|
||||
if (NS_WARN_IF(!uriLoader)) {
|
||||
MOZ_ASSERT_UNREACHABLE("Failed to get uriLoader service");
|
||||
mFrameLoader->Destroy();
|
||||
mFrameLoader = nullptr;
|
||||
RefPtr<nsFrameLoader> loader = std::move(mFrameLoader);
|
||||
loader->Destroy();
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1591,11 +1591,6 @@ uint32_t nsObjectLoadingContent::GetCapabilities() const {
|
|||
}
|
||||
|
||||
void nsObjectLoadingContent::Destroy() {
|
||||
if (mFrameLoader) {
|
||||
mFrameLoader->Destroy();
|
||||
mFrameLoader = nullptr;
|
||||
}
|
||||
|
||||
// Reset state so that if the element is re-appended to tree again (e.g.
|
||||
// adopting to another document), it will reload resource again.
|
||||
UnloadObject();
|
||||
|
|
@ -1619,8 +1614,8 @@ void nsObjectLoadingContent::Unlink(nsObjectLoadingContent* tmp) {
|
|||
|
||||
void nsObjectLoadingContent::UnloadObject(bool aResetState) {
|
||||
if (mFrameLoader) {
|
||||
mFrameLoader->Destroy();
|
||||
mFrameLoader = nullptr;
|
||||
RefPtr<nsFrameLoader> loader = std::move(mFrameLoader);
|
||||
loader->Destroy();
|
||||
}
|
||||
|
||||
if (aResetState) {
|
||||
|
|
@ -1718,23 +1713,30 @@ void nsObjectLoadingContent::TriggerInnerFallbackLoads() {
|
|||
}
|
||||
// Do a depth-first traverse of node tree with the current element as root,
|
||||
// looking for non-<param> elements. If we find some then we have an HTML
|
||||
// fallback for this element.
|
||||
// fallback for this element
|
||||
AutoTArray<RefPtr<nsIContent>, 4> targets;
|
||||
for (nsIContent* child = el->GetFirstChild(); child;) {
|
||||
// <object> and <embed> elements in the fallback need to StartObjectLoad.
|
||||
// Their children should be ignored since they are part of those element's
|
||||
// fallback.
|
||||
if (auto* embed = HTMLEmbedElement::FromNode(child)) {
|
||||
embed->StartObjectLoad(true, true);
|
||||
// Skip the children
|
||||
child = child->GetNextNonChildNode(el);
|
||||
} else if (auto* object = HTMLObjectElement::FromNode(child)) {
|
||||
object->StartObjectLoad(true, true);
|
||||
// Skip the children
|
||||
if (child->IsAnyOfHTMLElements(nsGkAtoms::embed, nsGkAtoms::object)) {
|
||||
targets.AppendElement(child);
|
||||
child = child->GetNextNonChildNode(el);
|
||||
} else {
|
||||
child = child->GetNextNode(el);
|
||||
}
|
||||
}
|
||||
|
||||
for (RefPtr<nsIContent>& target : targets) {
|
||||
if (!target->IsInclusiveDescendantOf(el)) {
|
||||
continue;
|
||||
}
|
||||
if (auto* embed = HTMLEmbedElement::FromNode(target)) {
|
||||
embed->StartObjectLoad(true, true);
|
||||
} else if (auto* object = HTMLObjectElement::FromNode(target)) {
|
||||
object->StartObjectLoad(true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
|||
|
|
@ -366,6 +366,7 @@ class nsPIDOMWindowInner : public mozIDOMWindow {
|
|||
mozilla::Maybe<mozilla::dom::ClientInfo> GetClientInfo() const;
|
||||
mozilla::Maybe<mozilla::dom::ClientState> GetClientState() const;
|
||||
mozilla::Maybe<mozilla::dom::ServiceWorkerDescriptor> GetController() const;
|
||||
mozilla::dom::ClientSource* GetClientSource() const;
|
||||
|
||||
void SetCsp(nsIContentSecurityPolicy* aCsp);
|
||||
void SetPreloadCsp(nsIContentSecurityPolicy* aPreloadCsp);
|
||||
|
|
|
|||
|
|
@ -2829,20 +2829,6 @@ static nsTextFrame* GetTextFrameForContent(nsIContent* aContent,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// Try to un-suppress whitespace if needed, but only if we'll be able to flush
|
||||
// to immediately see the results of the un-suppression. If we can't flush
|
||||
// here, then calling EnsureFrameForTextNodeIsCreatedAfterFlush would be
|
||||
// pointless anyway.
|
||||
if (aFlushLayout) {
|
||||
const bool frameWillBeUnsuppressed =
|
||||
presShell->FrameConstructor()
|
||||
->EnsureFrameForTextNodeIsCreatedAfterFlush(
|
||||
static_cast<CharacterData*>(aContent));
|
||||
if (frameWillBeUnsuppressed) {
|
||||
doc->FlushPendingNotifications(FlushType::Layout);
|
||||
}
|
||||
}
|
||||
|
||||
nsIFrame* frame = aContent->GetPrimaryFrame();
|
||||
if (!frame || !frame->IsTextFrame()) {
|
||||
return nullptr;
|
||||
|
|
|
|||
|
|
@ -23,8 +23,14 @@ using namespace mozilla;
|
|||
using namespace mozilla::dom;
|
||||
|
||||
nsScreen::nsScreen(nsPIDOMWindowInner* aWindow)
|
||||
: DOMEventTargetHelper(aWindow),
|
||||
mScreenOrientation(new ScreenOrientation(aWindow, this)) {}
|
||||
: DOMEventTargetHelper(aWindow) {}
|
||||
|
||||
/* static */ already_AddRefed<nsScreen> nsScreen::Create(
|
||||
nsPIDOMWindowInner* aWindow) {
|
||||
RefPtr screen = new nsScreen(aWindow);
|
||||
screen->mScreenOrientation = ScreenOrientation::Create(aWindow, screen);
|
||||
return screen.forget();
|
||||
}
|
||||
|
||||
nsScreen::~nsScreen() = default;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,9 +21,12 @@ enum class RFPTarget : uint64_t;
|
|||
|
||||
// Script "screen" object
|
||||
class nsScreen : public mozilla::DOMEventTargetHelper {
|
||||
public:
|
||||
private:
|
||||
explicit nsScreen(nsPIDOMWindowInner* aWindow);
|
||||
|
||||
public:
|
||||
static already_AddRefed<nsScreen> Create(nsPIDOMWindowInner* aWindow);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsScreen,
|
||||
mozilla::DOMEventTargetHelper)
|
||||
|
|
|
|||
|
|
@ -47,6 +47,13 @@ void nsWrapperCache::SetWrapperJSObject(JSObject* aNewWrapper) {
|
|||
}
|
||||
}
|
||||
|
||||
void nsWrapperCache::ClearWrapperOnWrapFailure() {
|
||||
if (IsNurseryWrapper(mWrapper)) {
|
||||
CycleCollectedJSRuntime::Get()->NurseryWrapperRemovedSlow(this);
|
||||
}
|
||||
ClearWrapper();
|
||||
}
|
||||
|
||||
void nsWrapperCache::ReleaseWrapper(void* aScriptObjectHolder) {
|
||||
// If the behavior here changes in a substantive way, you may need
|
||||
// to update css::Rule::UnlinkDeclarationWrapper as well.
|
||||
|
|
|
|||
|
|
@ -170,6 +170,8 @@ class JS_HAZ_ROOTED nsWrapperCache {
|
|||
}
|
||||
}
|
||||
|
||||
void ClearWrapperOnWrapFailure();
|
||||
|
||||
/**
|
||||
* Update the wrapper when the object moves between globals.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -86,12 +86,18 @@ inline void nsWrapperCache::UpdateWrapperForNewGlobal(T* aScriptObjectHolder,
|
|||
SetPreservingWrapper(false);
|
||||
}
|
||||
|
||||
JSObject* oldWrapper = mWrapper;
|
||||
SetWrapper(aNewWrapper);
|
||||
|
||||
if (zoneChanged) {
|
||||
PreserveWrapper(aScriptObjectHolder);
|
||||
} else if (preserving) {
|
||||
SetPreservingWrapper(true);
|
||||
if (!JS::ObjectIsTenured(mWrapper)) {
|
||||
// SetWrapper doesn't fire a write barrier; add one so minor GC can
|
||||
// update mWrapper if the new wrapper is tenured.
|
||||
JS::HeapObjectPostWriteBarrier(&mWrapper, oldWrapper, mWrapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
[DEFAULT]
|
||||
|
||||
["test_bug_2027541.html"]
|
||||
|
||||
["test_nested_modules.html"]
|
||||
|
|
|
|||
47
icecat/dom/base/test/jsmodules/test_bug_2027541.html
Normal file
47
icecat/dom/base/test/jsmodules/test_bug_2027541.html
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<!DOCTYPE html>
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<title>Call import.meta.resolve after iframe removal</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script>
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
window.stolenResolve = null;
|
||||
|
||||
async function runTest() {
|
||||
const iframe = document.createElement("iframe");
|
||||
iframe.srcdoc = `<!DOCTYPE html><html><body>
|
||||
<script type="module">
|
||||
window.parent.stolenResolve = import.meta.resolve;
|
||||
window.parent.postMessage("ready", "*");
|
||||
<\/script>
|
||||
</body></html>`;
|
||||
|
||||
const ready = new Promise(resolve => {
|
||||
window.addEventListener("message", () => resolve(), { once: true });
|
||||
});
|
||||
document.body.appendChild(iframe);
|
||||
await ready;
|
||||
|
||||
ok(typeof window.stolenResolve === "function",
|
||||
"Got import.meta.resolve from inline iframe module");
|
||||
|
||||
iframe.remove();
|
||||
|
||||
SpecialPowers.forceGC();
|
||||
SpecialPowers.forceCC();
|
||||
await new Promise(r => requestAnimationFrame(r));
|
||||
|
||||
let result = window.stolenResolve("https://example.com/");
|
||||
is(result, "https://example.com/",
|
||||
"import.meta.resolve returns correct result after iframe removal and GC");
|
||||
|
||||
window.stolenResolve = null;
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
runTest();
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -2473,8 +2473,7 @@ void UpdateReflectorGlobal(JSContext* aCx, JS::Handle<JSObject*> aObjArg,
|
|||
}
|
||||
|
||||
// We've set up |newobj|, so we make it own the native by setting its reserved
|
||||
// slot and nulling out the reserved slot of |obj|. Update the wrapper cache
|
||||
// to keep everything consistent in case GC moves newobj.
|
||||
// slot and nulling out the reserved slot of |obj|.
|
||||
//
|
||||
// NB: It's important to do this _after_ copying the properties to
|
||||
// propertyHolder. Otherwise, an object with |foo.x === foo| will
|
||||
|
|
@ -2483,18 +2482,37 @@ void UpdateReflectorGlobal(JSContext* aCx, JS::Handle<JSObject*> aObjArg,
|
|||
JS::SetReservedSlot(newobj, DOM_OBJECT_SLOT,
|
||||
JS::GetReservedSlot(aObj, DOM_OBJECT_SLOT));
|
||||
JS::SetReservedSlot(aObj, DOM_OBJECT_SLOT, JS::PrivateValue(nullptr));
|
||||
size_t nslots = JSCLASS_RESERVED_SLOTS(JS::GetClass(aObj));
|
||||
for (size_t slot = DOM_INSTANCE_RESERVED_SLOTS; slot < nslots; ++slot) {
|
||||
const JS::Value& slotValue = JS::GetReservedSlot(aObj, slot);
|
||||
if (slotValue.isObject()) {
|
||||
JSObject* slotObj = &slotValue.toObject();
|
||||
if (IsObservableArrayProxy(slotObj)) {
|
||||
JS::SetReservedSlot(newobj, slot, slotValue);
|
||||
JS::SetReservedSlot(aObj, slot, JS::UndefinedValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsWrapperCache* cache = nullptr;
|
||||
CallQueryInterface(native, &cache);
|
||||
cache->UpdateWrapperForNewGlobal(native, newobj);
|
||||
|
||||
// For preserved wrappers the store buffer keeps mWrapper consistent across
|
||||
// the transplant. For non-preserved wrappers clear mWrapper so that
|
||||
// JSObjectsTenured doesn't follow a stale pointer if nursery GC fires.
|
||||
bool preserving = cache->PreservingWrapper();
|
||||
if (preserving) {
|
||||
cache->UpdateWrapperForNewGlobal(native, newobj);
|
||||
} else {
|
||||
cache->ClearWrapper();
|
||||
}
|
||||
|
||||
aObj = xpc::TransplantObjectRetainingXrayExpandos(aCx, aObj, newobj);
|
||||
if (!aObj) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
// Update the wrapper cache again if transplanting didn't use newobj but
|
||||
// returned some other object.
|
||||
if (aObj != newobj) {
|
||||
if (!preserving || aObj != newobj) {
|
||||
MOZ_ASSERT(UnwrapDOMObjectToISupports(aObj) == native);
|
||||
cache->UpdateWrapperForNewGlobal(native, aObj);
|
||||
}
|
||||
|
|
@ -3555,6 +3573,7 @@ static bool GetBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
|
|||
? aObj
|
||||
: js::UncheckedUnwrap(aObj,
|
||||
/* stopAtWindowProxy = */ false);
|
||||
MOZ_ASSERT(aSlotIndex < JSCLASS_RESERVED_SLOTS(JS::GetClass(reflector)));
|
||||
|
||||
// Retrieve the backing object from the reserved slot on the maplike/setlike
|
||||
// object. If it doesn't exist yet, create it.
|
||||
|
|
|
|||
|
|
@ -4683,7 +4683,7 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
|
|||
failureCode = dedent(
|
||||
"""
|
||||
aCache->ReleaseWrapper(aObject);
|
||||
aCache->ClearWrapper();
|
||||
aCache->ClearWrapperOnWrapFailure();
|
||||
return false;
|
||||
"""
|
||||
)
|
||||
|
|
@ -23213,7 +23213,9 @@ class CGIterableMethodGenerator(CGGeneric):
|
|||
CGGeneric.__init__(self, createIterator)
|
||||
|
||||
|
||||
def getObservableArrayBackingObject(descriptor, attr, errorReturn="return false;\n"):
|
||||
def getObservableArrayBackingObject(
|
||||
descriptor, attr, objName="obj", errorReturn="return false;\n"
|
||||
):
|
||||
"""
|
||||
Generate code to get/create a JS backing list for an observableArray attribute
|
||||
from the declaration slot.
|
||||
|
|
@ -23228,7 +23230,7 @@ def getObservableArrayBackingObject(descriptor, attr, errorReturn="return false;
|
|||
"""
|
||||
JS::Rooted<JSObject*> backingObj(cx);
|
||||
bool created = false;
|
||||
if (!GetObservableArrayBackingObject(cx, obj, ${slot},
|
||||
if (!GetObservableArrayBackingObject(cx, ${objName}, ${slot},
|
||||
&backingObj, &created, ${namespace}::ObservableArrayProxyHandler::getInstance(),
|
||||
self)) {
|
||||
$*{errorReturn}
|
||||
|
|
@ -23237,8 +23239,9 @@ def getObservableArrayBackingObject(descriptor, attr, errorReturn="return false;
|
|||
PreserveWrapper(self);
|
||||
}
|
||||
""",
|
||||
namespace=toBindingNamespace(MakeNativeName(attr.identifier.name)),
|
||||
objName=objName,
|
||||
slot=memberReservedSlot(attr, descriptor),
|
||||
namespace=toBindingNamespace(MakeNativeName(attr.identifier.name)),
|
||||
errorReturn=errorReturn,
|
||||
selfType=descriptor.nativeType,
|
||||
)
|
||||
|
|
@ -23350,12 +23353,18 @@ class CGObservableArrayProxyHandler_callback(ClassMethod):
|
|||
$*{convertType}
|
||||
|
||||
$*{preCallback}
|
||||
JS::Value val = js::GetProxyReservedSlot(aProxy, OBSERVABLE_ARRAY_DOM_INTERFACE_SLOT);
|
||||
auto* interface = static_cast<${ifaceType}*>(val.toPrivate());
|
||||
MOZ_ASSERT(interface);
|
||||
const JS::Value& val = js::GetProxyReservedSlot(aProxy, OBSERVABLE_ARRAY_DOM_INTERFACE_SLOT);
|
||||
if (MOZ_LIKELY(!val.isUndefined())) {
|
||||
auto* interface = static_cast<${ifaceType}*>(val.toPrivate());
|
||||
MOZ_ASSERT(interface);
|
||||
|
||||
ErrorResult rv;
|
||||
MOZ_KnownLive(interface)->${methodName}(${callbackArgs});
|
||||
if (rv.MaybeSetPendingException(cx)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ErrorResult rv;
|
||||
MOZ_KnownLive(interface)->${methodName}(${callbackArgs});
|
||||
$*{postCallback}
|
||||
""",
|
||||
preConversion=self.preConversion(),
|
||||
|
|
@ -23399,7 +23408,7 @@ class CGObservableArrayProxyHandler_OnDeleteItem(
|
|||
def postCallback(self):
|
||||
return dedent(
|
||||
"""
|
||||
return !rv.MaybeSetPendingException(cx);
|
||||
return true;
|
||||
"""
|
||||
)
|
||||
|
||||
|
|
@ -23464,10 +23473,6 @@ class CGObservableArrayProxyHandler_SetIndexedValue(
|
|||
def postCallback(self):
|
||||
return dedent(
|
||||
"""
|
||||
if (rv.MaybeSetPendingException(cx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!JS_SetElement(aCx, aBackingList, aIndex, aValue)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -23530,7 +23535,9 @@ class CGObservableArraySetterGenerator(CGGeneric):
|
|||
def __init__(self, descriptor, attr):
|
||||
assert attr.isAttr()
|
||||
assert attr.type.isObservableArray()
|
||||
getBackingObject = getObservableArrayBackingObject(descriptor, attr)
|
||||
getBackingObject = getObservableArrayBackingObject(
|
||||
descriptor, attr, objName="unwrappedObj"
|
||||
)
|
||||
setElement = dedent(
|
||||
"""
|
||||
if (!JS_SetElement(cx, backingObj, i, val)) {
|
||||
|
|
@ -23557,15 +23564,22 @@ class CGObservableArraySetterGenerator(CGGeneric):
|
|||
return false;
|
||||
}
|
||||
|
||||
${getBackingObject}
|
||||
const ObservableArrayProxyHandler* handler = GetObservableArrayProxyHandler(backingObj);
|
||||
if (!handler->SetLength(cx, backingObj, 0)) {
|
||||
return false;
|
||||
}
|
||||
JS::Rooted<JSObject*> unwrappedObj(cx, js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false));
|
||||
MOZ_ASSERT(IsDOMObject(unwrappedObj));
|
||||
{
|
||||
JSAutoRealm ar(cx, unwrappedObj);
|
||||
|
||||
JS::Rooted<JS::Value> val(cx);
|
||||
for (size_t i = 0; i < arg0.Length(); i++) {
|
||||
$*{conversion}
|
||||
$*{getBackingObject}
|
||||
|
||||
const ObservableArrayProxyHandler* handler = GetObservableArrayProxyHandler(backingObj);
|
||||
if (!handler->SetLength(cx, backingObj, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> val(cx);
|
||||
for (size_t i = 0; i < arg0.Length(); i++) {
|
||||
$*{conversion}
|
||||
}
|
||||
}
|
||||
""",
|
||||
conversion=conversion,
|
||||
|
|
@ -23611,7 +23625,7 @@ class CGObservableArrayHelperFunctionGenerator(CGHelperFunctionGenerator):
|
|||
getObservableArrayBackingObject(
|
||||
descriptor,
|
||||
attr,
|
||||
dedent(
|
||||
errorReturn=dedent(
|
||||
"""
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return%s;
|
||||
|
|
|
|||
|
|
@ -215,6 +215,7 @@ class TErrorResult {
|
|||
// informative message and calling the relevant Throw*Error.
|
||||
void MOZ_MUST_RETURN_FROM_CALLER_IF_THIS_IS_ARG Throw(nsresult rv) {
|
||||
MOZ_ASSERT(NS_FAILED(rv), "Please don't try throwing success");
|
||||
ClearUnionData();
|
||||
AssignErrorCode(rv);
|
||||
}
|
||||
|
||||
|
|
@ -431,7 +432,10 @@ class TErrorResult {
|
|||
// Backwards-compat to make conversion simpler. We don't call
|
||||
// Throw() here because people can easily pass success codes to
|
||||
// this. This operator is deprecated and ideally shouldn't be used.
|
||||
void operator=(nsresult rv) { AssignErrorCode(rv); }
|
||||
void operator=(nsresult rv) {
|
||||
ClearUnionData();
|
||||
AssignErrorCode(rv);
|
||||
}
|
||||
|
||||
bool Failed() const { return NS_FAILED(mResult); }
|
||||
|
||||
|
|
@ -542,6 +546,7 @@ class TErrorResult {
|
|||
}
|
||||
|
||||
void AssignErrorCode(nsresult aRv) {
|
||||
MOZ_ASSERT(mUnionState == HasNothing);
|
||||
MOZ_ASSERT(aRv != NS_ERROR_INTERNAL_ERRORRESULT_TYPEERROR,
|
||||
"Use ThrowTypeError()");
|
||||
MOZ_ASSERT(aRv != NS_ERROR_INTERNAL_ERRORRESULT_RANGEERROR,
|
||||
|
|
|
|||
12
icecat/dom/cache/Manager.cpp
vendored
12
icecat/dom/cache/Manager.cpp
vendored
|
|
@ -658,7 +658,8 @@ class Manager::CacheMatchAction final : public Manager::BaseAction {
|
|||
|
||||
// If we entered shutdown on the main thread while we were doing IO,
|
||||
// bail out now.
|
||||
if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownQM)) {
|
||||
if (IsCanceled() ||
|
||||
AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownQM)) {
|
||||
if (stream) {
|
||||
stream->Close();
|
||||
}
|
||||
|
|
@ -734,7 +735,8 @@ class Manager::CacheMatchAllAction final : public Manager::BaseAction {
|
|||
|
||||
// If we entered shutdown on the main thread while we were doing IO,
|
||||
// bail out now.
|
||||
if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownQM)) {
|
||||
if (IsCanceled() ||
|
||||
AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownQM)) {
|
||||
if (stream) {
|
||||
stream->Close();
|
||||
}
|
||||
|
|
@ -1289,7 +1291,8 @@ class Manager::CacheKeysAction final : public Manager::BaseAction {
|
|||
|
||||
// If we entered shutdown on the main thread while we were doing IO,
|
||||
// bail out now.
|
||||
if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownQM)) {
|
||||
if (IsCanceled() ||
|
||||
AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownQM)) {
|
||||
if (stream) {
|
||||
stream->Close();
|
||||
}
|
||||
|
|
@ -1368,7 +1371,8 @@ class Manager::StorageMatchAction final : public Manager::BaseAction {
|
|||
|
||||
// If we entered shutdown on the main thread while we were doing IO,
|
||||
// bail out now.
|
||||
if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownQM)) {
|
||||
if (IsCanceled() ||
|
||||
AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownQM)) {
|
||||
if (stream) {
|
||||
stream->Close();
|
||||
}
|
||||
|
|
|
|||
7
icecat/dom/cache/StreamList.cpp
vendored
7
icecat/dom/cache/StreamList.cpp
vendored
|
|
@ -30,7 +30,6 @@ StreamList::StreamList(SafeRefPtr<Manager> aManager,
|
|||
mStreamControl(nullptr),
|
||||
mActivated(false) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mManager);
|
||||
mContext->AddActivity(*this);
|
||||
}
|
||||
|
||||
Manager& StreamList::GetManager() const {
|
||||
|
|
@ -73,6 +72,9 @@ void StreamList::Activate(CacheId aCacheId) {
|
|||
MOZ_DIAGNOSTIC_ASSERT(mCacheId == INVALID_CACHE_ID);
|
||||
mActivated = true;
|
||||
mCacheId = aCacheId;
|
||||
|
||||
mContext->AddActivity(*this);
|
||||
|
||||
mManager->AddRefCacheId(mCacheId);
|
||||
mManager->AddStreamList(*this);
|
||||
|
||||
|
|
@ -134,6 +136,7 @@ void StreamList::NoteClosedAll() {
|
|||
|
||||
void StreamList::CloseAll() {
|
||||
NS_ASSERT_OWNINGTHREAD(StreamList);
|
||||
SafeRefPtr<StreamList> kungFuDeathGrip = SafeRefPtrFromThis();
|
||||
|
||||
if (mStreamControl && mStreamControl->CanSend()) {
|
||||
// CloseAll will kick off everything needed for shutdown.
|
||||
|
|
@ -192,13 +195,13 @@ StreamList::~StreamList() {
|
|||
NS_ASSERT_OWNINGTHREAD(StreamList);
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mStreamControl);
|
||||
if (mActivated) {
|
||||
mContext->RemoveActivity(*this);
|
||||
mManager->RemoveStreamList(*this);
|
||||
for (uint32_t i = 0; i < mList.Length(); ++i) {
|
||||
mManager->ReleaseBodyId(mList[i].mId);
|
||||
}
|
||||
mManager->ReleaseCacheId(mCacheId);
|
||||
}
|
||||
mContext->RemoveActivity(*this);
|
||||
}
|
||||
|
||||
} // namespace mozilla::dom::cache
|
||||
|
|
|
|||
|
|
@ -880,6 +880,8 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(CanvasRenderingContext2D)
|
|||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(CanvasRenderingContext2D)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CanvasRenderingContext2D)
|
||||
tmp->RemoveShutdownObserver();
|
||||
tmp->OnShutdown();
|
||||
// Make sure we remove ourselves from the list of demotable contexts (raw
|
||||
// pointers), since we're logically destructed at this point.
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCanvasElement)
|
||||
|
|
@ -2888,8 +2890,12 @@ void CanvasRenderingContext2D::GetLetterSpacing(nsACString& aLetterSpacing) {
|
|||
|
||||
void CanvasRenderingContext2D::SetLetterSpacing(
|
||||
const nsACString& aLetterSpacing) {
|
||||
ParseSpacing(aLetterSpacing, &CurrentState().letterSpacing,
|
||||
CurrentState().letterSpacingStr);
|
||||
nsAutoCString normalized;
|
||||
Maybe<float> value = ParseSpacing(aLetterSpacing, normalized);
|
||||
if (value) {
|
||||
CurrentState().letterSpacing = *value;
|
||||
CurrentState().letterSpacingStr = normalized;
|
||||
}
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::GetWordSpacing(nsACString& aWordSpacing) {
|
||||
|
|
@ -2901,8 +2907,12 @@ void CanvasRenderingContext2D::GetWordSpacing(nsACString& aWordSpacing) {
|
|||
}
|
||||
|
||||
void CanvasRenderingContext2D::SetWordSpacing(const nsACString& aWordSpacing) {
|
||||
ParseSpacing(aWordSpacing, &CurrentState().wordSpacing,
|
||||
CurrentState().wordSpacingStr);
|
||||
nsAutoCString normalized;
|
||||
Maybe<float> value = ParseSpacing(aWordSpacing, normalized);
|
||||
if (value) {
|
||||
CurrentState().wordSpacing = *value;
|
||||
CurrentState().wordSpacingStr = normalized;
|
||||
}
|
||||
}
|
||||
|
||||
static GeckoFontMetrics GetFontMetricsFromCanvas(void* aContext) {
|
||||
|
|
@ -2933,9 +2943,8 @@ static GeckoFontMetrics GetFontMetricsFromCanvas(void* aContext) {
|
|||
0.0f};
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::ParseSpacing(const nsACString& aSpacing,
|
||||
float* aValue,
|
||||
nsACString& aNormalized) {
|
||||
Maybe<float> CanvasRenderingContext2D::ParseSpacing(const nsACString& aSpacing,
|
||||
nsACString& aNormalized) {
|
||||
// Normalize whitespace in the string before trying to parse it, as we want
|
||||
// to store it in normalized form, and this allows a simple check against the
|
||||
// 'normal' keyword, which is not accepted.
|
||||
|
|
@ -2943,28 +2952,28 @@ void CanvasRenderingContext2D::ParseSpacing(const nsACString& aSpacing,
|
|||
normalized.CompressWhitespace(true, true);
|
||||
ToLowerCase(normalized);
|
||||
if (normalized.EqualsLiteral("normal")) {
|
||||
return;
|
||||
return Nothing();
|
||||
}
|
||||
float value;
|
||||
if (!Servo_ParseLengthWithoutStyleContext(&normalized, &value,
|
||||
GetFontMetricsFromCanvas, this)) {
|
||||
if (!GetPresShell()) {
|
||||
return;
|
||||
return Nothing();
|
||||
}
|
||||
// This will parse aSpacing as a <length-percentage>...
|
||||
RefPtr<const ComputedStyle> style =
|
||||
ResolveStyleForProperty(eCSSProperty_letter_spacing, aSpacing);
|
||||
if (!style) {
|
||||
return;
|
||||
return Nothing();
|
||||
}
|
||||
// ...but only <length> is allowed according to the canvas spec.
|
||||
if (!style->StyleText()->mLetterSpacing.IsLength()) {
|
||||
return;
|
||||
return Nothing();
|
||||
}
|
||||
value = style->StyleText()->mLetterSpacing.AsLength().ToCSSPixels();
|
||||
}
|
||||
aNormalized = normalized;
|
||||
*aValue = value;
|
||||
return Some(value);
|
||||
}
|
||||
|
||||
class CanvasUserSpaceMetrics final : public UserSpaceMetricsWithSize {
|
||||
|
|
@ -3434,6 +3443,11 @@ void CanvasRenderingContext2D::StrokeImpl(const gfx::Path& aPath) {
|
|||
return;
|
||||
}
|
||||
|
||||
const bool needBounds = NeedToCalculateBounds();
|
||||
if (!IsTargetValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ContextState* state = &CurrentState();
|
||||
StrokeOptions strokeOptions(state->lineWidth, CanvasToGfx(state->lineJoin),
|
||||
CanvasToGfx(state->lineCap), state->miterLimit,
|
||||
|
|
@ -3441,10 +3455,6 @@ void CanvasRenderingContext2D::StrokeImpl(const gfx::Path& aPath) {
|
|||
state->dashOffset);
|
||||
state = nullptr;
|
||||
|
||||
const bool needBounds = NeedToCalculateBounds();
|
||||
if (!IsTargetValid()) {
|
||||
return;
|
||||
}
|
||||
gfx::Rect bounds;
|
||||
if (needBounds) {
|
||||
bounds = aPath.GetStrokedBounds(strokeOptions, mTarget->GetTransform());
|
||||
|
|
@ -4695,6 +4705,7 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor final
|
|||
}
|
||||
|
||||
mCtx->EnsureTarget();
|
||||
const bool needBounds = mCtx->NeedToCalculateBounds();
|
||||
if (!mCtx->IsTargetValid()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -4709,7 +4720,7 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor final
|
|||
const ContextState& state = mCtx->CurrentState();
|
||||
|
||||
gfx::Rect bounds;
|
||||
if (mCtx->NeedToCalculateBounds()) {
|
||||
if (needBounds) {
|
||||
bounds = ToRect(mBoundingBox);
|
||||
bounds.MoveBy(mPt / mAppUnitsPerDevPixel);
|
||||
if (style == Style::STROKE) {
|
||||
|
|
@ -4857,6 +4868,9 @@ UniquePtr<TextMetrics> CanvasRenderingContext2D::DrawOrMeasureText(
|
|||
canvasStyle = nsComputedDOMStyle::GetComputedStyle(mCanvasElement);
|
||||
}
|
||||
|
||||
// This is only needed to know if we can know the drawing bounding box easily.
|
||||
const bool doCalculateBounds = NeedToCalculateBounds();
|
||||
|
||||
// Get text direction, either from the property or inherited from context.
|
||||
const ContextState& state = CurrentState();
|
||||
bool isRTL;
|
||||
|
|
@ -4882,8 +4896,6 @@ UniquePtr<TextMetrics> CanvasRenderingContext2D::DrawOrMeasureText(
|
|||
MOZ_CRASH("unknown direction!");
|
||||
}
|
||||
|
||||
// This is only needed to know if we can know the drawing bounding box easily.
|
||||
const bool doCalculateBounds = NeedToCalculateBounds();
|
||||
if (presShell && presShell->IsDestroying()) {
|
||||
aError = NS_ERROR_FAILURE;
|
||||
return nullptr;
|
||||
|
|
@ -5163,50 +5175,54 @@ gfxFontGroup* CanvasRenderingContext2D::GetCurrentFontStyle() {
|
|||
nsPresContext* presContext =
|
||||
presShell ? presShell->GetPresContext() : nullptr;
|
||||
|
||||
// If we have a cached fontGroup, check that it is valid for the current
|
||||
// prescontext; if not, we need to discard and re-create it.
|
||||
RefPtr<gfxFontGroup>& fontGroup = CurrentState().fontGroup;
|
||||
if (fontGroup) {
|
||||
if (fontGroup->GetPresContext() != presContext) {
|
||||
fontGroup = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fontGroup) {
|
||||
ErrorResult err;
|
||||
constexpr auto kDefaultFontStyle = "10px sans-serif"_ns;
|
||||
const float kDefaultFontSize = 10.0;
|
||||
// If the font has already been set, we're re-creating the fontGroup
|
||||
// and should re-use the existing font attribute; if not, we initialize
|
||||
// it to the canvas default.
|
||||
const nsCString& currentFont = CurrentState().font;
|
||||
bool fontUpdated = SetFontInternal(
|
||||
currentFont.IsEmpty() ? kDefaultFontStyle : currentFont, err);
|
||||
if (err.Failed() || !fontUpdated) {
|
||||
err.SuppressException();
|
||||
// XXX Should we get a default lang from the prescontext or something?
|
||||
nsAtom* language = nsGkAtoms::x_western;
|
||||
bool explicitLanguage = false;
|
||||
gfxFontStyle style;
|
||||
style.size = kDefaultFontSize;
|
||||
int32_t perDevPixel, perCSSPixel;
|
||||
GetAppUnitsValues(&perDevPixel, &perCSSPixel);
|
||||
gfxFloat devToCssSize = gfxFloat(perDevPixel) / gfxFloat(perCSSPixel);
|
||||
const auto* sans =
|
||||
Servo_FontFamily_Generic(StyleGenericFontFamily::SansSerif);
|
||||
fontGroup = new gfxFontGroup(
|
||||
presContext, sans->families, &style, language, explicitLanguage,
|
||||
presContext ? presContext->GetTextPerfMetrics() : nullptr, nullptr,
|
||||
devToCssSize, StyleFontVariantEmoji::Normal);
|
||||
if (fontGroup) {
|
||||
CurrentState().font = kDefaultFontStyle;
|
||||
{
|
||||
// If we have a cached fontGroup, check that it is valid for the current
|
||||
// prescontext; if not, we need to discard and re-create it.
|
||||
RefPtr<gfxFontGroup>& fontGroup = CurrentState().fontGroup;
|
||||
if (fontGroup) {
|
||||
if (fontGroup->GetPresContext() != presContext) {
|
||||
fontGroup = nullptr;
|
||||
} else {
|
||||
NS_ERROR("Default canvas font is invalid");
|
||||
return fontGroup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fontGroup;
|
||||
ErrorResult err;
|
||||
constexpr auto kDefaultFontStyle = "10px sans-serif"_ns;
|
||||
const float kDefaultFontSize = 10.0;
|
||||
// If the font has already been set, we're re-creating the fontGroup
|
||||
// and should re-use the existing font attribute; if not, we initialize
|
||||
// it to the canvas default.
|
||||
nsAutoCString currentFont(CurrentState().font);
|
||||
if (currentFont.IsEmpty()) {
|
||||
currentFont = kDefaultFontStyle;
|
||||
}
|
||||
bool fontUpdated = SetFontInternal(currentFont, err);
|
||||
if (err.Failed() || !fontUpdated) {
|
||||
err.SuppressException();
|
||||
// XXX Should we get a default lang from the prescontext or something?
|
||||
nsAtom* language = nsGkAtoms::x_western;
|
||||
bool explicitLanguage = false;
|
||||
gfxFontStyle style;
|
||||
style.size = kDefaultFontSize;
|
||||
int32_t perDevPixel, perCSSPixel;
|
||||
GetAppUnitsValues(&perDevPixel, &perCSSPixel);
|
||||
gfxFloat devToCssSize = gfxFloat(perDevPixel) / gfxFloat(perCSSPixel);
|
||||
const auto* sans =
|
||||
Servo_FontFamily_Generic(StyleGenericFontFamily::SansSerif);
|
||||
CurrentState().fontGroup = new gfxFontGroup(
|
||||
presContext, sans->families, &style, language, explicitLanguage,
|
||||
presContext ? presContext->GetTextPerfMetrics() : nullptr, nullptr,
|
||||
devToCssSize, StyleFontVariantEmoji::Normal);
|
||||
if (CurrentState().fontGroup) {
|
||||
CurrentState().font = kDefaultFontStyle;
|
||||
} else {
|
||||
NS_ERROR("Default canvas font is invalid");
|
||||
}
|
||||
}
|
||||
|
||||
return CurrentState().fontGroup;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -5711,7 +5727,7 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
|
|||
HTMLVideoElement* video = HTMLVideoElement::FromNodeOrNull(element);
|
||||
if (video && mBufferProvider->IsAccelerated() &&
|
||||
mTarget->IsRecording() &&
|
||||
!(!NeedToApplyFilter() && NeedToDrawShadow())) {
|
||||
!(NeedToApplyFilter() || NeedToDrawShadow())) {
|
||||
res = nsLayoutUtils::SurfaceFromElement(
|
||||
video, sfeFlags, mTarget, /* aOptimizeSourceSurface */ false);
|
||||
surfaceDescriptor = MaybeGetSurfaceDescriptorForRemoteCanvas(res);
|
||||
|
|
|
|||
|
|
@ -613,11 +613,13 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,
|
|||
protected:
|
||||
/**
|
||||
* Helper to parse a value for the letterSpacing or wordSpacing attribute.
|
||||
* If successful, returns the result in aValue, and the whitespace-normalized
|
||||
* value string in aNormalized; if unsuccessful these are left untouched.
|
||||
* If the string can be parsed, returns Some(value) and sets aNormalized to
|
||||
* the normalized form of the specified string. If it cannot be parsed as a
|
||||
* spacing value, returns Nothing, and aNormalized is untouched.
|
||||
* Note that ParseSpacing may flush style (to resolve font-relative units).
|
||||
*/
|
||||
void ParseSpacing(const nsACString& aSpacing, float* aValue,
|
||||
nsACString& aNormalized);
|
||||
mozilla::Maybe<float> ParseSpacing(const nsACString& aSpacing,
|
||||
nsACString& aNormalized);
|
||||
|
||||
already_AddRefed<const ComputedStyle> ResolveStyleForProperty(
|
||||
nsCSSPropertyID aProperty, const nsACString& aValue);
|
||||
|
|
@ -1000,10 +1002,14 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,
|
|||
* last call to UpdateFilter and now.
|
||||
*/
|
||||
const gfx::FilterDescription& EnsureUpdatedFilter() {
|
||||
bool isWriteOnly = mCanvasElement && mCanvasElement->IsWriteOnly();
|
||||
bool isWriteOnly = IsWriteOnly() ||
|
||||
(mCanvasElement && mCanvasElement->IsWriteOnly()) ||
|
||||
(mOffscreenCanvas && mOffscreenCanvas->IsWriteOnly());
|
||||
if (CurrentState().filterSourceGraphicTainted != isWriteOnly) {
|
||||
UpdateFilter(/* aFlushIfNeeded = */ true);
|
||||
EnsureTarget();
|
||||
// Do not flush here: this runs inside drawing operations that hold raw
|
||||
// references to mPath/state, and a flush can run script that resets the
|
||||
// context, leading to UAF. Flush already happened at SetFilter() time.
|
||||
UpdateFilter(/* aFlushIfNeeded = */ false);
|
||||
}
|
||||
MOZ_ASSERT(CurrentState().filterSourceGraphicTainted == isWriteOnly);
|
||||
return CurrentState().filter;
|
||||
|
|
|
|||
|
|
@ -198,7 +198,18 @@ ClientWebGLContext::ClientWebGLContext(const bool webgl2)
|
|||
: mIsWebGL2(webgl2),
|
||||
mExtLoseContext(new ClientWebGLExtensionLoseContext(*this)) {}
|
||||
|
||||
ClientWebGLContext::~ClientWebGLContext() { RemovePostRefreshObserver(); }
|
||||
static inline void SafeReleaseNotLostData(std::shared_ptr<webgl::NotLostData>& notLost) {
|
||||
if (notLost) {
|
||||
const auto keepAlive = std::move(notLost);
|
||||
keepAlive->extensions = {};
|
||||
keepAlive->state = {};
|
||||
}
|
||||
}
|
||||
|
||||
ClientWebGLContext::~ClientWebGLContext() {
|
||||
RemovePostRefreshObserver();
|
||||
SafeReleaseNotLostData(mNotLost);
|
||||
}
|
||||
|
||||
void ClientWebGLContext::JsWarning(const std::string& utf8) const {
|
||||
nsIGlobalObject* global = nullptr;
|
||||
|
|
@ -4511,6 +4522,14 @@ void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget,
|
|||
std::string{"gpuProcessTextureId works only in GPU process."});
|
||||
}
|
||||
} break;
|
||||
case layers::SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr: {
|
||||
MOZ_ASSERT(desc->image);
|
||||
keepAliveImage = desc->image;
|
||||
} break;
|
||||
case layers::SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: {
|
||||
MOZ_ASSERT(desc->image);
|
||||
keepAliveImage = desc->image;
|
||||
} break;
|
||||
case layers::SurfaceDescriptor::TSurfaceDescriptorGPUVideo: {
|
||||
const auto& inProcess = mNotLost->inProcess;
|
||||
MOZ_ASSERT(desc->image);
|
||||
|
|
@ -7004,11 +7023,7 @@ void ImplCycleCollectionTraverse(
|
|||
}
|
||||
|
||||
void ImplCycleCollectionUnlink(std::shared_ptr<webgl::NotLostData>& field) {
|
||||
if (!field) return;
|
||||
const auto keepAlive = field;
|
||||
keepAlive->extensions = {};
|
||||
keepAlive->state = {};
|
||||
field = nullptr;
|
||||
SafeReleaseNotLostData(field);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
#include "mozilla/gfx/Swizzle.h"
|
||||
#include "mozilla/layers/ImageDataSerializer.h"
|
||||
#include "mozilla/layers/RemoteTextureMap.h"
|
||||
#include "mozilla/widget/ScreenManager.h"
|
||||
#include "skia/include/core/SkPixmap.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
|
|
@ -817,7 +816,7 @@ bool DrawTargetWebgl::GenerateComplexClipMask() {
|
|||
return !!data;
|
||||
}
|
||||
|
||||
bool DrawTargetWebgl::SetSimpleClipRect() {
|
||||
Maybe<Rect> DrawTargetWebgl::ComputeSimpleClipRect() const {
|
||||
// Determine whether the clipping rectangle is simple enough to accelerate.
|
||||
// Check if there is a device space clip rectangle available from the Skia
|
||||
// target.
|
||||
|
|
@ -829,9 +828,7 @@ bool DrawTargetWebgl::SetSimpleClipRect() {
|
|||
if (!clip->IsEmpty() && clip->Contains(GetRect())) {
|
||||
clip = Some(GetRect());
|
||||
}
|
||||
mSharedContext->SetClipRect(*clip);
|
||||
mSharedContext->SetNoClipMask();
|
||||
return true;
|
||||
return Some(Rect(*clip));
|
||||
}
|
||||
|
||||
// There was no pixel-aligned clip rect available, so check the clip stack to
|
||||
|
|
@ -842,15 +839,22 @@ bool DrawTargetWebgl::SetSimpleClipRect() {
|
|||
// complex.
|
||||
if (clipStack.mPath ||
|
||||
!clipStack.mTransform.PreservesAxisAlignedRectangles()) {
|
||||
return false;
|
||||
return Nothing();
|
||||
}
|
||||
// Transform the rect and intersect it with the current clip.
|
||||
rect =
|
||||
clipStack.mTransform.TransformBounds(clipStack.mRect).Intersect(rect);
|
||||
}
|
||||
mSharedContext->SetClipRect(rect);
|
||||
mSharedContext->SetNoClipMask();
|
||||
return true;
|
||||
return Some(rect);
|
||||
}
|
||||
|
||||
bool DrawTargetWebgl::SetSimpleClipRect() {
|
||||
if (Maybe<Rect> rect = ComputeSimpleClipRect()) {
|
||||
mSharedContext->SetClipRect(*rect);
|
||||
mSharedContext->SetNoClipMask();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Installs the Skia clip rectangle, if applicable, onto the shared WebGL
|
||||
|
|
@ -874,6 +878,21 @@ bool DrawTargetWebgl::PrepareContext(bool aClipped) {
|
|||
return mSharedContext->SetTarget(this);
|
||||
}
|
||||
|
||||
// Whether clipping may be necessary for the operation. This tries to avoid
|
||||
// generating a complex clip mask in case the current target is not active
|
||||
// or not using WebGL. If there is only a simple clip mask and its bounds
|
||||
// encompass the viewport, then no clipping is required.
|
||||
bool DrawTargetWebgl::ShouldClip() {
|
||||
if (mSharedContext->IsCurrentTarget(this) && !mRefreshClipState) {
|
||||
return mSharedContext->HasClipMask() ||
|
||||
!mSharedContext->mClipAARect.Contains(Rect(GetRect()));
|
||||
}
|
||||
if (Maybe<Rect> rect = ComputeSimpleClipRect()) {
|
||||
return !rect->Contains(Rect(GetRect()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedContextWebgl::IsContextLost() const {
|
||||
return !mWebgl || mWebgl->IsContextLost();
|
||||
}
|
||||
|
|
@ -905,29 +924,12 @@ bool DrawTargetWebgl::CanCreate(const IntSize& aSize, SurfaceFormat aFormat) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Maximum pref allows 3 different options:
|
||||
// 0 means unlimited size,
|
||||
// Maximum pref allows 2 different options:
|
||||
// <= 0 means unlimited size,
|
||||
// > 0 means use value as an absolute threshold,
|
||||
// < 0 means use the number of screen pixels as a threshold.
|
||||
int32_t maxSize = StaticPrefs::gfx_canvas_accelerated_max_size();
|
||||
if (maxSize > 0) {
|
||||
if (std::max(aSize.width, aSize.height) > maxSize) {
|
||||
return false;
|
||||
}
|
||||
} else if (maxSize < 0) {
|
||||
// Default to historical mobile screen size of 980x480, like FishIEtank.
|
||||
// In addition, allow acceleration up to this size even if the screen is
|
||||
// smaller. A lot content expects this size to work well. See Bug 999841
|
||||
static const int32_t kScreenPixels = 980 * 480;
|
||||
|
||||
if (RefPtr<widget::Screen> screen =
|
||||
widget::ScreenManager::GetSingleton().GetPrimaryScreen()) {
|
||||
LayoutDeviceIntSize screenSize = screen->GetRect().Size();
|
||||
if (aSize.width * aSize.height >
|
||||
std::max(screenSize.width * screenSize.height, kScreenPixels)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (maxSize > 0 && std::max(aSize.width, aSize.height) > maxSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -1645,9 +1647,7 @@ void DrawTargetWebgl::ClearRect(const Rect& aRect) {
|
|||
|
||||
// If the clear rectangle encompasses the entire viewport and is not clipped,
|
||||
// then mark the target as entirely clear.
|
||||
if (containsViewport && mSharedContext->IsCurrentTarget(this) &&
|
||||
!mSharedContext->HasClipMask() &&
|
||||
mSharedContext->mClipAARect.Contains(Rect(GetRect()))) {
|
||||
if (containsViewport && !ShouldClip()) {
|
||||
mIsClear = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -2038,6 +2038,7 @@ bool SharedContextWebgl::UploadSurface(DataSourceSurface* aData,
|
|||
if (srcRect.IsEmpty()) {
|
||||
return true;
|
||||
}
|
||||
Maybe<DataSourceSurface::ScopedMap> map;
|
||||
if (aData) {
|
||||
// If the source rect could not possibly overlap the surface, then it is
|
||||
// effectively empty with nothing to upload.
|
||||
|
|
@ -2058,15 +2059,15 @@ bool SharedContextWebgl::UploadSurface(DataSourceSurface* aData,
|
|||
// The surface needs to be uploaded to its backing texture either to
|
||||
// initialize or update the texture handle contents. Map the data
|
||||
// contents of the surface so it can be read.
|
||||
DataSourceSurface::ScopedMap map(aData, DataSourceSurface::READ);
|
||||
if (!map.IsMapped()) {
|
||||
map.emplace(aData, DataSourceSurface::READ);
|
||||
if (!map->IsMapped()) {
|
||||
return false;
|
||||
}
|
||||
int32_t stride = map.GetStride();
|
||||
int32_t stride = map->GetStride();
|
||||
// Get the data pointer range considering the sampling rect offset and
|
||||
// size.
|
||||
Span<const uint8_t> range(
|
||||
map.GetData() + srcRect.y * size_t(stride) + srcRect.x * bpp,
|
||||
map->GetData() + srcRect.y * size_t(stride) + srcRect.x * bpp,
|
||||
std::max(srcRect.height - 1, 0) * size_t(stride) + srcRect.width * bpp);
|
||||
texDesc.cpuData = Some(range);
|
||||
// If the stride happens to be 4 byte aligned, assume that is the
|
||||
|
|
|
|||
|
|
@ -617,9 +617,11 @@ class DrawTargetWebgl : public DrawTarget, public SupportsWeakPtr {
|
|||
return mSharedContext->SupportsPattern(aPattern);
|
||||
}
|
||||
|
||||
Maybe<Rect> ComputeSimpleClipRect() const;
|
||||
bool SetSimpleClipRect();
|
||||
bool GenerateComplexClipMask();
|
||||
bool PrepareContext(bool aClipped = true);
|
||||
bool ShouldClip();
|
||||
|
||||
void DrawRectFallback(const Rect& aRect, const Pattern& aPattern,
|
||||
const DrawOptions& aOptions,
|
||||
|
|
|
|||
|
|
@ -146,10 +146,29 @@ already_AddRefed<ImageData> ImageData::ReadStructuredClone(
|
|||
!JS_ReadTypedArray(aReader, &dataArray)) {
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(dataArray.isObject());
|
||||
|
||||
JS::Rooted<JSObject*> arrayObj(aCx, &dataArray.toObject());
|
||||
RefPtr<ImageData> imageData = new ImageData(aGlobal, width, height, arrayObj);
|
||||
JS::Rooted<JSObject*> dataObj(aCx, &dataArray.toObject());
|
||||
RootedSpiderMonkeyInterface<Uint8ClampedArray> data(aCx);
|
||||
if (!data.Init(dataObj)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Maybe<size_t> maybeLength = data.ProcessData(
|
||||
[&](const Span<uint8_t>& aData, JS::AutoCheckCannotGC&& nogc) {
|
||||
return Some(aData.Length());
|
||||
});
|
||||
if (maybeLength.isNothing()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CheckedInt<uint32_t> calculatedLength =
|
||||
CheckedInt<uint32_t>(width) * height * 4;
|
||||
if (!calculatedLength.isValid() ||
|
||||
size_t(calculatedLength.value()) != maybeLength.value()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<ImageData> imageData = new ImageData(aGlobal, width, height, dataObj);
|
||||
return imageData.forget();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -391,8 +391,8 @@ static bool HasColorAndAlpha(const WebGLTexelFormat format) {
|
|||
}
|
||||
|
||||
bool TexUnpackBlob::ConvertIfNeeded(
|
||||
const WebGLContext* const webgl, const uint32_t rowLength,
|
||||
const uint32_t rowCount, WebGLTexelFormat srcFormat,
|
||||
const WebGLContext* const webgl, const size_t rowLength,
|
||||
const size_t rowCount, WebGLTexelFormat srcFormat,
|
||||
const uint8_t* const srcBegin, const ptrdiff_t srcStride,
|
||||
WebGLTexelFormat dstFormat, const ptrdiff_t dstStride,
|
||||
const uint8_t** const out_begin,
|
||||
|
|
@ -469,7 +469,7 @@ bool TexUnpackBlob::ConvertIfNeeded(
|
|||
|
||||
////
|
||||
|
||||
const auto dstTotalBytes = CheckedUint32(rowCount) * dstStride;
|
||||
const auto dstTotalBytes = CheckedInt<size_t>(rowCount) * dstStride;
|
||||
if (!dstTotalBytes.isValid()) {
|
||||
webgl->ErrorOutOfMemory("Calculation failed.");
|
||||
return false;
|
||||
|
|
@ -855,9 +855,14 @@ bool TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec,
|
|||
: dom::PredefinedColorSpace::Srgb;
|
||||
bool sameColorSpace = (srcColorSpace == dstColorSpace);
|
||||
|
||||
const auto reason = BlitPreventReason(
|
||||
Maybe<std::string> reason;
|
||||
if (!webgl->IsUploadableSdType(sd)) {
|
||||
reason = Some(std::string("Unsupported surface descriptor type"));
|
||||
} else {
|
||||
reason = BlitPreventReason(
|
||||
level, {xOffset, yOffset, zOffset}, dui->internalFormat, pi, mDesc,
|
||||
webgl->mOptionalRenderableFormatBits, sameColorSpace);
|
||||
}
|
||||
if (reason) {
|
||||
webgl->GeneratePerfWarning(
|
||||
"Failed to hit GPU-copy fast-path."
|
||||
|
|
|
|||
|
|
@ -65,8 +65,8 @@ class TexUnpackBlob {
|
|||
virtual ~TexUnpackBlob() = default;
|
||||
|
||||
protected:
|
||||
bool ConvertIfNeeded(const WebGLContext*, const uint32_t rowLength,
|
||||
const uint32_t rowCount, WebGLTexelFormat srcFormat,
|
||||
bool ConvertIfNeeded(const WebGLContext*, const size_t rowLength,
|
||||
const size_t rowCount, WebGLTexelFormat srcFormat,
|
||||
const uint8_t* const srcBegin, const ptrdiff_t srcStride,
|
||||
WebGLTexelFormat dstFormat, const ptrdiff_t dstStride,
|
||||
|
||||
|
|
|
|||
|
|
@ -630,50 +630,6 @@ RefPtr<WebGLContext> WebGLContext::Create(HostWebGLContext* host,
|
|||
|
||||
// -
|
||||
|
||||
const auto UploadableSdTypes = [&]() {
|
||||
webgl::EnumMask<layers::SurfaceDescriptor::Type> types;
|
||||
types[layers::SurfaceDescriptor::TSurfaceDescriptorBuffer] = true;
|
||||
// Only support canvas surface interchange if using AC2D. This guarantees
|
||||
// that WebGL and AC2D commands are sequenced and processed on the same
|
||||
// thread, so that there is no mal-ordering between AC2D and WebGL
|
||||
// processing. We can flush out AC2D commands to produce a surface in time
|
||||
// for WebGL to use without requiring any blocking to occur.
|
||||
types[layers::SurfaceDescriptor::TSurfaceDescriptorCanvasSurface] =
|
||||
gfx::gfxVars::UseAcceleratedCanvas2D();
|
||||
// This is conditional on not using the Compositor thread because we may
|
||||
// need to synchronize with the RDD process over the PVideoBridge protocol
|
||||
// to wait for the texture to be available in the compositor process. We
|
||||
// cannot block on the Compositor thread, so in that configuration, we would
|
||||
// prefer to do the readback from the RDD which is guaranteed to work, and
|
||||
// only block the owning thread for WebGL.
|
||||
const bool offCompositorThread = gfx::gfxVars::UseCanvasRenderThread() ||
|
||||
!gfx::gfxVars::SupportsThreadsafeGL();
|
||||
types[layers::SurfaceDescriptor::TSurfaceDescriptorGPUVideo] =
|
||||
offCompositorThread;
|
||||
// Similarly to the PVideoBridge protocol, we may need to synchronize with
|
||||
// the content process over the PCompositorManager protocol to wait for the
|
||||
// shared surface to be available in the compositor process, and we cannot
|
||||
// block on the Compositor thread.
|
||||
types[layers::SurfaceDescriptor::TSurfaceDescriptorExternalImage] =
|
||||
offCompositorThread;
|
||||
if (webgl->gl->IsANGLE()) {
|
||||
types[layers::SurfaceDescriptor::TSurfaceDescriptorD3D10] = true;
|
||||
types[layers::SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr] = true;
|
||||
}
|
||||
if (kIsMacOS) {
|
||||
types[layers::SurfaceDescriptor::TSurfaceDescriptorMacIOSurface] = true;
|
||||
}
|
||||
if (kIsAndroid) {
|
||||
types[layers::SurfaceDescriptor::TSurfaceTextureDescriptor] = true;
|
||||
}
|
||||
if (kIsLinux) {
|
||||
types[layers::SurfaceDescriptor::TSurfaceDescriptorDMABuf] = true;
|
||||
}
|
||||
return types;
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
constexpr GLenum SHADER_TYPES[] = {
|
||||
LOCAL_GL_VERTEX_SHADER,
|
||||
LOCAL_GL_FRAGMENT_SHADER,
|
||||
|
|
@ -709,7 +665,7 @@ RefPtr<WebGLContext> WebGLContext::Create(HostWebGLContext* host,
|
|||
|
||||
out->options = webgl->mOptions;
|
||||
out->limits = *webgl->mLimits;
|
||||
out->uploadableSdTypes = UploadableSdTypes();
|
||||
out->uploadableSdTypes = webgl->mUploadableSdTypes;
|
||||
out->vendor = webgl->gl->Vendor();
|
||||
out->optionalRenderableFormatBits = webgl->mOptionalRenderableFormatBits;
|
||||
|
||||
|
|
@ -811,6 +767,58 @@ void WebGLContext::FinishInit() {
|
|||
|
||||
gl->ResetSyncCallCount("WebGLContext Initialization");
|
||||
LoseLruContextIfLimitExceeded();
|
||||
|
||||
InitUploadableSdTypes();
|
||||
}
|
||||
|
||||
void WebGLContext::InitUploadableSdTypes() {
|
||||
webgl::EnumMask<layers::SurfaceDescriptor::Type> types;
|
||||
types[layers::SurfaceDescriptor::TSurfaceDescriptorBuffer] = true;
|
||||
// Only support canvas surface interchange if using AC2D. This guarantees
|
||||
// that WebGL and AC2D commands are sequenced and processed on the same
|
||||
// thread, so that there is no mal-ordering between AC2D and WebGL
|
||||
// processing. We can flush out AC2D commands to produce a surface in time
|
||||
// for WebGL to use without requiring any blocking to occur.
|
||||
types[layers::SurfaceDescriptor::TSurfaceDescriptorCanvasSurface] =
|
||||
gfx::gfxVars::UseAcceleratedCanvas2D();
|
||||
// This is conditional on not using the Compositor thread because we may
|
||||
// need to synchronize with the RDD process over the PVideoBridge protocol
|
||||
// to wait for the texture to be available in the compositor process. We
|
||||
// cannot block on the Compositor thread, so in that configuration, we would
|
||||
// prefer to do the readback from the RDD which is guaranteed to work, and
|
||||
// only block the owning thread for WebGL.
|
||||
const bool offCompositorThread = gfx::gfxVars::UseCanvasRenderThread() ||
|
||||
!gfx::gfxVars::SupportsThreadsafeGL();
|
||||
types[layers::SurfaceDescriptor::TSurfaceDescriptorGPUVideo] =
|
||||
offCompositorThread;
|
||||
// Similarly to the PVideoBridge protocol, we may need to synchronize with
|
||||
// the content process over the PCompositorManager protocol to wait for the
|
||||
// shared surface to be available in the compositor process, and we cannot
|
||||
// block on the Compositor thread.
|
||||
types[layers::SurfaceDescriptor::TSurfaceDescriptorExternalImage] =
|
||||
offCompositorThread;
|
||||
if (gl->IsANGLE()) {
|
||||
types[layers::SurfaceDescriptor::TSurfaceDescriptorD3D10] = true;
|
||||
types[layers::SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr] = true;
|
||||
}
|
||||
if (kIsMacOS) {
|
||||
types[layers::SurfaceDescriptor::TSurfaceDescriptorMacIOSurface] = true;
|
||||
}
|
||||
if (kIsAndroid) {
|
||||
types[layers::SurfaceDescriptor::TSurfaceTextureDescriptor] = true;
|
||||
}
|
||||
if (kIsLinux) {
|
||||
types[layers::SurfaceDescriptor::TSurfaceDescriptorDMABuf] = true;
|
||||
}
|
||||
|
||||
mUploadableSdTypes = types;
|
||||
}
|
||||
|
||||
bool WebGLContext::IsUploadableSdType(
|
||||
const layers::SurfaceDescriptor& sd) const {
|
||||
// If the WebGLContext is remote, then validate that the SD is an allowed
|
||||
// type.
|
||||
return !bool(mHost) || mUploadableSdTypes[sd.type()];
|
||||
}
|
||||
|
||||
void WebGLContext::SetCompositableHost(
|
||||
|
|
@ -2787,6 +2795,23 @@ webgl::ExplicitPixelPackingState::ForUseWith(
|
|||
const Maybe<size_t> bytesPerRowStrideOverride) {
|
||||
auto state = stateOrZero;
|
||||
|
||||
// Enforce the GLES alignmentInTypeElems invariant. ElemsPerRowStride below
|
||||
// assumes a in {1,2,4,8}. Callers at IPC entry points validate this but
|
||||
// alignmentInTypeElems is deserialized from IPC, so guard it here too.
|
||||
switch (state.alignmentInTypeElems) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
break;
|
||||
default: {
|
||||
const auto text = nsPrintfCString(
|
||||
"PACK/UNPACK_ALIGNMENT must be one of [1,2,4,8], was %u.",
|
||||
state.alignmentInTypeElems);
|
||||
return Err(mozilla::ToString(text));
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsTexTarget3D(target)) {
|
||||
state.skipImages = 0;
|
||||
state.imageHeight = 0;
|
||||
|
|
@ -2892,7 +2917,9 @@ webgl::ExplicitPixelPackingState::ForUseWith(
|
|||
|
||||
const auto elemsPerRowStride = ElemsPerRowStride();
|
||||
const auto bytesPerRowStride = pii.bytesPerElement * elemsPerRowStride;
|
||||
if (!bytesPerRowStride.isValid()) {
|
||||
const auto maxBytesPerRow = StaticPrefs::webgl_max_bytes_per_row();
|
||||
if (!bytesPerRowStride.isValid() ||
|
||||
(maxBytesPerRow > 0 && bytesPerRowStride.value() > maxBytesPerRow)) {
|
||||
return Err("ROW_LENGTH or width too large for packing.");
|
||||
}
|
||||
metrics.bytesPerRowStride = bytesPerRowStride.value();
|
||||
|
|
|
|||
|
|
@ -292,6 +292,7 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr {
|
|||
WebGLContextOptions mOptions;
|
||||
const uint32_t mPrincipalKey;
|
||||
Maybe<webgl::Limits> mLimits;
|
||||
webgl::EnumMask<layers::SurfaceDescriptor::Type> mUploadableSdTypes;
|
||||
const uint32_t mMaxVertIdsPerDraw =
|
||||
StaticPrefs::webgl_max_vert_ids_per_draw();
|
||||
|
||||
|
|
@ -340,6 +341,7 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr {
|
|||
webgl::OptionalRenderableFormatBits mOptionalRenderableFormatBits =
|
||||
webgl::OptionalRenderableFormatBits{0};
|
||||
void FinishInit();
|
||||
void InitUploadableSdTypes();
|
||||
|
||||
protected:
|
||||
WebGLContext(HostWebGLContext*, const webgl::InitContextDesc&);
|
||||
|
|
@ -995,6 +997,8 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr {
|
|||
|
||||
bool IsFormatValidForFB(TexInternalFormat format) const;
|
||||
|
||||
bool IsUploadableSdType(const layers::SurfaceDescriptor& sd) const;
|
||||
|
||||
protected:
|
||||
// -------------------------------------------------------------------------
|
||||
// WebGL extensions (implemented in WebGLContextExtensions.cpp)
|
||||
|
|
|
|||
|
|
@ -1133,6 +1133,18 @@ webgl::ReadPixelsResult WebGLContext::ReadPixelsImpl(
|
|||
|
||||
//////
|
||||
|
||||
// Reject invalid pack alignment.
|
||||
switch (desc.packState.alignmentInTypeElems) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
break; // all good
|
||||
default:
|
||||
ErrorInvalidValue("pack alignment must be 1, 2, 4, or 8.");
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto& srcOffset = desc.srcOffset;
|
||||
const auto& size = desc.size;
|
||||
|
||||
|
|
|
|||
|
|
@ -487,23 +487,28 @@ bool ShaderValidatorResults::CanLinkTo(const ShaderValidatorResults& vert,
|
|||
size_t ShaderValidatorResults::SizeOfIncludingThis(
|
||||
const MallocSizeOf fnSizeOf) const {
|
||||
auto ret = fnSizeOf(this);
|
||||
ret += mInfoLog.size();
|
||||
ret += mObjectCode.size();
|
||||
|
||||
for (const auto& cur : mAttributes) {
|
||||
ret += fnSizeOf(&cur);
|
||||
// std::string heap allocations are not measured here because:
|
||||
// 1. Small String Optimization (SSO) means data() may point to inline
|
||||
// storage within the std::string object (already counted in
|
||||
// fnSizeOf(this))
|
||||
// 2. There's no standard way to distinguish SSO from heap-allocated strings
|
||||
// 3. Calling fnSizeOf on a pointer to inline storage is inappropriate
|
||||
|
||||
if (!mAttributes.empty()) {
|
||||
ret += fnSizeOf(mAttributes.data());
|
||||
}
|
||||
for (const auto& cur : mInterfaceBlocks) {
|
||||
ret += fnSizeOf(&cur);
|
||||
if (!mInterfaceBlocks.empty()) {
|
||||
ret += fnSizeOf(mInterfaceBlocks.data());
|
||||
}
|
||||
for (const auto& cur : mOutputVariables) {
|
||||
ret += fnSizeOf(&cur);
|
||||
if (!mOutputVariables.empty()) {
|
||||
ret += fnSizeOf(mOutputVariables.data());
|
||||
}
|
||||
for (const auto& cur : mUniforms) {
|
||||
ret += fnSizeOf(&cur);
|
||||
if (!mUniforms.empty()) {
|
||||
ret += fnSizeOf(mUniforms.data());
|
||||
}
|
||||
for (const auto& cur : mVaryings) {
|
||||
ret += fnSizeOf(&cur);
|
||||
if (!mVaryings.empty()) {
|
||||
ret += fnSizeOf(mVaryings.data());
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -55,8 +55,9 @@ bool ClientManagerChild::DeallocPClientNavigateOpChild(
|
|||
mozilla::ipc::IPCResult ClientManagerChild::RecvPClientNavigateOpConstructor(
|
||||
PClientNavigateOpChild* aActor,
|
||||
const ClientNavigateOpConstructorArgs& aArgs) {
|
||||
auto actor = static_cast<ClientNavigateOpChild*>(aActor);
|
||||
actor->Init(aArgs);
|
||||
RefPtr<mozilla::ipc::ActorLifecycleProxy> proxy = aActor->GetLifecycleProxy();
|
||||
auto* actor = static_cast<ClientNavigateOpChild*>(aActor);
|
||||
actor->Init(aArgs, proxy);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -152,7 +152,8 @@ NS_IMPL_ISUPPORTS(NavigateLoadListener, nsIWebProgressListener,
|
|||
} // anonymous namespace
|
||||
|
||||
RefPtr<ClientOpPromise> ClientNavigateOpChild::DoNavigate(
|
||||
const ClientNavigateOpConstructorArgs& aArgs) {
|
||||
const ClientNavigateOpConstructorArgs& aArgs,
|
||||
mozilla::ipc::ActorLifecycleProxy* aProxy) {
|
||||
nsCOMPtr<nsPIDOMWindowInner> window;
|
||||
|
||||
// Navigating the target client window will result in the original
|
||||
|
|
@ -278,6 +279,12 @@ RefPtr<ClientOpPromise> ClientNavigateOpChild::DoNavigate(
|
|||
return ClientOpPromise::CreateAndReject(result, __func__);
|
||||
}
|
||||
|
||||
if (!aProxy->Get() || !CanSend()) {
|
||||
CopyableErrorResult result;
|
||||
result.ThrowInvalidStateError("Unknown Client");
|
||||
return ClientOpPromise::CreateAndReject(result, __func__);
|
||||
}
|
||||
|
||||
RefPtr<ClientOpPromise::Private> promise =
|
||||
new ClientOpPromise::Private(__func__);
|
||||
|
||||
|
|
@ -305,8 +312,12 @@ void ClientNavigateOpChild::ActorDestroy(ActorDestroyReason aReason) {
|
|||
mPromiseRequestHolder.DisconnectIfExists();
|
||||
}
|
||||
|
||||
void ClientNavigateOpChild::Init(const ClientNavigateOpConstructorArgs& aArgs) {
|
||||
RefPtr<ClientOpPromise> promise = DoNavigate(aArgs);
|
||||
void ClientNavigateOpChild::Init(const ClientNavigateOpConstructorArgs& aArgs,
|
||||
mozilla::ipc::ActorLifecycleProxy* aProxy) {
|
||||
RefPtr<ClientOpPromise> promise = DoNavigate(aArgs, aProxy);
|
||||
if (!aProxy->Get() || !CanSend()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Normally we get the event target from the window in DoNavigate(). If a
|
||||
// failure occurred, though, we may need to fall back to the current thread
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@ class ClientNavigateOpChild final : public PClientNavigateOpChild {
|
|||
nsCOMPtr<nsISerialEventTarget> mSerialEventTarget;
|
||||
|
||||
[[nodiscard]] RefPtr<ClientOpPromise> DoNavigate(
|
||||
const ClientNavigateOpConstructorArgs& aArgs);
|
||||
const ClientNavigateOpConstructorArgs& aArgs,
|
||||
mozilla::ipc::ActorLifecycleProxy* aProxy);
|
||||
|
||||
// PClientNavigateOpChild interface
|
||||
void ActorDestroy(ActorDestroyReason aReason) override;
|
||||
|
|
@ -25,7 +26,8 @@ class ClientNavigateOpChild final : public PClientNavigateOpChild {
|
|||
ClientNavigateOpChild() = default;
|
||||
~ClientNavigateOpChild() = default;
|
||||
|
||||
void Init(const ClientNavigateOpConstructorArgs& aArgs);
|
||||
void Init(const ClientNavigateOpConstructorArgs& aArgs,
|
||||
mozilla::ipc::ActorLifecycleProxy* aProxy);
|
||||
};
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
|
|
|||
|
|
@ -520,11 +520,12 @@ RefPtr<ClientOpPromise> ClientSource::Focus(const ClientFocusArgs& aArgs) {
|
|||
return ClientOpPromise::CreateAndReject(rv, __func__);
|
||||
}
|
||||
nsCOMPtr<nsPIDOMWindowOuter> outer;
|
||||
nsPIDOMWindowInner* inner = GetInnerWindow();
|
||||
nsCOMPtr<nsPIDOMWindowInner> inner = GetInnerWindow();
|
||||
nsIDocShell* docshell = nullptr;
|
||||
if (inner) {
|
||||
outer = inner->GetOuterWindow();
|
||||
} else {
|
||||
nsIDocShell* docshell = GetDocShell();
|
||||
docshell = GetDocShell();
|
||||
if (docshell) {
|
||||
outer = docshell->GetWindow();
|
||||
}
|
||||
|
|
@ -537,9 +538,48 @@ RefPtr<ClientOpPromise> ClientSource::Focus(const ClientFocusArgs& aArgs) {
|
|||
}
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Inlined from `ClientSource::SnapshotWindowState()`:
|
||||
// Should not be necessary after bug 543435. Clean this up in bug 2025284.
|
||||
if (docshell) {
|
||||
// Force the creation of the initial document if it does not yet exist.
|
||||
if (!docshell->GetDocument()) {
|
||||
CopyableErrorResult rv;
|
||||
rv.ThrowInvalidStateError("No document available.");
|
||||
return ClientOpPromise::CreateAndReject(rv, __func__);
|
||||
}
|
||||
inner = GetInnerWindow();
|
||||
}
|
||||
|
||||
nsFocusManager::FocusWindow(outer, aArgs.callerType());
|
||||
|
||||
Result<ClientState, ErrorResult> state = SnapshotState();
|
||||
Result<ClientState, ErrorResult> state =
|
||||
[&]() -> Result<ClientState, ErrorResult> {
|
||||
if (!inner) {
|
||||
// Inlined from `ClientSource::SnapshotWindowState()`:
|
||||
return ClientState(ClientWindowState(VisibilityState::Hidden, TimeStamp(),
|
||||
StorageAccess::eDeny, false));
|
||||
}
|
||||
if (inner->GetClientSource() == this) {
|
||||
// The pointer comparison assumes that an inner window
|
||||
// cannot gain a new ClientSource other than this same
|
||||
// `ClientSource` having moved from a docshell owner to an
|
||||
// inner window owner gained via `outer`, so we don't need to worry
|
||||
// about a newly-allocated ClientSource occupying the same
|
||||
// memory as the one pointed to by `this`. That is, in the case
|
||||
// of the pointers being unequal, `inner->GetClientSource()`
|
||||
// returns `nullptr` and `this` is an invalid pointer.
|
||||
// Per [expr.eq], it's not UB to compare a pointer to a deleted
|
||||
// object, since no pointer comparisons are UB anymore. The
|
||||
// case about pointer-past-end for a different object being
|
||||
// _unspecified_ behavior does not apply here.
|
||||
return SnapshotState();
|
||||
}
|
||||
ErrorResult rv;
|
||||
rv.ThrowInvalidStateError("Client destroyed during focus");
|
||||
return Err(std::move(rv));
|
||||
}();
|
||||
|
||||
if (state.isErr()) {
|
||||
return ClientOpPromise::CreateAndReject(
|
||||
CopyableErrorResult(state.unwrapErr()), __func__);
|
||||
|
|
|
|||
|
|
@ -424,6 +424,7 @@ class ConsoleRunnable : public StructuredCloneHolderBase {
|
|||
}
|
||||
|
||||
Sequence<JS::Value> arguments;
|
||||
SequenceRooter<JS::Value> rooter(aCx, &arguments);
|
||||
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
JS::Rooted<JS::Value> value(aCx);
|
||||
|
|
|
|||
|
|
@ -196,10 +196,17 @@ void CookieStoreNotifier::DispatchEvent(const CookieListItem& aItem,
|
|||
void CookieStoreNotifier::FireDelayedDOMEvents() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
RefPtr<CookieStoreNotifier> kungFuDeathGrip(this);
|
||||
|
||||
nsTArray<RefPtr<Event>> delayedDOMEvents;
|
||||
delayedDOMEvents.SwapElements(mDelayedDOMEvents);
|
||||
|
||||
for (Event* event : delayedDOMEvents) {
|
||||
// mCookieStore is a raw pointer cleared by Disentangle().
|
||||
if (!mCookieStore) {
|
||||
break;
|
||||
}
|
||||
|
||||
mCookieStore->DispatchEvent(*event);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2134,9 +2134,13 @@ const TypedEventHandler* EventListenerManager::GetTypedEventHandler(
|
|||
}
|
||||
|
||||
JSEventHandler* jsEventHandler = listener->GetJSEventHandler();
|
||||
|
||||
Maybe<RefPtr<JSEventHandler>> pin;
|
||||
if (listener->mHandlerIsString) {
|
||||
CompileEventHandlerInternal(listener, aEventName, nullptr, nullptr);
|
||||
pin.emplace(jsEventHandler);
|
||||
if (NS_FAILED(CompileEventHandlerInternal(listener, aEventName, nullptr,
|
||||
nullptr))) {
|
||||
listener = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const TypedEventHandler& typedHandler =
|
||||
|
|
|
|||
|
|
@ -788,7 +788,8 @@ nsresult IMEContentObserver::MaybeHandleSelectionEvent(
|
|||
bool IMEContentObserver::OnMouseButtonEvent(nsPresContext& aPresContext,
|
||||
WidgetMouseEvent& aMouseEvent) {
|
||||
if (!mIMENotificationRequests ||
|
||||
!mIMENotificationRequests->WantMouseButtonEventOnChar()) {
|
||||
!mIMENotificationRequests->contains(
|
||||
IMENotificationRequest::MouseEventOnChar)) {
|
||||
return false;
|
||||
}
|
||||
if (!aMouseEvent.IsTrusted() || aMouseEvent.DefaultPrevented() ||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ class IMEContentObserver final : public nsStubMutationObserver,
|
|||
using SelectionChangeData = widget::IMENotification::SelectionChangeData;
|
||||
using TextChangeData = widget::IMENotification::TextChangeData;
|
||||
using TextChangeDataBase = widget::IMENotification::TextChangeDataBase;
|
||||
using IMENotificationRequest = widget::IMENotificationRequest;
|
||||
using IMENotificationRequests = widget::IMENotificationRequests;
|
||||
using IMEMessage = widget::IMEMessage;
|
||||
enum class ForRemoval : bool { No, Yes };
|
||||
|
|
@ -163,7 +164,8 @@ class IMEContentObserver final : public nsStubMutationObserver,
|
|||
bool IsEditorHandlingEventForComposition() const;
|
||||
bool KeepAliveDuringDeactive() const {
|
||||
return mIMENotificationRequests &&
|
||||
mIMENotificationRequests->WantDuringDeactive();
|
||||
mIMENotificationRequests->contains(
|
||||
IMENotificationRequest::NotifyDuringInactive);
|
||||
}
|
||||
[[nodiscard]] bool EditorIsTextEditor() const {
|
||||
return mEditorBase && mEditorBase->IsTextEditor();
|
||||
|
|
@ -328,12 +330,13 @@ class IMEContentObserver final : public nsStubMutationObserver,
|
|||
void UnregisterObservers();
|
||||
void FlushMergeableNotifications();
|
||||
bool NeedsTextChangeNotification() const {
|
||||
return mIMENotificationRequests &&
|
||||
mIMENotificationRequests->WantTextChange();
|
||||
return mIMENotificationRequests && mIMENotificationRequests->contains(
|
||||
IMENotificationRequest::TextChange);
|
||||
}
|
||||
bool NeedsPositionChangeNotification() const {
|
||||
return mIMENotificationRequests &&
|
||||
mIMENotificationRequests->WantPositionChanged();
|
||||
mIMENotificationRequests->contains(
|
||||
IMENotificationRequest::PositionChange);
|
||||
}
|
||||
void ClearPendingNotifications() {
|
||||
mNeedsToNotifyIMEOfFocusSet = false;
|
||||
|
|
|
|||
|
|
@ -198,13 +198,12 @@ void IMEStateManager::OnFocusMovedBetweenBrowsers(BrowserParent* aBlur,
|
|||
RefPtr<TextComposition> composition =
|
||||
sTextCompositions->GetCompositionFor(oldWidget);
|
||||
if (composition) {
|
||||
MOZ_LOG(
|
||||
sISMLog, LogLevel::Debug,
|
||||
(" OnFocusMovedBetweenBrowsers(), requesting to commit "
|
||||
"composition to "
|
||||
"the (previous) focused widget (would request=%s)",
|
||||
GetBoolName(
|
||||
!oldWidget->IMENotificationRequestsRef().WantDuringDeactive())));
|
||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||
(" OnFocusMovedBetweenBrowsers(), requesting to commit "
|
||||
"composition to "
|
||||
"the (previous) focused widget (would request=%s)",
|
||||
GetBoolName(!oldWidget->IMENotificationRequestsRef().contains(
|
||||
IMENotificationRequest::NotifyDuringInactive))));
|
||||
NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, oldWidget,
|
||||
composition->GetBrowserParent());
|
||||
}
|
||||
|
|
@ -727,8 +726,8 @@ nsresult IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
|
|||
// such case, sFocusedIMEWidget is perhaps nullptr). For example, IME
|
||||
// may receive only blur notification but still has composition.
|
||||
// We need to clean up only the oldWidget's composition state here.
|
||||
if (aPresContext ||
|
||||
!oldWidget->IMENotificationRequestsRef().WantDuringDeactive()) {
|
||||
if (aPresContext || !oldWidget->IMENotificationRequestsRef().contains(
|
||||
IMENotificationRequest::NotifyDuringInactive)) {
|
||||
MOZ_LOG(
|
||||
sISMLog, LogLevel::Info,
|
||||
(" OnChangeFocusInternal(), requesting to commit composition to "
|
||||
|
|
|
|||
|
|
@ -66,21 +66,17 @@ namespace {
|
|||
// https://fetch.spec.whatwg.org/#concept-http-network-fetch
|
||||
// If stream is readable, then error stream with ...
|
||||
void AbortStream(JSContext* aCx, ReadableStream* aReadableStream,
|
||||
ErrorResult& aRv, JS::Handle<JS::Value> aReasonDetails) {
|
||||
AbortSignalImpl* aSignal, ErrorResult& aRv) {
|
||||
MOZ_ASSERT(aSignal->Aborted());
|
||||
|
||||
if (aReadableStream->State() != ReadableStream::ReaderState::Readable) {
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> value(aCx, aReasonDetails);
|
||||
JS::Rooted<JS::Value> reason(aCx);
|
||||
aSignal->GetReason(aCx, &reason);
|
||||
|
||||
if (aReasonDetails.isUndefined()) {
|
||||
RefPtr<DOMException> e = DOMException::Create(NS_ERROR_DOM_ABORT_ERR);
|
||||
if (!GetOrCreateDOMReflector(aCx, e, &value)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
aReadableStream->ErrorNative(aCx, value, aRv);
|
||||
aReadableStream->ErrorNative(aCx, reason, aRv);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
@ -533,12 +529,8 @@ already_AddRefed<Promise> FetchRequest(nsIGlobalObject* aGlobal,
|
|||
|
||||
if (signalImpl && signalImpl->Aborted()) {
|
||||
// Already aborted signal rejects immediately.
|
||||
JS::Rooted<JS::Value> reason(cx, signalImpl->RawReason());
|
||||
if (reason.get().isUndefined()) {
|
||||
aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> reason(cx);
|
||||
signalImpl->GetReason(cx, &reason);
|
||||
p->MaybeReject(reason);
|
||||
return p.forget();
|
||||
}
|
||||
|
|
@ -1422,16 +1414,15 @@ already_AddRefed<Promise> FetchBody<Derived>::ConsumeBody(
|
|||
DerivedClass()->GetSignalImplToConsumeBody();
|
||||
|
||||
if (signalImpl && signalImpl->Aborted()) {
|
||||
JS::Rooted<JS::Value> abortReason(aCx, signalImpl->RawReason());
|
||||
JS::Rooted<JS::Value> abortReason(aCx);
|
||||
signalImpl->GetReason(aCx, &abortReason);
|
||||
|
||||
if (abortReason.get().isUndefined()) {
|
||||
aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
|
||||
nsCOMPtr<nsIGlobalObject> global = DerivedClass()->GetParentObject();
|
||||
RefPtr<Promise> promise = Promise::Create(global, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> go = DerivedClass()->GetParentObject();
|
||||
|
||||
RefPtr<Promise> promise = Promise::Create(go, aRv);
|
||||
promise->MaybeReject(abortReason);
|
||||
return promise.forget();
|
||||
}
|
||||
|
|
@ -1572,11 +1563,9 @@ void FetchBody<Derived>::SetReadableStreamBody(JSContext* aCx,
|
|||
return;
|
||||
}
|
||||
|
||||
bool aborted = signalImpl->Aborted();
|
||||
if (aborted) {
|
||||
if (signalImpl->Aborted()) {
|
||||
IgnoredErrorResult result;
|
||||
JS::Rooted<JS::Value> abortReason(aCx, signalImpl->RawReason());
|
||||
AbortStream(aCx, mReadableStreamBody, result, abortReason);
|
||||
AbortStream(aCx, mReadableStreamBody, signalImpl, result);
|
||||
if (NS_WARN_IF(result.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -1632,8 +1621,7 @@ already_AddRefed<ReadableStream> FetchBody<Derived>::GetBody(JSContext* aCx,
|
|||
RefPtr<AbortSignalImpl> signalImpl = DerivedClass()->GetSignalImpl();
|
||||
if (signalImpl) {
|
||||
if (signalImpl->Aborted()) {
|
||||
JS::Rooted<JS::Value> abortReason(aCx, signalImpl->RawReason());
|
||||
AbortStream(aCx, body, aRv, abortReason);
|
||||
AbortStream(aCx, body, signalImpl, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -1733,16 +1721,7 @@ void FetchBody<Derived>::RunAbortAlgorithm() {
|
|||
JSContext* cx = jsapi.cx();
|
||||
|
||||
RefPtr<ReadableStream> body(mReadableStreamBody);
|
||||
IgnoredErrorResult result;
|
||||
|
||||
JS::Rooted<JS::Value> abortReason(cx);
|
||||
|
||||
AbortSignalImpl* signalImpl = Signal();
|
||||
if (signalImpl) {
|
||||
abortReason.set(signalImpl->RawReason());
|
||||
}
|
||||
|
||||
AbortStream(cx, body, result, abortReason);
|
||||
AbortStream(cx, body, Signal(), IgnoredErrorResult());
|
||||
}
|
||||
|
||||
template void FetchBody<Request>::RunAbortAlgorithm();
|
||||
|
|
|
|||
|
|
@ -89,6 +89,9 @@ IPCResult FetchParent::RecvFetchOp(FetchOpArgs&& aArgs) {
|
|||
FETCH_LOG(("FetchParent::RecvFetchOp [%p]", this));
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
if (mReceivedFetchOp.exchange(true)) {
|
||||
return IPC_FAIL(this, "FetchOp received more than once on this actor");
|
||||
}
|
||||
MOZ_ASSERT(!mIsDone);
|
||||
if (mActorDestroyed) {
|
||||
return IPC_OK();
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ class FetchParent final : public PFetchParent {
|
|||
|
||||
Atomic<bool> mIsDone{false};
|
||||
Atomic<bool> mActorDestroyed{false};
|
||||
Atomic<bool> mReceivedFetchOp{false};
|
||||
|
||||
nsCOMPtr<nsISerialEventTarget> mBackgroundEventTarget;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -123,6 +123,19 @@ template <typename T>
|
|||
|
||||
InternalResponse::~InternalResponse() = default;
|
||||
|
||||
void InternalResponse::SnapshotUnfilteredHeaders() {
|
||||
auto snapshot = [](InternalHeaders* aHeaders) {
|
||||
nsTArray<InternalHeaders::Entry> entries;
|
||||
aHeaders->GetEntries(entries);
|
||||
return MakeRefPtr<InternalHeaders>(std::move(entries), aHeaders->Guard());
|
||||
};
|
||||
if (mWrappedResponse) {
|
||||
mWrappedResponse->mHeaders = snapshot(mWrappedResponse->mHeaders);
|
||||
} else {
|
||||
mHeaders = snapshot(mHeaders);
|
||||
}
|
||||
}
|
||||
|
||||
InternalResponseMetadata InternalResponse::GetMetadata() {
|
||||
nsTArray<HeadersEntry> headers;
|
||||
HeadersGuardEnum headersGuard;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue