Compare commits

..

No commits in common. "ecne" and "ecne/140.8.0-2gnu1" have entirely different histories.

2373 changed files with 38198 additions and 92775 deletions

View file

@ -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=bebaa23317332c95734df76e25193c24a83a6840"]
[source."git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=2407441a2f67341a0e13b4ba6547555e387c671c"]
git = "https://github.com/mozilla/cubeb-coreaudio-rs"
rev = "bebaa23317332c95734df76e25193c24a83a6840"
rev = "2407441a2f67341a0e13b4ba6547555e387c671c"
replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/cubeb-pulse-rs?rev=8678dcab1c287de79c4c184ccc2e065bc62b70e2"]

View file

@ -263,7 +263,8 @@ jobs:
- mozilla-release
- mozilla-esr140
when:
- {weekday: 'Monday', hour: 5, minute: 0}
- {weekday: 'Monday', hour: 8, minute: 0}
- {weekday: 'Thursday', hour: 8, minute: 0}
- name: daily-beta-perf
job:

3
icecat/.gitignore vendored
View file

@ -373,6 +373,3 @@ toolkit/crashreporter/minidump-analyzer/analyzer-test/target/
# Ignore mozperftest artifacts folder
/artifacts/
# Ignore personal preferences files
CLAUDE.local.md

View file

@ -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-03-23
Merge day clobber 2026-01-12

4
icecat/Cargo.lock generated
View file

@ -1086,7 +1086,7 @@ dependencies = [
[[package]]
name = "coreaudio-sys-utils"
version = "0.1.0"
source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=bebaa23317332c95734df76e25193c24a83a6840#bebaa23317332c95734df76e25193c24a83a6840"
source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=2407441a2f67341a0e13b4ba6547555e387c671c#2407441a2f67341a0e13b4ba6547555e387c671c"
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=bebaa23317332c95734df76e25193c24a83a6840#bebaa23317332c95734df76e25193c24a83a6840"
source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=2407441a2f67341a0e13b4ba6547555e387c671c#2407441a2f67341a0e13b4ba6547555e387c671c"
dependencies = [
"atomic",
"audio-mixer",

View file

@ -23,7 +23,7 @@ using namespace mozilla::a11y;
// AccIterator
////////////////////////////////////////////////////////////////////////////////
AccIterator::AccIterator(LocalAccessible* aAccessible,
AccIterator::AccIterator(const LocalAccessible* aAccessible,
filters::FilterFuncPtr aFilterFunc)
: mFilterFunc(aFilterFunc) {
mState = new IteratorState(aAccessible);
@ -63,7 +63,7 @@ LocalAccessible* AccIterator::Next() {
////////////////////////////////////////////////////////////////////////////////
// nsAccIterator::IteratorState
AccIterator::IteratorState::IteratorState(LocalAccessible* aParent,
AccIterator::IteratorState::IteratorState(const LocalAccessible* aParent,
IteratorState* mParentState)
: mParent(aParent), mIndex(0), mParentState(mParentState) {}

View file

@ -42,7 +42,7 @@ class AccIterable {
*/
class AccIterator : public AccIterable {
public:
AccIterator(LocalAccessible* aRoot, filters::FilterFuncPtr aFilterFunc);
AccIterator(const LocalAccessible* aRoot, filters::FilterFuncPtr aFilterFunc);
virtual ~AccIterator();
/**
@ -57,10 +57,10 @@ class AccIterator : public AccIterable {
AccIterator& operator=(const AccIterator&);
struct IteratorState {
explicit IteratorState(LocalAccessible* aParent,
explicit IteratorState(const LocalAccessible* aParent,
IteratorState* mParentState = nullptr);
RefPtr<LocalAccessible> mParent;
const LocalAccessible* mParent;
int32_t mIndex;
IteratorState* mParentState;
};

View file

@ -71,14 +71,10 @@ void CachedTableAccessible::Invalidate(Accessible* aAcc) {
return;
}
Accessible* table = nsAccUtils::TableFor(aAcc);
while (table && table->IsTable()) {
if (Accessible* table = nsAccUtils::TableFor(aAcc)) {
// Destroy the instance (if any). We'll create a new one the next time it
// is requested. Climb up the heirarcy to invalidate parent tables as well.
// is requested.
sCachedTables->Remove(table);
// The table may be a direct child of another table, invalidate that one as
// well.
table = table->Parent();
}
}

View file

@ -536,7 +536,7 @@ static dom::Selection* GetDOMSelection(const nsIContent* aStartContent,
return startFrameSel ? &startFrameSel->NormalSelection() : nullptr;
}
std::pair<RefPtr<nsIContent>, uint32_t> TextLeafPoint::ToDOMPoint(
std::pair<nsIContent*, uint32_t> TextLeafPoint::ToDOMPoint(
bool aIncludeGenerated) const {
if (!(*this) || !mAcc->IsLocal()) {
MOZ_ASSERT_UNREACHABLE("Invalid point");

View file

@ -188,7 +188,7 @@ class TextLeafPoint final {
/**
* Translate given TextLeafPoint into a DOM point.
*/
MOZ_CAN_RUN_SCRIPT std::pair<RefPtr<nsIContent>, uint32_t> ToDOMPoint(
MOZ_CAN_RUN_SCRIPT std::pair<nsIContent*, uint32_t> ToDOMPoint(
bool aIncludeGenerated = true) const;
private:

View file

@ -1768,12 +1768,11 @@ void DocAccessible::DoInitialUpdate() {
}
#endif
// Fire a reorder event on the OuterDocAccessible after the document tree is
// constructed. Note that since this reorder event is processed by the parent
// document, events targeted to this child document may be fired prior to this
// reorder event. We don't fire a reorder event for remote documents; the
// parent process handles that.
if (!IPCDoc() && !IsRoot()) {
// Fire reorder event after the document tree is constructed. Note, since
// this reorder event is processed by parent document then events targeted to
// this document may be fired prior to this reorder event. If this is
// a problem then consider to keep event processing per tab document.
if (!IsRoot()) {
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(LocalParent());
ParentDocument()->FireDelayedEvent(reorderEvent);
}

View file

@ -859,15 +859,16 @@ void HyperTextAccessible::ReplaceText(const nsAString& aText) {
return;
}
RefPtr<EditorBase> editorBase = GetEditor();
SetSelectionBoundsAt(TextLeafRange::kRemoveAllExistingSelectedRanges, 0,
CharacterCount());
if (editorBase) {
DebugOnly<nsresult> rv = editorBase->InsertTextAsAction(aText);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to insert the new text");
RefPtr<EditorBase> editorBase = GetEditor();
if (!editorBase) {
return;
}
DebugOnly<nsresult> rv = editorBase->InsertTextAsAction(aText);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to insert the new text");
}
void HyperTextAccessible::InsertText(const nsAString& aText,

View file

@ -50,7 +50,6 @@ DocAccessibleParent::DocAccessibleParent()
mTopLevel(false),
mTopLevelInContentProcess(false),
mShutdown(false),
mIsInitialTreeDone(false),
mFocus(0),
mCaretId(0),
mCaretOffset(-1),
@ -118,11 +117,6 @@ 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();
@ -151,9 +145,7 @@ mozilla::ipc::IPCResult DocAccessibleParent::ProcessShowEvent(
// Otherwise, clients might crawl the incomplete subtree and they won't get
// mutation events for the remaining pieces.
if (aComplete || root != child) {
if (!AttachChild(parent, childIdx, child)) {
return IPC_FAIL(this, "failed to attach child");
}
AttachChild(parent, childIdx, child);
}
}
@ -182,9 +174,7 @@ mozilla::ipc::IPCResult DocAccessibleParent::ProcessShowEvent(
MOZ_ASSERT(rootParent);
root = GetAccessible(mPendingShowChild);
MOZ_ASSERT(root);
if (!AttachChild(rootParent, mPendingShowIndex, root)) {
return IPC_FAIL(this, "failed to attach pending show child");
}
AttachChild(rootParent, mPendingShowIndex, root);
mPendingShowChild = 0;
mPendingShowParent = 0;
mPendingShowIndex = 0;
@ -228,11 +218,6 @@ 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.
@ -249,11 +234,6 @@ RemoteAccessible* DocAccessibleParent::CreateAcc(
return nullptr;
}
if (aAccData.GenericTypes() & eDocument) {
MOZ_ASSERT_UNREACHABLE("Invalid acc type");
return nullptr;
}
newProxy = new RemoteAccessible(aAccData.ID(), this, aAccData.Role(),
aAccData.Type(), aAccData.GenericTypes(),
aAccData.RoleMapEntryIndex());
@ -266,20 +246,9 @@ RemoteAccessible* DocAccessibleParent::CreateAcc(
return newProxy;
}
bool DocAccessibleParent::AttachChild(RemoteAccessible* aParent,
void DocAccessibleParent::AttachChild(RemoteAccessible* aParent,
uint32_t aIndex,
RemoteAccessible* aChild) {
if (aChild->RemoteParent()) {
MOZ_ASSERT_UNREACHABLE(
"Attempt to attach child which already has a parent!");
return false;
}
if (aParent == aChild) {
MOZ_ASSERT_UNREACHABLE("Attempt to make an accessible its own child!");
return false;
}
aParent->AddChildAt(aIndex, aChild);
aChild->SetParent(aParent);
// ProxyCreated might have already been called if aChild is being moved.
@ -300,16 +269,11 @@ bool DocAccessibleParent::AttachChild(RemoteAccessible* aParent,
}
MOZ_ASSERT(bridge->GetEmbedderAccessibleDoc() == this);
if (DocAccessibleParent* childDoc = bridge->GetDocAccessibleParent()) {
MOZ_DIAGNOSTIC_ASSERT(!childDoc->RemoteParent(),
"Pending OOP child doc shouldn't have parent "
"once new OuterDoc is attached");
AddChildDoc(childDoc, aChild->ID(), false);
}
return true;
});
}
return true;
}
void DocAccessibleParent::ShutdownOrPrepareForMove(RemoteAccessible* aAcc) {
@ -322,10 +286,6 @@ void DocAccessibleParent::ShutdownOrPrepareForMove(RemoteAccessible* aAcc) {
// the show event. For now, clear all of them by moving them to a temporary.
auto children{std::move(aAcc->mChildren)};
for (RemoteAccessible* child : children) {
if (child == aAcc) {
MOZ_ASSERT_UNREACHABLE(
"Somehow an accessible got added as a child of itself!");
}
ShutdownOrPrepareForMove(child);
}
}
@ -643,18 +603,6 @@ mozilla::ipc::IPCResult DocAccessibleParent::RecvMutationEvents(
mozilla::ipc::IPCResult DocAccessibleParent::RecvRequestAckMutationEvents() {
if (!mShutdown) {
if (!mIsInitialTreeDone) {
// This is the first request for an ACK, which means we now have the
// initial tree.
mIsInitialTreeDone = true;
// If this document is already bound to its embedder, fire a reorder event
// to notify the client that the embedded document is available. If not,
// this will be handled when this document is bound in AddChildDoc.
if (RemoteAccessible* parent = RemoteParent()) {
parent->Document()->FireEvent(parent,
nsIAccessibleEvent::EVENT_REORDER);
}
}
Unused << SendAckMutationEvents();
}
return IPC_OK();
@ -916,10 +864,7 @@ mozilla::ipc::IPCResult DocAccessibleParent::RecvBindChildDoc(
MOZ_ASSERT(CheckDocTree());
auto childDoc = static_cast<DocAccessibleParent*>(aChildDoc.get());
if (childDoc->IsShutdown()) {
return IPC_FAIL(this, "Attempt to bind a shutdown child doc");
}
childDoc->Unbind();
ipc::IPCResult result = AddChildDoc(childDoc, aID, false);
MOZ_ASSERT(result);
MOZ_ASSERT(CheckDocTree());
@ -937,15 +882,6 @@ mozilla::ipc::IPCResult DocAccessibleParent::RecvBindChildDoc(
ipc::IPCResult DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc,
uint64_t aParentID,
bool aCreating) {
if (aChildDoc->RemoteParent()) {
return IPC_FAIL(this,
"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);
@ -994,20 +930,11 @@ ipc::IPCResult DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc,
aChildDoc->SetEmulatedWindowHandle(mEmulatedWindowHandle);
}
#endif // defined(XP_WIN)
}
// We need to fire a reorder event on the embedder. We do this here rather
// than in the content process for two reasons:
// 1. It isn't possible for the content process to fire a reorder event on the
// embedder when the embedded document is in a different process to its
// embedder.
// 2. Doing it here ensures that the event is fired after the child document
// is bound. Otherwise, there could be a short period where the content
// process has fired the reorder event, but the child document isn't bound
// yet.
// However, if the initial tree hasn't been received yet, we don't want to
// fire the reorder event yet. That gets handled in
// RecvRequestAckMutationEvents.
if (aChildDoc->mIsInitialTreeDone) {
// We need to fire a reorder event on the outer doc accessible.
// For same-process documents, this is fired by the content process, but
// this isn't possible when the document is in a different process to its
// embedder.
// FireEvent fires both OS and XPCOM events.
FireEvent(outerDoc, nsIAccessibleEvent::EVENT_REORDER);
}
@ -1048,9 +975,6 @@ 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;
}
@ -1088,8 +1012,6 @@ 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);
@ -1135,9 +1057,6 @@ void DocAccessibleParent::ActorDestroy(ActorDestroyReason aWhy) {
if (!mShutdown) {
ACQUIRE_ANDROID_LOCK
Destroy();
} else if (RemoteParent()) {
ACQUIRE_ANDROID_LOCK
Unbind();
}
}

View file

@ -325,14 +325,11 @@ class DocAccessibleParent : public RemoteAccessible,
};
RemoteAccessible* CreateAcc(const AccessibleData& aAccData);
bool AttachChild(RemoteAccessible* aParent, uint32_t aIndex,
void AttachChild(RemoteAccessible* aParent, uint32_t aIndex,
RemoteAccessible* aChild);
[[nodiscard]] bool CheckDocTree() const;
xpcAccessibleGeneric* GetXPCAccessible(RemoteAccessible* aProxy);
/**
* Fire an event to both OS and XPCOM consumers.
*/
void FireEvent(RemoteAccessible* aAcc, const uint32_t& aType);
/**
@ -368,10 +365,9 @@ class DocAccessibleParent : public RemoteAccessible,
uint32_t mPendingShowIndex = 0;
nsTHashSet<uint64_t> mMovingIDs;
uint64_t mActorID;
bool mTopLevel : 1;
bool mTopLevelInContentProcess : 1;
bool mShutdown : 1;
bool mIsInitialTreeDone : 1;
bool mTopLevel;
bool mTopLevelInContentProcess;
bool mShutdown;
RefPtr<dom::CanonicalBrowsingContext> mBrowsingContext;
nsTHashSet<RefPtr<dom::BrowserBridgeParent>> mPendingOOPChildDocs;

View file

@ -11,8 +11,6 @@ support-files = [
["browser_hidden_iframe.js"]
https_first_disabled = true
["browser_iframe_recreation.js"]
["browser_nested_iframe.js"]
["browser_reframe_root.js"]

View file

@ -1,29 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
addAccessibleTask(
`test`,
async function testRecreation(browser, iframeDocAcc, topDocAcc) {
let iframe = findAccessibleChildByID(topDocAcc, DEFAULT_IFRAME_ID);
is(iframeDocAcc.parent, iframe, "iframe doc's parent is iframe");
// The ARIA role currently causes re-creation. If that ever changes, we'll
// need to switch to another technique here.
info("Change iframe's role to recreate it");
let shown = waitForEvent(EVENT_SHOW, DEFAULT_IFRAME_ID);
let reordered = waitForEvent(EVENT_REORDER, DEFAULT_IFRAME_ID);
await SpecialPowers.spawn(
topDocAcc.browsingContext,
[DEFAULT_IFRAME_ID],
id => {
content.document.getElementById(id).role = "foo";
}
);
iframe = (await shown).accessible;
await reordered;
is(iframeDocAcc.parent, iframe, "iframe doc's parent is iframe");
},
{ chrome: false, topLevel: false, iframe: true, remoteIframe: true }
);

View file

@ -16,9 +16,25 @@ 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,
};
}
}

View file

@ -177,11 +177,8 @@ 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(
uri,
Services.io.newURI(blockedInfo.uri),
browsingContext.currentWindowGlobal.documentPrincipal.originAttributes
);
Services.perms.addFromPrincipal(
@ -209,10 +206,10 @@ export class BlockedSiteParent extends EscapablePageParent {
let title;
let chromeWin = browsingContext.topChromeWindow;
if (reason === "malware") {
let reportUrl = lazy.SafeBrowsing.getReportURL("MalwareMistake", {
...blockedInfo,
uri: uri.asciiSpec,
});
let reportUrl = lazy.SafeBrowsing.getReportURL(
"MalwareMistake",
blockedInfo
);
title = lazy.browserBundle.GetStringFromName(
"safebrowsing.reportedAttackSite"
);
@ -236,10 +233,10 @@ export class BlockedSiteParent extends EscapablePageParent {
};
}
} else if (reason === "phishing") {
let reportUrl = lazy.SafeBrowsing.getReportURL("PhishMistake", {
...blockedInfo,
uri: uri.asciiSpec,
});
let reportUrl = lazy.SafeBrowsing.getReportURL(
"PhishMistake",
blockedInfo
);
title = lazy.browserBundle.GetStringFromName(
"safebrowsing.deceptiveSite"
);
@ -284,15 +281,16 @@ export class BlockedSiteParent extends EscapablePageParent {
buttons
);
let activeSHEntry = browsingContext.activeSessionHistoryEntry;
if (!activeSHEntry) {
console.error("No active session history entry found");
return;
}
// Allow users to override and continue through to the site.
browsingContext.loadURI(uri, {
triggeringPrincipal: activeSHEntry.triggeringPrincipal,
// 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({});
browsingContext.fixupAndLoadURIString(blockedInfo.uri, {
triggeringPrincipal,
loadFlags: Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CLASSIFIER,
});
}

View file

@ -142,7 +142,9 @@ 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(topBrowsingContext);
window.PointerlockFsWarning.showFullScreen(
aMessage.data.originNoSuffix
);
}
this.updateFullscreenWindowReference(window);
break;
@ -220,7 +222,7 @@ export class DOMFullscreenParent extends JSWindowActorParent {
if (!this.hasBeenDestroyed() && this.requestOrigin) {
window.PointerlockFsWarning.showFullScreen(
this.requestOrigin.browsingContext
this.requestOrigin.manager.documentPrincipal.originNoSuffix
);
}
break;

View file

@ -49,16 +49,10 @@ var PointerlockFsWarning = {
}
},
// 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;
showFullScreen(aOrigin) {
let timeout = Services.prefs.getIntPref("full-screen-api.warning.timeout");
let delay = Services.prefs.getIntPref("full-screen-api.warning.delay");
this.show(origin, "fullscreen-warning", timeout, delay);
this.show(aOrigin, "fullscreen-warning", timeout, delay);
},
// Shows a warning that the site has entered fullscreen or

View file

@ -60,9 +60,6 @@ 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 = [

View file

@ -1,184 +0,0 @@
/* 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();
});
});

View file

@ -551,8 +551,11 @@ async function getAutofillRecords(data) {
// JSActors, but that would import a lot of code for a targeting attribute.
return 0;
}
let records = await actor?.getRecords(data);
return records?.length ?? 0;
let records = await actor?.receiveMessage({
name: "FormAutofill:GetRecords",
data,
});
return records?.records?.length ?? 0;
}
// Attribution data can be encoded multiple times so we need this function to

View file

@ -1418,10 +1418,15 @@ add_task(async function test_creditCardsSaved() {
gBrowser.selectedBrowser.browsingContext.currentWindowGlobal.getActor(
"FormAutofill"
),
"getRecords"
"receiveMessage"
)
.withArgs(sandbox.match({ collectionName: "creditCards" }))
.resolves([creditcard])
.withArgs(
sandbox.match({
name: "FormAutofill:GetRecords",
data: { collectionName: "creditCards" },
})
)
.resolves({ records: [creditcard] })
.callThrough();
is(
@ -1430,8 +1435,8 @@ add_task(async function test_creditCardsSaved() {
"Should return 1 when 1 credit card is saved"
);
ok(
stub.calledWithMatch({ collectionName: "creditCards" }),
"Targeting called getRecords"
stub.calledWithMatch({ name: "FormAutofill:GetRecords" }),
"Targeting called FormAutofill:GetRecords"
);
sandbox.restore();

View file

@ -60,5 +60,5 @@
}
}
},
"required": ["providerId", "searchPageRegexp"]
"required": ["providerId", "searchPageRegexp", "includeParams"]
}

View file

@ -1 +1 @@
140.10.1
140.8.0

View file

@ -1 +1 @@
140.10.1esr
140.8.0esr

View file

@ -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.10.1
MOZ_APP_VERSION=140.8.0
MOZ_DATA_REPORTING=0

View file

@ -10,4 +10,4 @@
# hardcoded milestones in the tree from these two files.
#--------------------------------------------------------
140.10.1
140.8.0

View file

@ -1,21 +1,3 @@
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)
-- Capitulo Mexicano de Software Libre <devel@cmxsl.org> Sat, 28 Mar 2026 01:16:35 -0600
icecat (140.8.0-2gnu1+build1-0.12.0) ecne; urgency=medium
* New upstream stable release (icecat-140.8.0-2gnu1)

View file

@ -190,7 +190,6 @@ 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
]

View file

@ -96,11 +96,8 @@ 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' && 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
"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
]
["browser_application_panel_target-switching.js"]

View file

@ -47,8 +47,6 @@ export default [
process: true,
global: true,
L10N: true,
// TODO: Add this to the main ESlint globals Bug 2025542
Sanitizer: true,
},
},
rules: {

View file

@ -2,12 +2,11 @@
* 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,
createRef,
} from "devtools/client/shared/vendor/react";
import React, { Component } from "devtools/client/shared/vendor/react";
import { div } from "devtools/client/shared/vendor/react-dom-factories";
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");
@ -60,7 +59,6 @@ export class QuickOpenModal extends Component {
constructor(props) {
super(props);
this.state = { results: null, selectedIndex: 0 };
this.resultListRef = createRef();
}
static get propTypes() {
@ -225,14 +223,20 @@ export class QuickOpenModal extends Component {
if (query == "" && !this.isShortcutQuery()) {
this.showTopSources();
} else if (this.isSymbolSearch()) {
await this.searchSymbols(query);
} else if (this.isShortcutQuery()) {
this.searchShortcuts(query);
} else {
this.searchSources(query);
return;
}
this.highlightQueryMatches(this.props.query);
if (this.isSymbolSearch()) {
await this.searchSymbols(query);
return;
}
if (this.isShortcutQuery()) {
this.searchShortcuts(query);
return;
}
this.searchSources(query);
} catch (e) {
// Due to throttling this might get scheduled after the component and the
// toolbox are destroyed.
@ -390,35 +394,23 @@ export class QuickOpenModal extends Component {
isSourcesQuery = () => this.props.searchType === "sources";
isSourceSearch = () => this.isSourcesQuery() || this.isGotoSourceQuery();
highlightQueryMatches(query) {
/* eslint-disable react/no-danger */
renderHighlight(candidateString, query) {
const options = {
wrap: {
tagOpen: '<mark class="highlight">',
tagClose: "</mark>",
},
};
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 });
}
}
}
const html = fuzzyAldrin.wrap(candidateString, query, options);
return div({
dangerouslySetInnerHTML: {
__html: html,
},
});
}
renderResults = (query, results) => {
highlightMatching = (query, results) => {
let newQuery = query;
if (newQuery === "") {
return results;
@ -429,7 +421,11 @@ export class QuickOpenModal extends Component {
if (typeof result.title == "string") {
return {
...result,
title: result.title,
title: this.renderHighlight(
result.title,
basename(newQuery),
"title"
),
};
}
return result;
@ -458,7 +454,7 @@ export class QuickOpenModal extends Component {
const { query } = this.props;
const { selectedIndex, results } = this.state;
const items = this.renderResults(query, results || []);
const items = this.highlightMatching(query, results || []);
const expanded = !!items && !!items.length;
return React.createElement(
Modal,
@ -491,7 +487,7 @@ export class QuickOpenModal extends Component {
items,
selected: selectedIndex,
selectItem: this.selectResultItem,
ref: this.resultListRef,
ref: "resultList",
expanded,
...(this.isSourceSearch() ? SIZE_BIG : SIZE_DEFAULT),
})

View file

@ -115,9 +115,6 @@ 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"]
@ -289,7 +286,6 @@ 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
]

View file

@ -94,18 +94,6 @@ 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);
@ -182,19 +170,3 @@ 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");
}
}

View file

@ -112,12 +112,6 @@ 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"]
@ -297,9 +291,6 @@ 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"]

View file

@ -150,11 +150,8 @@ fail-if = ["a11y_checks"] # Bug 1849028 clicked element may not be focusable and
["browser_animation_logic_mutations_fast.js"]
skip-if = [
"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
"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
]
["browser_animation_logic_mutations_properties.js"]

View file

@ -746,7 +746,7 @@ class RequestListContextMenu {
};
const options = JSON.stringify(fetchOptions, null, 4);
const fetchString = `await fetch(${JSON.stringify(url)}, ${options});`;
const fetchString = `await fetch("${url}", ${options});`;
return fetchString;
}

View file

@ -50,11 +50,10 @@ add_task(async function () {
const types = ["end", "response", "duration", "latency"];
for (const t of types) {
info("Check the timing column for type: " + t);
await waitUntil(() => {
const node = item.querySelector(".requests-list-" + t + "-time");
const value = parseInt(node.textContent, 10);
return value >= 0;
return value > 0;
});
}

View file

@ -7,7 +7,7 @@
* Tests if Copy as Fetch works.
*/
add_task(async function testBasicCopyAsFetch() {
add_task(async function () {
const { tab, monitor } = await initNetMonitor(HTTPS_CURL_URL, {
requestCount: 1,
});
@ -15,9 +15,7 @@ add_task(async function testBasicCopyAsFetch() {
// GET request, no cookies (first request)
await performRequest("GET");
await testClipboardContent(
monitor,
`await fetch("https://example.com/browser/devtools/client/netmonitor/test/sjs_simple-test-server.sjs", {
await testClipboardContent(`await fetch("https://example.com/browser/devtools/client/netmonitor/test/sjs_simple-test-server.sjs", {
"credentials": "omit",
"headers": {
"User-Agent": "${navigator.userAgent}",
@ -35,8 +33,7 @@ add_task(async function testBasicCopyAsFetch() {
"referrer": "https://example.com/browser/devtools/client/netmonitor/test/html_copy-as-curl.html",
"method": "GET",
"mode": "cors"
});`
);
});`);
await teardown(monitor);
@ -57,71 +54,39 @@ add_task(async function testBasicCopyAsFetch() {
);
await waitRequest;
}
});
/**
* Tests for Url escaping of copy as Fetch
*/
add_task(async function testUrlEscapeOfCopyAsFetch() {
const { monitor } = await initNetMonitor(HTTPS_CURL_URL, {
requestCount: 1,
});
info("Starting test... ");
async function testClipboardContent(expectedResult) {
const { document } = monitor.panelWin;
const waitRequest = waitForNetworkEvents(monitor, 1);
await SpecialPowers.spawn(
gBrowser.selectedBrowser,
['data:text/html,"+alert(document.domain)+"'],
url => {
content.fetch(url);
}
);
await waitRequest;
const items = document.querySelectorAll(".request-list-item");
EventUtils.sendMouseEvent({ type: "mousedown" }, items[items.length - 1]);
EventUtils.sendMouseEvent(
{ type: "contextmenu" },
document.querySelectorAll(".request-list-item")[0]
);
await testClipboardContent(
monitor,
`await fetch("data:text/html,\\"+alert(document.domain)+\\"", {
"credentials": "omit",
"headers": {},
"method": "GET",
"mode": "cors"
});`
);
/* Ensure that the copy as fetch option is always visible */
is(
!!getContextMenuItem(monitor, "request-list-context-copy-as-fetch"),
true,
'The "Copy as Fetch" context menu item should not be hidden.'
);
await teardown(monitor);
});
async function testClipboardContent(monitor, expectedResult) {
const { document } = monitor.panelWin;
const items = document.querySelectorAll(".request-list-item");
EventUtils.sendMouseEvent({ type: "mousedown" }, items[items.length - 1]);
EventUtils.sendMouseEvent(
{ type: "contextmenu" },
document.querySelectorAll(".request-list-item")[0]
);
/* Ensure that the copy as fetch option is always visible */
is(
!!getContextMenuItem(monitor, "request-list-context-copy-as-fetch"),
true,
'The "Copy as Fetch" context menu item should not be hidden.'
);
await waitForClipboardPromise(
async function setup() {
await selectContextMenuItem(
monitor,
"request-list-context-copy-as-fetch"
);
},
function validate(result) {
if (typeof result !== "string") {
return false;
await waitForClipboardPromise(
async function setup() {
await selectContextMenuItem(
monitor,
"request-list-context-copy-as-fetch"
);
},
function validate(result) {
if (typeof result !== "string") {
return false;
}
return expectedResult === result;
}
return expectedResult === result;
}
);
);
info("Clipboard contains a fetch command for item " + (items.length - 1));
}
info("Clipboard contains a fetch command for item " + (items.length - 1));
}
});

View file

@ -10,13 +10,15 @@ const DEFAULT_DPPX = window.devicePixelRatio;
/* eslint-disable max-len */
const TEST_DEVICE = {
name: "iPhone 17 / 17 Pro",
width: 402,
height: 874,
pixelRatio: 3,
name: "iPhone 6/7/8",
width: 375,
height: 667,
pixelRatio: 2,
userAgent:
"Mozilla/5.0 (iPhone; CPU iPhone OS 18_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Mobile/15E148 Safari/604.1",
"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1",
touch: true,
icecatOS: false,
os: "iOS",
featured: true,
};
/* eslint-enable max-len */

View file

@ -587,9 +587,7 @@ 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"]

View file

@ -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;
}
// 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)) {
// 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) {
res.waitingTime = existingPacket.waitingTime;
}

View file

@ -1937,19 +1937,6 @@ 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> {
@ -2799,11 +2786,6 @@ void BrowsingContext::DidSet(FieldIndex<IDX_ExplicitActive>,
});
}
bool BrowsingContext::CanSet(FieldIndex<IDX_InRDMPane>, const bool&,
ContentParent* aSource) {
return XRE_IsParentProcess() && IsTop() && !aSource;
}
void BrowsingContext::DidSet(FieldIndex<IDX_InRDMPane>, bool aOldValue) {
MOZ_ASSERT(IsTop(),
"Should only set InRDMPane in the top-level browsing context");

View file

@ -734,9 +734,6 @@ 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
@ -1139,7 +1136,6 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
return IsTop();
}
bool CanSet(FieldIndex<IDX_InRDMPane>, const bool&, ContentParent* aSource);
void DidSet(FieldIndex<IDX_InRDMPane>, bool aOldValue);
MOZ_CAN_RUN_SCRIPT_BOUNDARY void DidSet(FieldIndex<IDX_ForceDesktopViewport>,
bool aOldValue);
@ -1381,8 +1377,10 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
RefPtr<nsGeolocationService> mGeolocationServiceOverride;
// This is a weak reference. It will be updated automatically during sweeping
// by SweepWindowProxies.
// 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.
JS::Heap<JSObject*> mWindowProxy;
LocationProxy mLocation;

View file

@ -38,11 +38,6 @@ 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(); }
@ -80,7 +75,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();
}

View file

@ -386,9 +386,11 @@ void Animation::SetStartTime(const Nullable<TimeDuration>& aNewStartTime) {
}
CancelPendingTasks();
// We may have already resolved mReady, but in that case calling
// MaybeResolve is a no-op, so that's okay.
MaybeResolvePromiseWithThis(mReady);
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);
}
UpdateTiming(SeekFlag::DidSeek, SyncNotifyFlag::Async);
if (IsRelevant()) {
@ -447,7 +449,9 @@ void Animation::SetCurrentTimeNoUpdate(const TimeDuration& aSeekTime) {
ApplyPendingPlaybackRate();
mStartTime.SetNull();
MaybeResolvePromiseWithThis(mReady);
if (mReady) {
mReady->MaybeResolve(this);
}
CancelPendingTasks();
}
@ -604,25 +608,11 @@ Promise* Animation::GetReady(ErrorResult& aRv) {
return nullptr;
}
if (!Pending()) {
MaybeResolvePromiseWithThis(mReady);
mReady->MaybeResolve(this);
}
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) {
@ -724,7 +714,9 @@ void Animation::Finish(ErrorResult& aRv) {
}
CancelPendingTasks();
didChange = true;
MaybeResolvePromiseWithThis(mReady);
if (mReady) {
mReady->MaybeResolve(this);
}
}
UpdateTiming(SeekFlag::DidSeek, SyncNotifyFlag::Sync);
if (didChange && IsRelevant()) {
@ -1615,7 +1607,9 @@ void Animation::ResumeAt(const TimeDuration& aReadyTime) {
MutationObservers::NotifyAnimationChanged(this);
}
MaybeResolvePromiseWithThis(mReady);
if (mReady) {
mReady->MaybeResolve(this);
}
}
void Animation::PauseAt(const TimeDuration& aReadyTime) {
@ -1632,7 +1626,9 @@ void Animation::PauseAt(const TimeDuration& aReadyTime) {
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
MaybeResolvePromiseWithThis(mReady);
if (mReady) {
mReady->MaybeResolve(this);
}
}
void Animation::UpdateTiming(SeekFlag aSeekFlag,
@ -1881,8 +1877,10 @@ void Animation::ResetFinishedPromise() {
}
void Animation::MaybeResolveFinishedPromise() {
if (mFinished) {
mFinished->MaybeResolve(this);
}
mFinishedIsResolved = true;
MaybeResolvePromiseWithThis(mFinished);
}
void Animation::DoFinishNotificationImmediately(MicroTaskRunnable* aAsync) {

View file

@ -466,7 +466,6 @@ 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

View file

@ -10664,25 +10664,23 @@ void nsDOMAttributeMap::BlastSubtreeToPieces(nsINode* aNode) {
mozilla::DebugOnly<nsresult> rv =
element->UnsetAttr(attr->NodeInfo()->NamespaceID(),
attr->NodeInfo()->NameAtom(), true);
attr->NodeInfo()->NameAtom(), false);
// XXX Should we abort here?
NS_ASSERTION(NS_SUCCEEDED(rv), "Uh-oh, UnsetAttr shouldn't fail!");
}
}
// Hold the strong reference to be sure, since we may notify
if (RefPtr<mozilla::dom::ShadowRoot> shadow = element->GetShadowRoot()) {
if (mozilla::dom::ShadowRoot* shadow = element->GetShadowRoot()) {
BlastSubtreeToPieces(shadow);
element->UnattachShadow();
}
}
while (aNode->HasChildren()) {
// Hold the strong reference to be sure, since we are notifying.
nsCOMPtr<nsIContent> node = aNode->GetFirstChild();
nsIContent* node = aNode->GetFirstChild();
BlastSubtreeToPieces(node);
aNode->RemoveChildNode(node, true);
aNode->RemoveChildNode(node, false);
}
}
@ -16277,16 +16275,11 @@ 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;
for (UniquePtr<FullscreenRequest>& request : requests) {
PendingFullscreenChangeList::Iterator<FullscreenRequest> iter(
aDoc, PendingFullscreenChangeList::eDocumentsWithSameRoot);
while (!iter.AtEnd()) {
UniquePtr<FullscreenRequest> request = iter.TakeAndNext();
Document* doc = request->Document();
if (doc->ApplyFullscreen(std::move(request))) {
handled = true;

View file

@ -5732,7 +5732,7 @@ class MOZ_RAII IgnoreOpensDuringUnload final {
}
private:
RefPtr<Document> mDoc;
Document* mDoc;
};
bool IsInFocusedTab(Document* aDoc);

View file

@ -7,7 +7,6 @@
#include "DocumentOrShadowRoot.h"
#include "mozilla/AnimationComparator.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/Likely.h"
#include "mozilla/PointerLockManager.h"
#include "mozilla/PresShell.h"
#include "mozilla/StyleSheet.h"
@ -113,10 +112,6 @@ void DocumentOrShadowRoot::RemoveSheetFromStylesIfApplicable(
void DocumentOrShadowRoot::OnSetAdoptedStyleSheets(StyleSheet& aSheet,
uint32_t aIndex,
ErrorResult& aRv) {
if (MOZ_UNLIKELY(aIndex > mAdoptedStyleSheets.Length())) {
MOZ_ASSERT_UNREACHABLE("Out of sync proxy");
return;
}
Document& doc = *AsNode().OwnerDoc();
// 1. If values constructed flag is not set, or its constructor document is
// not equal to this DocumentOrShadowRoot's node document, throw a
@ -169,10 +164,7 @@ void DocumentOrShadowRoot::OnSetAdoptedStyleSheets(StyleSheet& aSheet,
void DocumentOrShadowRoot::OnDeleteAdoptedStyleSheets(StyleSheet& aSheet,
uint32_t aIndex,
ErrorResult&) {
if (MOZ_UNLIKELY(mAdoptedStyleSheets.ElementAt(aIndex) != &aSheet)) {
MOZ_ASSERT_UNREACHABLE("Out of sync proxy");
return;
}
MOZ_ASSERT(mAdoptedStyleSheets.ElementAt(aIndex) == &aSheet);
mAdoptedStyleSheets.RemoveElementAt(aIndex);
auto existingIndex = mAdoptedStyleSheets.LastIndexOf(&aSheet);
if (existingIndex != mAdoptedStyleSheets.NoIndex && existingIndex >= aIndex) {

View file

@ -279,9 +279,8 @@ nsIFrame* nsIContent::GetPrimaryFrame(mozilla::FlushType aType) {
return nullptr;
}
RefPtr<mozilla::PresShell> presShell = frame->PresShell();
if (aType == mozilla::FlushType::Layout) {
presShell->EnsureReflowIfFrameHasHiddenContent(frame);
frame->PresShell()->EnsureReflowIfFrameHasHiddenContent(frame);
frame = GetPrimaryFrame();
}
@ -2808,7 +2807,6 @@ bool Element::OnlyNotifySameValueSet(int32_t aNamespaceID, nsAtom* aName,
}
nsAutoScriptBlocker scriptBlocker;
OnAttrSetButNotChanged(aNamespaceID, aName, aValue, aNotify);
MutationObservers::NotifyAttributeSetToCurrentValue(this, aNamespaceID,
aName);
return true;
@ -2858,6 +2856,7 @@ 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;
}
}
@ -2907,6 +2906,7 @@ 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;
}
}

View file

@ -341,8 +341,8 @@ nsresult ImageEncoder::ExtractDataInternal(
return NS_ERROR_INVALID_ARG;
}
auto size = data->GetSize();
rv = aEncoder->InitFromData(map.mData, map.mStride * size.height,
size.width, size.height, map.mStride,
rv = aEncoder->InitFromData(map.mData, size.width * size.height * 4,
size.width, size.height, size.width * 4,
imgIEncoder::INPUT_FORMAT_HOSTARGB, aOptions);
data->Unmap();
}
@ -374,8 +374,8 @@ nsresult ImageEncoder::ExtractDataInternal(
}
rv = aEncoder->InitFromData(data.Elements(),
length, aSize.width,
aSize.height, stride,
aSize.width * aSize.height * 4, aSize.width,
aSize.height, aSize.width * 4,
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, map.mStride * size.height,
size.width, size.height, map.mStride,
rv = aEncoder->InitFromData(map.mData, size.width * size.height * 4,
size.width, size.height, size.width * 4,
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, size, aSize.width, aSize.height,
map.mStride,
rv = aEncoder->InitFromData(map.mData, aSize.width * aSize.height * 4,
aSize.width, aSize.height, aSize.width * 4,
imgIEncoder::INPUT_FORMAT_HOSTARGB, aOptions);
emptyCanvas->Unmap();
if (NS_SUCCEEDED(rv)) {

View file

@ -271,7 +271,6 @@ template <typename char_type>
const nsTSubstring<char_type>& aMimeType,
nsTSubstring<char_type>& aOutEssence,
nsTSubstring<char_type>& aOutCharset) {
// https://fetch.spec.whatwg.org/#concept-header-extract-mime-type
static char_type kCHARSET[] = {'c', 'h', 'a', 'r', 's', 'e', 't'};
static nsTDependentSubstring<char_type> kCharset(kCHARSET, 7);
@ -279,8 +278,8 @@ template <typename char_type>
nsTAutoString<char_type> prevContentType;
nsTAutoString<char_type> prevCharset;
aOutEssence.Truncate();
aOutCharset.Truncate();
prevContentType.Assign(aOutEssence);
prevCharset.Assign(aOutCharset);
nsTArray<nsTDependentSubstring<char_type>> mimeTypeParts =
SplitMimetype(aMimeType);
@ -293,7 +292,9 @@ template <typename char_type>
parsed = Parse(mimeTypeString);
if (!parsed) {
continue;
aOutEssence.Truncate();
aOutCharset.Truncate();
return false;
}
parsed->GetEssence(aOutEssence);
@ -321,10 +322,6 @@ template <typename char_type>
}
}
if (aOutEssence.IsEmpty()) {
return false;
}
return true;
}

View file

@ -70,24 +70,15 @@ ScreenOrientation::ScreenOrientation(nsPIDOMWindowInner* aWindow,
: DOMEventTargetHelper(aWindow), mScreen(aScreen) {
MOZ_ASSERT(aWindow);
MOZ_ASSERT(aScreen);
}
/* static */ already_AddRefed<ScreenOrientation> ScreenOrientation::Create(
nsPIDOMWindowInner* aWindow, nsScreen* aScreen) {
RefPtr screenOrientation = new ScreenOrientation(aWindow, aScreen);
mAngle = aScreen->GetOrientationAngle();
mType = InternalOrientationToType(aScreen->GetOrientationType());
screenOrientation->mAngle = aScreen->GetOrientationAngle();
screenOrientation->mType =
InternalOrientationToType(aScreen->GetOrientationType());
Document* doc = screenOrientation->GetResponsibleDocument();
Document* doc = GetResponsibleDocument();
BrowsingContext* bc = doc ? doc->GetBrowsingContext() : nullptr;
if (bc && !bc->IsDiscarded() && !bc->InRDMPane()) {
MOZ_ALWAYS_SUCCEEDS(bc->SetCurrentOrientation(screenOrientation->mType,
screenOrientation->mAngle));
MOZ_ALWAYS_SUCCEEDS(bc->SetCurrentOrientation(mType, mAngle));
}
return screenOrientation.forget();
}
ScreenOrientation::~ScreenOrientation() {

View file

@ -33,13 +33,8 @@ 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);
@ -112,8 +107,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,

View file

@ -213,7 +213,7 @@ void ShadowRoot::Unattach() {
void ShadowRoot::InvalidateStyleAndLayoutOnSubtree(Element* aElement) {
MOZ_ASSERT(aElement);
Document* doc = aElement->GetComposedDoc();
Document* doc = GetComposedDoc();
if (!doc) {
return;
}

View file

@ -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.
*/
static void InvalidateStyleAndLayoutOnSubtree(Element*);
void InvalidateStyleAndLayoutOnSubtree(Element*);
private:
void InsertSheetIntoAuthorData(size_t aIndex, StyleSheet&,

View file

@ -15,7 +15,6 @@
#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"
@ -215,13 +214,8 @@ bool StructuredCloneBlob::WriteStructuredClone(JSContext* aCx,
bool StructuredCloneBlob::Holder::WriteStructuredClone(
JSContext* aCx, JSStructuredCloneWriter* aWriter,
StructuredCloneHolder* aHolder) {
const auto& data = mBuffer->data();
CheckedUint32 dataSize(data.Size());
if (!dataSize.isValid()) {
return false;
}
if (!JS_WriteUint32Pair(aWriter, dataSize.value(),
JS_STRUCTURED_CLONE_VERSION) ||
auto& data = mBuffer->data();
if (!JS_WriteUint32Pair(aWriter, data.Size(), JS_STRUCTURED_CLONE_VERSION) ||
!JS_WriteUint32Pair(aWriter, aHolder->BlobImpls().Length(),
BlobImpls().Length())) {
return false;

View file

@ -938,8 +938,9 @@ TextInputProcessor::NotifyIME(TextEventDispatcher* aTextEventDispatcher,
NS_IMETHODIMP_(IMENotificationRequests)
TextInputProcessor::GetIMENotificationRequests() {
// TextInputProcessor should support all change notifications.
return {IMENotificationRequest::TextChange,
IMENotificationRequest::PositionChange};
return IMENotificationRequests(
IMENotificationRequests::NOTIFY_TEXT_CHANGE |
IMENotificationRequests::NOTIFY_POSITION_CHANGE);
}
NS_IMETHODIMP_(void)

View file

@ -27,10 +27,9 @@ class KeyboardEvent;
class TextInputProcessor final : public nsITextInputProcessor,
public widget::TextEventDispatcherListener {
using IMENotification = mozilla::widget::IMENotification;
using IMENotificationRequest = mozilla::widget::IMENotificationRequest;
using IMENotificationRequests = mozilla::widget::IMENotificationRequests;
using TextEventDispatcher = mozilla::widget::TextEventDispatcher;
typedef mozilla::widget::IMENotification IMENotification;
typedef mozilla::widget::IMENotificationRequests IMENotificationRequests;
typedef mozilla::widget::TextEventDispatcher TextEventDispatcher;
public:
TextInputProcessor();

View file

@ -1333,11 +1333,7 @@ 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;
}
@ -1937,11 +1933,7 @@ 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;
}

View file

@ -592,8 +592,7 @@ Element* nsContentList::NamedItem(const nsAString& aName, bool aDoFlush) {
return mNamedItemsCache->Get(name);
}
void nsContentList::GetSupportedNames(nsTArray<nsString>& aNames,
FilterElementWithName aFilter) {
void nsContentList::GetSupportedNames(nsTArray<nsString>& aNames) {
BringSelfUpToDate(true);
AutoTArray<nsAtom*, 8> atoms;
@ -607,14 +606,14 @@ void nsContentList::GetSupportedNames(nsTArray<nsString>& aNames,
}
}
if (nsGenericHTMLElement* el = nsGenericHTMLElement::FromNode(content)) {
nsGenericHTMLElement* el = nsGenericHTMLElement::FromNode(content);
if (el) {
// 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 &&
(!aFilter || aFilter(el))) {
if (val && val->Type() == nsAttrValue::eAtom) {
nsAtom* name = val->GetAtomValue();
MOZ_ASSERT(name != nsGkAtoms::_empty, "Empty names don't get atomized");
if (!atoms.Contains(name)) {

View file

@ -296,21 +296,13 @@ class nsContentList : public nsBaseContentList,
aFound = !!item;
return item;
}
void GetSupportedNames(nsTArray<nsString>& aNames) override {
GetSupportedNames(aNames, nullptr);
}
void GetSupportedNames(nsTArray<nsString>& aNames) override;
// 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

View file

@ -44,15 +44,12 @@ class ContentPermissionRequestParent : public PContentPermissionRequestParent {
// @param aIsRequestDelegatedToUnsafeThirdParty see
// mIsRequestDelegatedToUnsafeThirdParty.
ContentPermissionRequestParent(
Element* aElement, nsIPrincipal* aPrincipal,
nsIPrincipal* aTopLevelPrincipal,
const nsTArray<PermissionRequest>& aRequests, Element* aElement,
nsIPrincipal* aPrincipal, nsIPrincipal* aTopLevelPrincipal,
const bool aHasValidTransientUserGestureActivation,
const bool aIsRequestDelegatedToUnsafeThirdParty);
virtual ~ContentPermissionRequestParent();
MOZ_CAN_RUN_SCRIPT_BOUNDARY
void Init(nsTArray<PermissionRequest>&& aRequests);
bool IsBeingDestroyed();
nsCOMPtr<nsIPrincipal> mPrincipal;
@ -67,13 +64,16 @@ class ContentPermissionRequestParent : public PContentPermissionRequestParent {
nsTArray<PermissionRequest> mRequests;
private:
// Not MOZ_CAN_RUN_SCRIPT because we can't annotate the thing we override yet.
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual mozilla::ipc::IPCResult Recvprompt() override;
virtual mozilla::ipc::IPCResult RecvDestroy() override;
virtual void ActorDestroy(ActorDestroyReason why) override;
};
ContentPermissionRequestParent::ContentPermissionRequestParent(
Element* aElement, nsIPrincipal* aPrincipal,
nsIPrincipal* aTopLevelPrincipal,
const nsTArray<PermissionRequest>& aRequests, Element* aElement,
nsIPrincipal* aPrincipal, nsIPrincipal* aTopLevelPrincipal,
const bool aHasValidTransientUserGestureActivation,
const bool aIsRequestDelegatedToUnsafeThirdParty) {
MOZ_COUNT_CTOR(ContentPermissionRequestParent);
@ -81,6 +81,7 @@ ContentPermissionRequestParent::ContentPermissionRequestParent(
mPrincipal = aPrincipal;
mTopLevelPrincipal = aTopLevelPrincipal;
mElement = aElement;
mRequests = aRequests.Clone();
mHasValidTransientUserGestureActivation =
aHasValidTransientUserGestureActivation;
mIsRequestDelegatedToUnsafeThirdParty = aIsRequestDelegatedToUnsafeThirdParty;
@ -90,14 +91,13 @@ ContentPermissionRequestParent::~ContentPermissionRequestParent() {
MOZ_COUNT_DTOR(ContentPermissionRequestParent);
}
void ContentPermissionRequestParent::Init(
nsTArray<PermissionRequest>&& aRequests) {
mRequests = std::move(aRequests);
mozilla::ipc::IPCResult ContentPermissionRequestParent::Recvprompt() {
mProxy = new nsContentPermissionRequestProxy(this);
if (NS_FAILED(mProxy->Init(mRequests))) {
RefPtr<nsContentPermissionRequestProxy> proxy(mProxy);
proxy->Cancel();
}
return IPC_OK();
}
mozilla::ipc::IPCResult ContentPermissionRequestParent::RecvDestroy() {
@ -239,12 +239,12 @@ nsresult nsContentPermissionUtils::CreatePermissionArray(
/* static */
PContentPermissionRequestParent*
nsContentPermissionUtils::CreateContentPermissionRequestParent(
Element* aElement, nsIPrincipal* aPrincipal,
nsIPrincipal* aTopLevelPrincipal,
const nsTArray<PermissionRequest>& aRequests, Element* aElement,
nsIPrincipal* aPrincipal, nsIPrincipal* aTopLevelPrincipal,
const bool aHasValidTransientUserGestureActivation,
const bool aIsRequestDelegatedToUnsafeThirdParty, const TabId& aTabId) {
PContentPermissionRequestParent* parent = new ContentPermissionRequestParent(
aElement, aPrincipal, aTopLevelPrincipal,
aRequests, aElement, aPrincipal, aTopLevelPrincipal,
aHasValidTransientUserGestureActivation,
aIsRequestDelegatedToUnsafeThirdParty);
ContentPermissionRequestParentMap()[parent] = aTabId;
@ -252,14 +252,6 @@ nsContentPermissionUtils::CreateContentPermissionRequestParent(
return parent;
}
/* static */
void nsContentPermissionUtils::InitContentPermissionRequestParent(
PContentPermissionRequestParent* aActor,
nsTArray<PermissionRequest>&& aRequests) {
static_cast<ContentPermissionRequestParent*>(aActor)->Init(
std::move(aRequests));
}
/* static */
nsresult nsContentPermissionUtils::AskPermission(
nsIContentPermissionRequest* aRequest, nsPIDOMWindowInner* aWindow) {
@ -309,6 +301,7 @@ nsresult nsContentPermissionUtils::AskPermission(
}
ContentPermissionRequestChildMap()[req.get()] = child->GetTabId();
req->Sendprompt();
return NS_OK;
}

View file

@ -63,15 +63,11 @@ class nsContentPermissionUtils {
// @param aIsRequestDelegatedToUnsafeThirdParty see
// ContentPermissionRequestParent.
static PContentPermissionRequestParent* CreateContentPermissionRequestParent(
Element* aElement, nsIPrincipal* aPrincipal,
nsIPrincipal* aTopLevelPrincipal,
const nsTArray<PermissionRequest>& aRequests, Element* aElement,
nsIPrincipal* aPrincipal, nsIPrincipal* aTopLevelPrincipal,
const bool aHasValidTransientUserGestureActivation,
const bool aIsRequestDelegatedToUnsafeThirdParty, const TabId& aTabId);
static void InitContentPermissionRequestParent(
PContentPermissionRequestParent* aActor,
nsTArray<PermissionRequest>&& aRequests);
static nsresult AskPermission(nsIContentPermissionRequest* aRequest,
nsPIDOMWindowInner* aWindow);

View file

@ -4533,9 +4533,10 @@ nsDOMWindowUtils::WrCapture() {
}
NS_IMETHODIMP
nsDOMWindowUtils::WrStartCaptureSequence(uint32_t aFlags) {
nsDOMWindowUtils::WrStartCaptureSequence(const nsACString& aPath,
uint32_t aFlags) {
if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) {
wrbc->StartCaptureSequence(aFlags);
wrbc->StartCaptureSequence(nsCString(aPath), aFlags);
}
return NS_OK;
}

View file

@ -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.
RefPtr<Document> doc = owner->OwnerDoc();
Document* doc = owner->OwnerDoc();
doc->BlockOnload();
auto cleanup = MakeScopeExit([&]() { doc->UnblockOnload(false); });

View file

@ -2459,7 +2459,7 @@ VisualViewport* nsGlobalWindowInner::VisualViewport() {
nsScreen* nsGlobalWindowInner::Screen() {
if (!mScreen) {
mScreen = nsScreen::Create(this);
mScreen = new nsScreen(this);
}
return mScreen;
}
@ -2535,10 +2535,6 @@ 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);
}

View file

@ -1286,10 +1286,6 @@ 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;

View file

@ -1105,7 +1105,11 @@ void nsINode::Normalize() {
const nsTextFragment* text = node->GetText();
if (text->GetLength()) {
nsIContent* target = node->GetPreviousSibling();
if (target && target->NodeType() == TEXT_NODE) {
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)) {
nsTextNode* t = static_cast<nsTextNode*>(target);
if (text->Is2b()) {
t->AppendTextForNormalize(text->Get2b(), text->GetLength(), true,
@ -3717,10 +3721,8 @@ already_AddRefed<nsINode> nsINode::CloneAndAdopt(
JSAutoRealm ar(cx, wrapper);
UpdateReflectorGlobal(cx, wrapper, aError);
if (aError.Failed()) {
bool needsRollBack = false;
if (wasRegistered) {
needsRollBack =
newDoc->UnregisterActivityObserver(aNode->AsElement());
newDoc->UnregisterActivityObserver(aNode->AsElement());
}
if (hadProperties) {
// NOTE: When it fails it removes all properties for the node
@ -3730,7 +3732,7 @@ already_AddRefed<nsINode> nsINode::CloneAndAdopt(
}
aNode->mNodeInfo.swap(newNodeInfo);
aNode->NodeInfoChanged(newDoc);
if (needsRollBack) {
if (wasRegistered) {
oldDoc->RegisterActivityObserver(aNode->AsElement());
}
return nullptr;

View file

@ -214,8 +214,8 @@ already_AddRefed<nsIDocShell> nsObjectLoadingContent::SetupDocShell(
}
if (!docShell) {
RefPtr<nsFrameLoader> loader = std::move(mFrameLoader);
loader->Destroy();
mFrameLoader->Destroy();
mFrameLoader = nullptr;
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");
RefPtr<nsFrameLoader> loader = std::move(mFrameLoader);
loader->Destroy();
mFrameLoader->Destroy();
mFrameLoader = nullptr;
break;
}
@ -1591,6 +1591,11 @@ 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();
@ -1614,8 +1619,8 @@ void nsObjectLoadingContent::Unlink(nsObjectLoadingContent* tmp) {
void nsObjectLoadingContent::UnloadObject(bool aResetState) {
if (mFrameLoader) {
RefPtr<nsFrameLoader> loader = std::move(mFrameLoader);
loader->Destroy();
mFrameLoader->Destroy();
mFrameLoader = nullptr;
}
if (aResetState) {
@ -1713,30 +1718,23 @@ 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
AutoTArray<RefPtr<nsIContent>, 4> targets;
// fallback for this element.
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 (child->IsAnyOfHTMLElements(nsGkAtoms::embed, nsGkAtoms::object)) {
targets.AppendElement(child);
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
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

View file

@ -366,7 +366,6 @@ 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);

View file

@ -2829,6 +2829,20 @@ 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;

View file

@ -23,14 +23,8 @@ using namespace mozilla;
using namespace mozilla::dom;
nsScreen::nsScreen(nsPIDOMWindowInner* aWindow)
: DOMEventTargetHelper(aWindow) {}
/* static */ already_AddRefed<nsScreen> nsScreen::Create(
nsPIDOMWindowInner* aWindow) {
RefPtr screen = new nsScreen(aWindow);
screen->mScreenOrientation = ScreenOrientation::Create(aWindow, screen);
return screen.forget();
}
: DOMEventTargetHelper(aWindow),
mScreenOrientation(new ScreenOrientation(aWindow, this)) {}
nsScreen::~nsScreen() = default;

View file

@ -21,11 +21,8 @@ enum class RFPTarget : uint64_t;
// Script "screen" object
class nsScreen : public mozilla::DOMEventTargetHelper {
private:
explicit nsScreen(nsPIDOMWindowInner* aWindow);
public:
static already_AddRefed<nsScreen> Create(nsPIDOMWindowInner* aWindow);
explicit nsScreen(nsPIDOMWindowInner* aWindow);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsScreen,

View file

@ -47,13 +47,6 @@ 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.

View file

@ -170,8 +170,6 @@ class JS_HAZ_ROOTED nsWrapperCache {
}
}
void ClearWrapperOnWrapFailure();
/**
* Update the wrapper when the object moves between globals.
*/

View file

@ -86,18 +86,12 @@ 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);
}
}
}

View file

@ -821,8 +821,8 @@ TEST(MimeTypeParsing, contentTypes1)
bool parsed = CMimeType::Parse(val, contentType, contentCharset);
ASSERT_TRUE(parsed);
ASSERT_TRUE(contentType.EqualsLiteral("text/plain"));
ASSERT_FALSE(parsed);
ASSERT_TRUE(contentType.EqualsLiteral(""));
ASSERT_TRUE(contentCharset.EqualsLiteral(""));
}
@ -1074,43 +1074,3 @@ TEST(MimeTypeParsing, contentTypes20)
ASSERT_TRUE(contentType.EqualsLiteral("text/plain"));
ASSERT_TRUE(contentCharset.EqualsLiteral(""));
}
// U+002F(/) is not a valid HTTP token code point
// https://mimesniff.spec.whatwg.org/#http-token-code-point
TEST(MimeTypeParsing, invalidSubtype1)
{
const nsAutoCString val("text/json/");
RefPtr<CMimeType> parsed = CMimeType::Parse(val);
ASSERT_TRUE(!parsed);
}
TEST(MimeTypeParsing, invalidSubtype2)
{
const nsAutoCString val("text/json/bad");
RefPtr<CMimeType> parsed = CMimeType::Parse(val);
ASSERT_TRUE(!parsed);
}
TEST(MimeTypeParsing, EmptyParsing)
{
constexpr nsLiteralCString val("");
nsCString contentType;
nsCString contentCharset;
bool parsed = CMimeType::Parse(val, contentType, contentCharset);
ASSERT_FALSE(parsed);
ASSERT_TRUE(contentType.EqualsLiteral(""));
ASSERT_TRUE(contentCharset.EqualsLiteral(""));
}
TEST(MimeTypeParsing, EmptySubtype)
{
constexpr nsLiteralCString val("audio/");
nsCString contentType;
nsCString contentCharset;
bool parsed = CMimeType::Parse(val, contentType, contentCharset);
ASSERT_FALSE(parsed);
ASSERT_TRUE(contentType.EqualsLiteral(""));
ASSERT_TRUE(contentCharset.EqualsLiteral(""));
}

View file

@ -1,5 +1,3 @@
[DEFAULT]
["test_bug_2027541.html"]
["test_nested_modules.html"]

View file

@ -1,47 +0,0 @@
<!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>

View file

@ -259,6 +259,39 @@ nsTArray<nsCString>& TErrorResult<CleanupPolicy>::CreateErrorMessageHelper(
return message->mArgs;
}
template <typename CleanupPolicy>
void TErrorResult<CleanupPolicy>::SerializeMessage(
IPC::MessageWriter* aWriter) const {
using namespace IPC;
AssertInOwningThread();
MOZ_ASSERT(mUnionState == HasMessage);
MOZ_ASSERT(mExtra.mMessage);
WriteParam(aWriter, mExtra.mMessage->mArgs);
WriteParam(aWriter, mExtra.mMessage->mErrorNumber);
}
template <typename CleanupPolicy>
bool TErrorResult<CleanupPolicy>::DeserializeMessage(
IPC::MessageReader* aReader) {
using namespace IPC;
AssertInOwningThread();
auto readMessage = MakeUnique<Message>();
if (!ReadParam(aReader, &readMessage->mArgs) ||
!ReadParam(aReader, &readMessage->mErrorNumber)) {
return false;
}
if (!readMessage->HasCorrectNumberOfArguments()) {
return false;
}
MOZ_ASSERT(mUnionState == HasNothing);
InitMessage(readMessage.release());
#ifdef DEBUG
mUnionState = HasMessage;
#endif // DEBUG
return true;
}
template <typename CleanupPolicy>
void TErrorResult<CleanupPolicy>::SetPendingExceptionWithMessage(
JSContext* aCx, const char* context) {
@ -368,106 +401,34 @@ struct TErrorResult<CleanupPolicy>::DOMExceptionInfo {
};
template <typename CleanupPolicy>
void TErrorResult<CleanupPolicy>::SerializeErrorResult(
void TErrorResult<CleanupPolicy>::SerializeDOMExceptionInfo(
IPC::MessageWriter* aWriter) const {
using namespace IPC;
AssertInOwningThread();
// It should be the case that mMightHaveUnreportedJSException can only be
// true when we're expecting a JS exception. We cannot send such messages
// over the IPC channel since there is no sane way of transferring the JS
// value over to the other side. Callers should never do that.
MOZ_ASSERT(!mMightHaveUnreportedJSException);
if (IsJSException() || IsJSContextException()) {
MOZ_CRASH(
"Cannot serialize an ErrorResult representing a Javascript exception");
}
WriteParam(aWriter, mResult);
if (IsErrorWithMessage()) {
MOZ_ASSERT(mResult == NS_ERROR_INTERNAL_ERRORRESULT_TYPEERROR ||
mResult == NS_ERROR_INTERNAL_ERRORRESULT_RANGEERROR);
MOZ_ASSERT(mUnionState == HasMessage);
MOZ_ASSERT(mExtra.mMessage);
WriteParam(aWriter, mExtra.mMessage->mArgs);
WriteParam(aWriter, mExtra.mMessage->mErrorNumber);
} else if (IsDOMException()) {
MOZ_ASSERT(mResult == NS_ERROR_INTERNAL_ERRORRESULT_DOMEXCEPTION);
MOZ_ASSERT(mUnionState == HasDOMExceptionInfo);
MOZ_ASSERT(mExtra.mDOMExceptionInfo);
WriteParam(aWriter, mExtra.mDOMExceptionInfo->mMessage);
WriteParam(aWriter, mExtra.mDOMExceptionInfo->mRv);
} else {
MOZ_ASSERT(mUnionState == HasNothing);
}
MOZ_ASSERT(mUnionState == HasDOMExceptionInfo);
MOZ_ASSERT(mExtra.mDOMExceptionInfo);
WriteParam(aWriter, mExtra.mDOMExceptionInfo->mMessage);
WriteParam(aWriter, mExtra.mDOMExceptionInfo->mRv);
}
template <typename CleanupPolicy>
bool TErrorResult<CleanupPolicy>::DeserializeErrorResult(
bool TErrorResult<CleanupPolicy>::DeserializeDOMExceptionInfo(
IPC::MessageReader* aReader) {
using namespace IPC;
AssertInOwningThread();
nsresult result;
if (!ReadParam(aReader, &result)) {
nsCString message;
nsresult rv;
if (!ReadParam(aReader, &message) || !ReadParam(aReader, &rv)) {
return false;
}
switch (result) {
case NS_ERROR_INTERNAL_ERRORRESULT_JS_EXCEPTION:
case NS_ERROR_INTERNAL_ERRORRESULT_EXCEPTION_ON_JSCONTEXT:
// JS exceptions can not be serialized.
return false;
case NS_ERROR_INTERNAL_ERRORRESULT_TYPEERROR:
case NS_ERROR_INTERNAL_ERRORRESULT_RANGEERROR: {
nsTArray<nsCString> args;
dom::ErrNum errorNumber;
if (!ReadParam(aReader, &args) || !ReadParam(aReader, &errorNumber)) {
return false;
}
if (GetErrorArgCount(errorNumber) != args.Length()) {
return false;
}
for (nsCString& arg : args) {
if (Utf8ValidUpTo(arg) != arg.Length()) {
return false;
}
}
ClearUnionData();
nsTArray<nsCString>& messageArgsArray =
CreateErrorMessageHelper(errorNumber, result);
messageArgsArray = std::move(args);
MOZ_ASSERT(mExtra.mMessage->HasCorrectNumberOfArguments(),
"validated earlier");
MOZ_ASSERT(mUnionState == HasNothing);
MOZ_ASSERT(IsDOMException());
InitDOMExceptionInfo(new DOMExceptionInfo(rv, message));
#ifdef DEBUG
mUnionState = HasMessage;
#endif
return true;
}
case NS_ERROR_INTERNAL_ERRORRESULT_DOMEXCEPTION: {
nsCString message;
nsresult rv;
if (!ReadParam(aReader, &message) || !ReadParam(aReader, &rv)) {
return false;
}
ThrowDOMException(rv, message);
return true;
}
default:
ClearUnionData();
AssignErrorCode(result);
return true;
}
mUnionState = HasDOMExceptionInfo;
#endif // DEBUG
return true;
}
template <typename CleanupPolicy>
@ -2473,7 +2434,8 @@ 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|.
// slot and nulling out the reserved slot of |obj|. Update the wrapper cache
// to keep everything consistent in case GC moves newobj.
//
// NB: It's important to do this _after_ copying the properties to
// propertyHolder. Otherwise, an object with |foo.x === foo| will
@ -2482,37 +2444,18 @@ 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);
// 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();
}
cache->UpdateWrapperForNewGlobal(native, newobj);
aObj = xpc::TransplantObjectRetainingXrayExpandos(aCx, aObj, newobj);
if (!aObj) {
MOZ_CRASH();
}
if (!preserving || aObj != newobj) {
// Update the wrapper cache again if transplanting didn't use newobj but
// returned some other object.
if (aObj != newobj) {
MOZ_ASSERT(UnwrapDOMObjectToISupports(aObj) == native);
cache->UpdateWrapperForNewGlobal(native, aObj);
}
@ -3573,7 +3516,6 @@ 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.

View file

@ -4683,7 +4683,7 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
failureCode = dedent(
"""
aCache->ReleaseWrapper(aObject);
aCache->ClearWrapperOnWrapFailure();
aCache->ClearWrapper();
return false;
"""
)
@ -23213,9 +23213,7 @@ class CGIterableMethodGenerator(CGGeneric):
CGGeneric.__init__(self, createIterator)
def getObservableArrayBackingObject(
descriptor, attr, objName="obj", errorReturn="return false;\n"
):
def getObservableArrayBackingObject(descriptor, attr, errorReturn="return false;\n"):
"""
Generate code to get/create a JS backing list for an observableArray attribute
from the declaration slot.
@ -23230,7 +23228,7 @@ def getObservableArrayBackingObject(
"""
JS::Rooted<JSObject*> backingObj(cx);
bool created = false;
if (!GetObservableArrayBackingObject(cx, ${objName}, ${slot},
if (!GetObservableArrayBackingObject(cx, obj, ${slot},
&backingObj, &created, ${namespace}::ObservableArrayProxyHandler::getInstance(),
self)) {
$*{errorReturn}
@ -23239,9 +23237,8 @@ def getObservableArrayBackingObject(
PreserveWrapper(self);
}
""",
objName=objName,
slot=memberReservedSlot(attr, descriptor),
namespace=toBindingNamespace(MakeNativeName(attr.identifier.name)),
slot=memberReservedSlot(attr, descriptor),
errorReturn=errorReturn,
selfType=descriptor.nativeType,
)
@ -23353,18 +23350,12 @@ class CGObservableArrayProxyHandler_callback(ClassMethod):
$*{convertType}
$*{preCallback}
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;
}
}
JS::Value val = js::GetProxyReservedSlot(aProxy, OBSERVABLE_ARRAY_DOM_INTERFACE_SLOT);
auto* interface = static_cast<${ifaceType}*>(val.toPrivate());
MOZ_ASSERT(interface);
ErrorResult rv;
MOZ_KnownLive(interface)->${methodName}(${callbackArgs});
$*{postCallback}
""",
preConversion=self.preConversion(),
@ -23408,7 +23399,7 @@ class CGObservableArrayProxyHandler_OnDeleteItem(
def postCallback(self):
return dedent(
"""
return true;
return !rv.MaybeSetPendingException(cx);
"""
)
@ -23473,6 +23464,10 @@ class CGObservableArrayProxyHandler_SetIndexedValue(
def postCallback(self):
return dedent(
"""
if (rv.MaybeSetPendingException(cx)) {
return false;
}
if (!JS_SetElement(aCx, aBackingList, aIndex, aValue)) {
return false;
}
@ -23535,9 +23530,7 @@ class CGObservableArraySetterGenerator(CGGeneric):
def __init__(self, descriptor, attr):
assert attr.isAttr()
assert attr.type.isObservableArray()
getBackingObject = getObservableArrayBackingObject(
descriptor, attr, objName="unwrappedObj"
)
getBackingObject = getObservableArrayBackingObject(descriptor, attr)
setElement = dedent(
"""
if (!JS_SetElement(cx, backingObj, i, val)) {
@ -23564,22 +23557,15 @@ class CGObservableArraySetterGenerator(CGGeneric):
return false;
}
JS::Rooted<JSObject*> unwrappedObj(cx, js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false));
MOZ_ASSERT(IsDOMObject(unwrappedObj));
{
JSAutoRealm ar(cx, unwrappedObj);
${getBackingObject}
const ObservableArrayProxyHandler* handler = GetObservableArrayProxyHandler(backingObj);
if (!handler->SetLength(cx, backingObj, 0)) {
return false;
}
$*{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}
}
JS::Rooted<JS::Value> val(cx);
for (size_t i = 0; i < arg0.Length(); i++) {
$*{conversion}
}
""",
conversion=conversion,
@ -23625,7 +23611,7 @@ class CGObservableArrayHelperFunctionGenerator(CGHelperFunctionGenerator):
getObservableArrayBackingObject(
descriptor,
attr,
errorReturn=dedent(
dedent(
"""
aRv.Throw(NS_ERROR_UNEXPECTED);
return%s;

View file

@ -7,8 +7,11 @@
#ifndef IPC_ErrorIPCUtils_h
#define IPC_ErrorIPCUtils_h
#include <utility>
#include "ipc/EnumSerializer.h"
#include "ipc/IPCMessageUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/ErrorResult.h"
namespace IPC {
@ -21,18 +24,64 @@ struct ParamTraits<mozilla::dom::ErrNum>
template <>
struct ParamTraits<mozilla::ErrorResult> {
static void Write(MessageWriter* aWriter,
const mozilla::ErrorResult& aParam) {
aParam.SerializeErrorResult(aWriter);
typedef mozilla::ErrorResult paramType;
static void Write(MessageWriter* aWriter, const paramType& aParam) {
// It should be the case that mMightHaveUnreportedJSException can only be
// true when we're expecting a JS exception. We cannot send such messages
// over the IPC channel since there is no sane way of transferring the JS
// value over to the other side. Callers should never do that.
MOZ_ASSERT_IF(aParam.IsJSException(),
aParam.mMightHaveUnreportedJSException);
if (aParam.IsJSException()
#ifdef DEBUG
|| aParam.mMightHaveUnreportedJSException
#endif
) {
MOZ_CRASH(
"Cannot encode an ErrorResult representing a Javascript exception");
}
WriteParam(aWriter, aParam.mResult);
WriteParam(aWriter, aParam.IsErrorWithMessage());
WriteParam(aWriter, aParam.IsDOMException());
if (aParam.IsErrorWithMessage()) {
aParam.SerializeMessage(aWriter);
} else if (aParam.IsDOMException()) {
aParam.SerializeDOMExceptionInfo(aWriter);
}
}
static void Write(MessageWriter* aWriter, mozilla::ErrorResult&& aParam) {
aParam.SerializeErrorResult(aWriter);
static void Write(MessageWriter* aWriter, paramType&& aParam) {
Write(aWriter, static_cast<const paramType&>(aParam));
aParam.SuppressException();
}
static bool Read(MessageReader* aReader, mozilla::ErrorResult* aResult) {
return aResult->DeserializeErrorResult(aReader);
static bool Read(MessageReader* aReader, paramType* aResult) {
paramType readValue;
if (!ReadParam(aReader, &readValue.mResult)) {
return false;
}
bool hasMessage = false;
if (!ReadParam(aReader, &hasMessage)) {
return false;
}
bool hasDOMExceptionInfo = false;
if (!ReadParam(aReader, &hasDOMExceptionInfo)) {
return false;
}
if (hasMessage && hasDOMExceptionInfo) {
// Shouldn't have both!
return false;
}
if (hasMessage && !readValue.DeserializeMessage(aReader)) {
return false;
} else if (hasDOMExceptionInfo &&
!readValue.DeserializeDOMExceptionInfo(aReader)) {
return false;
}
*aResult = std::move(readValue);
return true;
}
};
@ -41,11 +90,14 @@ struct ParamTraits<mozilla::CopyableErrorResult> {
typedef mozilla::CopyableErrorResult paramType;
static void Write(MessageWriter* aWriter, const paramType& aParam) {
aParam.SerializeErrorResult(aWriter);
ParamTraits<mozilla::ErrorResult>::Write(aWriter, aParam);
}
static bool Read(MessageReader* aReader, paramType* aResult) {
return aResult->DeserializeErrorResult(aReader);
// We can't cast *aResult to ErrorResult&, so cheat and just cast
// to ErrorResult*.
return ParamTraits<mozilla::ErrorResult>::Read(
aReader, reinterpret_cast<mozilla::ErrorResult*>(aResult));
}
};

View file

@ -215,7 +215,6 @@ 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);
}
@ -402,7 +401,7 @@ class TErrorResult {
// Check whether the TErrorResult says to just throw whatever is on
// the JSContext already.
bool IsJSContextException() const {
bool IsJSContextException() {
return ErrorCode() == NS_ERROR_INTERNAL_ERRORRESULT_EXCEPTION_ON_JSCONTEXT;
}
@ -432,10 +431,7 @@ 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) {
ClearUnionData();
AssignErrorCode(rv);
}
void operator=(nsresult rv) { AssignErrorCode(rv); }
bool Failed() const { return NS_FAILED(mResult); }
@ -485,10 +481,11 @@ class TErrorResult {
friend struct IPC::ParamTraits<TErrorResult>;
friend struct IPC::ParamTraits<ErrorResult>;
friend struct IPC::ParamTraits<CopyableErrorResult>;
void SerializeMessage(IPC::MessageWriter* aWriter) const;
bool DeserializeMessage(IPC::MessageReader* aReader);
void SerializeErrorResult(IPC::MessageWriter* aWriter) const;
bool DeserializeErrorResult(IPC::MessageReader* aReader);
void SerializeDOMExceptionInfo(IPC::MessageWriter* aWriter) const;
bool DeserializeDOMExceptionInfo(IPC::MessageReader* aReader);
// Helper method that creates a new Message for this TErrorResult,
// and returns the arguments array from that Message.
@ -546,7 +543,6 @@ 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,

View file

@ -277,9 +277,6 @@ bool ObservableArrayProxyHandler::GetBackingListObject(
if (NS_WARN_IF(!newBackingListObj)) {
return false;
}
if (NS_WARN_IF(!JS_SetPrototype(aCx, newBackingListObj, nullptr))) {
return false;
}
slotValue = JS::ObjectValue(*newBackingListObj);
js::SetProxyReservedSlot(aProxy, OBSERVABLE_ARRAY_BACKING_LIST_OBJECT_SLOT,
slotValue);

View file

@ -658,8 +658,7 @@ class Manager::CacheMatchAction final : public Manager::BaseAction {
// If we entered shutdown on the main thread while we were doing IO,
// bail out now.
if (IsCanceled() ||
AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownQM)) {
if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownQM)) {
if (stream) {
stream->Close();
}
@ -735,8 +734,7 @@ class Manager::CacheMatchAllAction final : public Manager::BaseAction {
// If we entered shutdown on the main thread while we were doing IO,
// bail out now.
if (IsCanceled() ||
AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownQM)) {
if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownQM)) {
if (stream) {
stream->Close();
}
@ -1291,8 +1289,7 @@ class Manager::CacheKeysAction final : public Manager::BaseAction {
// If we entered shutdown on the main thread while we were doing IO,
// bail out now.
if (IsCanceled() ||
AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownQM)) {
if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownQM)) {
if (stream) {
stream->Close();
}
@ -1371,8 +1368,7 @@ class Manager::StorageMatchAction final : public Manager::BaseAction {
// If we entered shutdown on the main thread while we were doing IO,
// bail out now.
if (IsCanceled() ||
AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownQM)) {
if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownQM)) {
if (stream) {
stream->Close();
}

View file

@ -30,6 +30,7 @@ StreamList::StreamList(SafeRefPtr<Manager> aManager,
mStreamControl(nullptr),
mActivated(false) {
MOZ_DIAGNOSTIC_ASSERT(mManager);
mContext->AddActivity(*this);
}
Manager& StreamList::GetManager() const {
@ -72,9 +73,6 @@ 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);
@ -136,7 +134,6 @@ 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.
@ -195,13 +192,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

View file

@ -880,8 +880,6 @@ 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)
@ -2890,12 +2888,8 @@ void CanvasRenderingContext2D::GetLetterSpacing(nsACString& aLetterSpacing) {
void CanvasRenderingContext2D::SetLetterSpacing(
const nsACString& aLetterSpacing) {
nsAutoCString normalized;
Maybe<float> value = ParseSpacing(aLetterSpacing, normalized);
if (value) {
CurrentState().letterSpacing = *value;
CurrentState().letterSpacingStr = normalized;
}
ParseSpacing(aLetterSpacing, &CurrentState().letterSpacing,
CurrentState().letterSpacingStr);
}
void CanvasRenderingContext2D::GetWordSpacing(nsACString& aWordSpacing) {
@ -2907,12 +2901,8 @@ void CanvasRenderingContext2D::GetWordSpacing(nsACString& aWordSpacing) {
}
void CanvasRenderingContext2D::SetWordSpacing(const nsACString& aWordSpacing) {
nsAutoCString normalized;
Maybe<float> value = ParseSpacing(aWordSpacing, normalized);
if (value) {
CurrentState().wordSpacing = *value;
CurrentState().wordSpacingStr = normalized;
}
ParseSpacing(aWordSpacing, &CurrentState().wordSpacing,
CurrentState().wordSpacingStr);
}
static GeckoFontMetrics GetFontMetricsFromCanvas(void* aContext) {
@ -2943,8 +2933,9 @@ static GeckoFontMetrics GetFontMetricsFromCanvas(void* aContext) {
0.0f};
}
Maybe<float> CanvasRenderingContext2D::ParseSpacing(const nsACString& aSpacing,
nsACString& aNormalized) {
void CanvasRenderingContext2D::ParseSpacing(const nsACString& aSpacing,
float* aValue,
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.
@ -2952,28 +2943,28 @@ Maybe<float> CanvasRenderingContext2D::ParseSpacing(const nsACString& aSpacing,
normalized.CompressWhitespace(true, true);
ToLowerCase(normalized);
if (normalized.EqualsLiteral("normal")) {
return Nothing();
return;
}
float value;
if (!Servo_ParseLengthWithoutStyleContext(&normalized, &value,
GetFontMetricsFromCanvas, this)) {
if (!GetPresShell()) {
return Nothing();
return;
}
// This will parse aSpacing as a <length-percentage>...
RefPtr<const ComputedStyle> style =
ResolveStyleForProperty(eCSSProperty_letter_spacing, aSpacing);
if (!style) {
return Nothing();
return;
}
// ...but only <length> is allowed according to the canvas spec.
if (!style->StyleText()->mLetterSpacing.IsLength()) {
return Nothing();
return;
}
value = style->StyleText()->mLetterSpacing.AsLength().ToCSSPixels();
}
aNormalized = normalized;
return Some(value);
*aValue = value;
}
class CanvasUserSpaceMetrics final : public UserSpaceMetricsWithSize {
@ -3443,11 +3434,6 @@ 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,
@ -3455,6 +3441,10 @@ 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());
@ -4705,7 +4695,6 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor final
}
mCtx->EnsureTarget();
const bool needBounds = mCtx->NeedToCalculateBounds();
if (!mCtx->IsTargetValid()) {
return;
}
@ -4720,7 +4709,7 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor final
const ContextState& state = mCtx->CurrentState();
gfx::Rect bounds;
if (needBounds) {
if (mCtx->NeedToCalculateBounds()) {
bounds = ToRect(mBoundingBox);
bounds.MoveBy(mPt / mAppUnitsPerDevPixel);
if (style == Style::STROKE) {
@ -4868,9 +4857,6 @@ 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;
@ -4896,6 +4882,8 @@ 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;
@ -5175,54 +5163,50 @@ 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 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;
} else {
return fontGroup;
NS_ERROR("Default canvas font is invalid");
}
}
}
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;
return fontGroup;
}
//
@ -5727,7 +5711,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);

View file

@ -613,13 +613,11 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,
protected:
/**
* Helper to parse a value for the letterSpacing or wordSpacing attribute.
* 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).
* If successful, returns the result in aValue, and the whitespace-normalized
* value string in aNormalized; if unsuccessful these are left untouched.
*/
mozilla::Maybe<float> ParseSpacing(const nsACString& aSpacing,
nsACString& aNormalized);
void ParseSpacing(const nsACString& aSpacing, float* aValue,
nsACString& aNormalized);
already_AddRefed<const ComputedStyle> ResolveStyleForProperty(
nsCSSPropertyID aProperty, const nsACString& aValue);
@ -1002,14 +1000,10 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,
* last call to UpdateFilter and now.
*/
const gfx::FilterDescription& EnsureUpdatedFilter() {
bool isWriteOnly = IsWriteOnly() ||
(mCanvasElement && mCanvasElement->IsWriteOnly()) ||
(mOffscreenCanvas && mOffscreenCanvas->IsWriteOnly());
bool isWriteOnly = mCanvasElement && mCanvasElement->IsWriteOnly();
if (CurrentState().filterSourceGraphicTainted != isWriteOnly) {
// 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);
UpdateFilter(/* aFlushIfNeeded = */ true);
EnsureTarget();
}
MOZ_ASSERT(CurrentState().filterSourceGraphicTainted == isWriteOnly);
return CurrentState().filter;

View file

@ -198,18 +198,7 @@ ClientWebGLContext::ClientWebGLContext(const bool webgl2)
: mIsWebGL2(webgl2),
mExtLoseContext(new ClientWebGLExtensionLoseContext(*this)) {}
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);
}
ClientWebGLContext::~ClientWebGLContext() { RemovePostRefreshObserver(); }
void ClientWebGLContext::JsWarning(const std::string& utf8) const {
nsIGlobalObject* global = nullptr;
@ -4522,14 +4511,6 @@ 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);
@ -7023,7 +7004,11 @@ void ImplCycleCollectionTraverse(
}
void ImplCycleCollectionUnlink(std::shared_ptr<webgl::NotLostData>& field) {
SafeReleaseNotLostData(field);
if (!field) return;
const auto keepAlive = field;
keepAlive->extensions = {};
keepAlive->state = {};
field = nullptr;
}
// -----------------------------------------------------

View file

@ -21,6 +21,7 @@
#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"
@ -816,7 +817,7 @@ bool DrawTargetWebgl::GenerateComplexClipMask() {
return !!data;
}
Maybe<Rect> DrawTargetWebgl::ComputeSimpleClipRect() const {
bool DrawTargetWebgl::SetSimpleClipRect() {
// Determine whether the clipping rectangle is simple enough to accelerate.
// Check if there is a device space clip rectangle available from the Skia
// target.
@ -828,7 +829,9 @@ Maybe<Rect> DrawTargetWebgl::ComputeSimpleClipRect() const {
if (!clip->IsEmpty() && clip->Contains(GetRect())) {
clip = Some(GetRect());
}
return Some(Rect(*clip));
mSharedContext->SetClipRect(*clip);
mSharedContext->SetNoClipMask();
return true;
}
// There was no pixel-aligned clip rect available, so check the clip stack to
@ -839,22 +842,15 @@ Maybe<Rect> DrawTargetWebgl::ComputeSimpleClipRect() const {
// complex.
if (clipStack.mPath ||
!clipStack.mTransform.PreservesAxisAlignedRectangles()) {
return Nothing();
return false;
}
// Transform the rect and intersect it with the current clip.
rect =
clipStack.mTransform.TransformBounds(clipStack.mRect).Intersect(rect);
}
return Some(rect);
}
bool DrawTargetWebgl::SetSimpleClipRect() {
if (Maybe<Rect> rect = ComputeSimpleClipRect()) {
mSharedContext->SetClipRect(*rect);
mSharedContext->SetNoClipMask();
return true;
}
return false;
mSharedContext->SetClipRect(rect);
mSharedContext->SetNoClipMask();
return true;
}
// Installs the Skia clip rectangle, if applicable, onto the shared WebGL
@ -878,21 +874,6 @@ 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();
}
@ -924,12 +905,29 @@ bool DrawTargetWebgl::CanCreate(const IntSize& aSize, SurfaceFormat aFormat) {
return false;
}
// Maximum pref allows 2 different options:
// <= 0 means unlimited size,
// Maximum pref allows 3 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 && std::max(aSize.width, aSize.height) > maxSize) {
return false;
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;
}
}
}
return true;
@ -1647,7 +1645,9 @@ 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 && !ShouldClip()) {
if (containsViewport && mSharedContext->IsCurrentTarget(this) &&
!mSharedContext->HasClipMask() &&
mSharedContext->mClipAARect.Contains(Rect(GetRect()))) {
mIsClear = true;
}
}
@ -2038,7 +2038,6 @@ 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.
@ -2059,15 +2058,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.
map.emplace(aData, DataSourceSurface::READ);
if (!map->IsMapped()) {
DataSourceSurface::ScopedMap map(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

View file

@ -617,11 +617,9 @@ 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,

View file

@ -146,29 +146,10 @@ already_AddRefed<ImageData> ImageData::ReadStructuredClone(
!JS_ReadTypedArray(aReader, &dataArray)) {
return nullptr;
}
MOZ_ASSERT(dataArray.isObject());
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);
JS::Rooted<JSObject*> arrayObj(aCx, &dataArray.toObject());
RefPtr<ImageData> imageData = new ImageData(aGlobal, width, height, arrayObj);
return imageData.forget();
}

View file

@ -391,8 +391,8 @@ static bool HasColorAndAlpha(const WebGLTexelFormat format) {
}
bool TexUnpackBlob::ConvertIfNeeded(
const WebGLContext* const webgl, const size_t rowLength,
const size_t rowCount, WebGLTexelFormat srcFormat,
const WebGLContext* const webgl, const uint32_t rowLength,
const uint32_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 = CheckedInt<size_t>(rowCount) * dstStride;
const auto dstTotalBytes = CheckedUint32(rowCount) * dstStride;
if (!dstTotalBytes.isValid()) {
webgl->ErrorOutOfMemory("Calculation failed.");
return false;
@ -855,14 +855,9 @@ bool TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec,
: dom::PredefinedColorSpace::Srgb;
bool sameColorSpace = (srcColorSpace == dstColorSpace);
Maybe<std::string> reason;
if (!webgl->IsUploadableSdType(sd)) {
reason = Some(std::string("Unsupported surface descriptor type"));
} else {
reason = BlitPreventReason(
const auto reason = BlitPreventReason(
level, {xOffset, yOffset, zOffset}, dui->internalFormat, pi, mDesc,
webgl->mOptionalRenderableFormatBits, sameColorSpace);
}
if (reason) {
webgl->GeneratePerfWarning(
"Failed to hit GPU-copy fast-path."
@ -1115,6 +1110,10 @@ bool TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec,
////
const auto surfSize = surf->GetSize();
if (uint32_t(surfSize.width) < size.x || uint32_t(surfSize.height) < size.y) {
gfxCriticalError() << "Source surface size too small for upload.";
return false;
}
WebGLTexelFormat srcFormat;
uint8_t srcBPP;
@ -1166,12 +1165,6 @@ bool TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec,
const auto& dstUnpacking = dstUnpackingRes.inspect();
MOZ_ASSERT(dstUnpacking.metrics.bytesPerRowStride == dstStride);
if (uint32_t(surfSize.width) < dstUnpacking.metrics.usedPixelsPerRow ||
uint32_t(surfSize.height) < dstUnpacking.metrics.totalRows) {
gfxCriticalError() << "Source surface size too small for upload.";
return false;
}
// -
const uint8_t* dstBegin = srcBegin;

View file

@ -65,8 +65,8 @@ class TexUnpackBlob {
virtual ~TexUnpackBlob() = default;
protected:
bool ConvertIfNeeded(const WebGLContext*, const size_t rowLength,
const size_t rowCount, WebGLTexelFormat srcFormat,
bool ConvertIfNeeded(const WebGLContext*, const uint32_t rowLength,
const uint32_t rowCount, WebGLTexelFormat srcFormat,
const uint8_t* const srcBegin, const ptrdiff_t srcStride,
WebGLTexelFormat dstFormat, const ptrdiff_t dstStride,

View file

@ -630,6 +630,50 @@ 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,
@ -665,7 +709,7 @@ RefPtr<WebGLContext> WebGLContext::Create(HostWebGLContext* host,
out->options = webgl->mOptions;
out->limits = *webgl->mLimits;
out->uploadableSdTypes = webgl->mUploadableSdTypes;
out->uploadableSdTypes = UploadableSdTypes();
out->vendor = webgl->gl->Vendor();
out->optionalRenderableFormatBits = webgl->mOptionalRenderableFormatBits;
@ -767,58 +811,6 @@ 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(
@ -2795,23 +2787,6 @@ 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;
@ -2917,9 +2892,7 @@ webgl::ExplicitPixelPackingState::ForUseWith(
const auto elemsPerRowStride = ElemsPerRowStride();
const auto bytesPerRowStride = pii.bytesPerElement * elemsPerRowStride;
const auto maxBytesPerRow = StaticPrefs::webgl_max_bytes_per_row();
if (!bytesPerRowStride.isValid() ||
(maxBytesPerRow > 0 && bytesPerRowStride.value() > maxBytesPerRow)) {
if (!bytesPerRowStride.isValid()) {
return Err("ROW_LENGTH or width too large for packing.");
}
metrics.bytesPerRowStride = bytesPerRowStride.value();

View file

@ -292,7 +292,6 @@ 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();
@ -341,7 +340,6 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr {
webgl::OptionalRenderableFormatBits mOptionalRenderableFormatBits =
webgl::OptionalRenderableFormatBits{0};
void FinishInit();
void InitUploadableSdTypes();
protected:
WebGLContext(HostWebGLContext*, const webgl::InitContextDesc&);
@ -997,8 +995,6 @@ 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)

Some files were not shown because too many files have changed in this diff Show more