Compare commits

...

3 commits

2933 changed files with 125637 additions and 65042 deletions

View file

@ -85,9 +85,9 @@ git = "https://github.com/mozilla/audioipc"
rev = "e6f44a2bd1e57d11dfc737632a9e849077632330" rev = "e6f44a2bd1e57d11dfc737632a9e849077632330"
replace-with = "vendored-sources" replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=2407441a2f67341a0e13b4ba6547555e387c671c"] [source."git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=bebaa23317332c95734df76e25193c24a83a6840"]
git = "https://github.com/mozilla/cubeb-coreaudio-rs" git = "https://github.com/mozilla/cubeb-coreaudio-rs"
rev = "2407441a2f67341a0e13b4ba6547555e387c671c" rev = "bebaa23317332c95734df76e25193c24a83a6840"
replace-with = "vendored-sources" replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/cubeb-pulse-rs?rev=8678dcab1c287de79c4c184ccc2e065bc62b70e2"] [source."git+https://github.com/mozilla/cubeb-pulse-rs?rev=8678dcab1c287de79c4c184ccc2e065bc62b70e2"]
@ -100,9 +100,9 @@ git = "https://github.com/mozilla/midir.git"
rev = "85156e360a37d851734118104619f86bd18e94c6" rev = "85156e360a37d851734118104619f86bd18e94c6"
replace-with = "vendored-sources" replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/mp4parse-rust?rev=e64650a686e5c5732395cd059e17cfd3b1e5b63b"] [source."git+https://github.com/mozilla/mp4parse-rust?rev=25ebfa59a21dc0d223052d73a2fafdd55307c2d7"]
git = "https://github.com/mozilla/mp4parse-rust" git = "https://github.com/mozilla/mp4parse-rust"
rev = "e64650a686e5c5732395cd059e17cfd3b1e5b63b" rev = "25ebfa59a21dc0d223052d73a2fafdd55307c2d7"
replace-with = "vendored-sources" replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/neqo?tag=v0.13.4"] [source."git+https://github.com/mozilla/neqo?tag=v0.13.4"]

View file

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

7
icecat/.gitignore vendored
View file

@ -37,6 +37,10 @@ ID
# third-party packages is dealt with by the script vendoring them. # third-party packages is dealt with by the script vendoring them.
*.egg-info/ *.egg-info/
# Ignore pywebsocket3 intermediate files.
testing/web-platform/tests/tools/third_party/pywebsocket3/pywebsocket3.egg-info
testing/web-platform/tests/tools/third_party/pywebsocket3/build
# Vim swap files. # Vim swap files.
.*.sw[a-z] .*.sw[a-z]
.sw[a-z] .sw[a-z]
@ -369,3 +373,6 @@ toolkit/crashreporter/minidump-analyzer/analyzer-test/target/
# Ignore mozperftest artifacts folder # Ignore mozperftest artifacts folder
/artifacts/ /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 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more. # don't change CLOBBER for WebIDL changes any more.
Merge day clobber 2025-12-08 Merge day clobber 2026-03-23

8
icecat/Cargo.lock generated
View file

@ -1086,7 +1086,7 @@ dependencies = [
[[package]] [[package]]
name = "coreaudio-sys-utils" name = "coreaudio-sys-utils"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=2407441a2f67341a0e13b4ba6547555e387c671c#2407441a2f67341a0e13b4ba6547555e387c671c" source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=bebaa23317332c95734df76e25193c24a83a6840#bebaa23317332c95734df76e25193c24a83a6840"
dependencies = [ dependencies = [
"core-foundation-sys", "core-foundation-sys",
"coreaudio-sys", "coreaudio-sys",
@ -1398,7 +1398,7 @@ dependencies = [
[[package]] [[package]]
name = "cubeb-coreaudio" name = "cubeb-coreaudio"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=2407441a2f67341a0e13b4ba6547555e387c671c#2407441a2f67341a0e13b4ba6547555e387c671c" source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=bebaa23317332c95734df76e25193c24a83a6840#bebaa23317332c95734df76e25193c24a83a6840"
dependencies = [ dependencies = [
"atomic", "atomic",
"audio-mixer", "audio-mixer",
@ -4607,7 +4607,7 @@ dependencies = [
[[package]] [[package]]
name = "mp4parse" name = "mp4parse"
version = "0.17.0" version = "0.17.0"
source = "git+https://github.com/mozilla/mp4parse-rust?rev=e64650a686e5c5732395cd059e17cfd3b1e5b63b#e64650a686e5c5732395cd059e17cfd3b1e5b63b" source = "git+https://github.com/mozilla/mp4parse-rust?rev=25ebfa59a21dc0d223052d73a2fafdd55307c2d7#25ebfa59a21dc0d223052d73a2fafdd55307c2d7"
dependencies = [ dependencies = [
"bitreader", "bitreader",
"byteorder", "byteorder",
@ -4624,7 +4624,7 @@ version = "0.1.0"
[[package]] [[package]]
name = "mp4parse_capi" name = "mp4parse_capi"
version = "0.17.0" version = "0.17.0"
source = "git+https://github.com/mozilla/mp4parse-rust?rev=e64650a686e5c5732395cd059e17cfd3b1e5b63b#e64650a686e5c5732395cd059e17cfd3b1e5b63b" source = "git+https://github.com/mozilla/mp4parse-rust?rev=25ebfa59a21dc0d223052d73a2fafdd55307c2d7#25ebfa59a21dc0d223052d73a2fafdd55307c2d7"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"fallible_collections", "fallible_collections",

View file

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

View file

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

View file

@ -71,10 +71,14 @@ void CachedTableAccessible::Invalidate(Accessible* aAcc) {
return; return;
} }
if (Accessible* table = nsAccUtils::TableFor(aAcc)) { Accessible* table = nsAccUtils::TableFor(aAcc);
while (table && table->IsTable()) {
// Destroy the instance (if any). We'll create a new one the next time it // Destroy the instance (if any). We'll create a new one the next time it
// is requested. // is requested. Climb up the heirarcy to invalidate parent tables as well.
sCachedTables->Remove(table); 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; return startFrameSel ? &startFrameSel->NormalSelection() : nullptr;
} }
std::pair<nsIContent*, uint32_t> TextLeafPoint::ToDOMPoint( std::pair<RefPtr<nsIContent>, uint32_t> TextLeafPoint::ToDOMPoint(
bool aIncludeGenerated) const { bool aIncludeGenerated) const {
if (!(*this) || !mAcc->IsLocal()) { if (!(*this) || !mAcc->IsLocal()) {
MOZ_ASSERT_UNREACHABLE("Invalid point"); MOZ_ASSERT_UNREACHABLE("Invalid point");

View file

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

View file

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

View file

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

View file

@ -50,6 +50,7 @@ DocAccessibleParent::DocAccessibleParent()
mTopLevel(false), mTopLevel(false),
mTopLevelInContentProcess(false), mTopLevelInContentProcess(false),
mShutdown(false), mShutdown(false),
mIsInitialTreeDone(false),
mFocus(0), mFocus(0),
mCaretId(0), mCaretId(0),
mCaretOffset(-1), mCaretOffset(-1),
@ -117,6 +118,11 @@ mozilla::ipc::IPCResult DocAccessibleParent::ProcessShowEvent(
return IPC_OK(); return IPC_OK();
#endif #endif
} }
if (parent->IsOuterDoc()) {
return IPC_FAIL(this, "Cannot attach non-doc to OuterDoc");
}
lastParent = parent; lastParent = parent;
lastParentID = accData.ParentID(); lastParentID = accData.ParentID();
@ -145,7 +151,9 @@ mozilla::ipc::IPCResult DocAccessibleParent::ProcessShowEvent(
// Otherwise, clients might crawl the incomplete subtree and they won't get // Otherwise, clients might crawl the incomplete subtree and they won't get
// mutation events for the remaining pieces. // mutation events for the remaining pieces.
if (aComplete || root != child) { if (aComplete || root != child) {
AttachChild(parent, childIdx, child); if (!AttachChild(parent, childIdx, child)) {
return IPC_FAIL(this, "failed to attach child");
}
} }
} }
@ -174,7 +182,9 @@ mozilla::ipc::IPCResult DocAccessibleParent::ProcessShowEvent(
MOZ_ASSERT(rootParent); MOZ_ASSERT(rootParent);
root = GetAccessible(mPendingShowChild); root = GetAccessible(mPendingShowChild);
MOZ_ASSERT(root); MOZ_ASSERT(root);
AttachChild(rootParent, mPendingShowIndex, root); if (!AttachChild(rootParent, mPendingShowIndex, root)) {
return IPC_FAIL(this, "failed to attach pending show child");
}
mPendingShowChild = 0; mPendingShowChild = 0;
mPendingShowParent = 0; mPendingShowParent = 0;
mPendingShowIndex = 0; mPendingShowIndex = 0;
@ -218,6 +228,11 @@ mozilla::ipc::IPCResult DocAccessibleParent::ProcessShowEvent(
RemoteAccessible* DocAccessibleParent::CreateAcc( RemoteAccessible* DocAccessibleParent::CreateAcc(
const AccessibleData& aAccData) { const AccessibleData& aAccData) {
if (aAccData.ID() == 0) {
MOZ_ASSERT_UNREACHABLE("An ID of 0 is reserved for the document itself");
return nullptr;
}
RemoteAccessible* newProxy; RemoteAccessible* newProxy;
if ((newProxy = GetAccessible(aAccData.ID()))) { if ((newProxy = GetAccessible(aAccData.ID()))) {
// This is a move. Reuse the Accessible; don't destroy it. // This is a move. Reuse the Accessible; don't destroy it.
@ -234,6 +249,11 @@ RemoteAccessible* DocAccessibleParent::CreateAcc(
return nullptr; return nullptr;
} }
if (aAccData.GenericTypes() & eDocument) {
MOZ_ASSERT_UNREACHABLE("Invalid acc type");
return nullptr;
}
newProxy = new RemoteAccessible(aAccData.ID(), this, aAccData.Role(), newProxy = new RemoteAccessible(aAccData.ID(), this, aAccData.Role(),
aAccData.Type(), aAccData.GenericTypes(), aAccData.Type(), aAccData.GenericTypes(),
aAccData.RoleMapEntryIndex()); aAccData.RoleMapEntryIndex());
@ -246,9 +266,20 @@ RemoteAccessible* DocAccessibleParent::CreateAcc(
return newProxy; return newProxy;
} }
void DocAccessibleParent::AttachChild(RemoteAccessible* aParent, bool DocAccessibleParent::AttachChild(RemoteAccessible* aParent,
uint32_t aIndex, uint32_t aIndex,
RemoteAccessible* aChild) { 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); aParent->AddChildAt(aIndex, aChild);
aChild->SetParent(aParent); aChild->SetParent(aParent);
// ProxyCreated might have already been called if aChild is being moved. // ProxyCreated might have already been called if aChild is being moved.
@ -269,11 +300,16 @@ void DocAccessibleParent::AttachChild(RemoteAccessible* aParent,
} }
MOZ_ASSERT(bridge->GetEmbedderAccessibleDoc() == this); MOZ_ASSERT(bridge->GetEmbedderAccessibleDoc() == this);
if (DocAccessibleParent* childDoc = bridge->GetDocAccessibleParent()) { 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); AddChildDoc(childDoc, aChild->ID(), false);
} }
return true; return true;
}); });
} }
return true;
} }
void DocAccessibleParent::ShutdownOrPrepareForMove(RemoteAccessible* aAcc) { void DocAccessibleParent::ShutdownOrPrepareForMove(RemoteAccessible* aAcc) {
@ -286,6 +322,10 @@ void DocAccessibleParent::ShutdownOrPrepareForMove(RemoteAccessible* aAcc) {
// the show event. For now, clear all of them by moving them to a temporary. // the show event. For now, clear all of them by moving them to a temporary.
auto children{std::move(aAcc->mChildren)}; auto children{std::move(aAcc->mChildren)};
for (RemoteAccessible* child : children) { for (RemoteAccessible* child : children) {
if (child == aAcc) {
MOZ_ASSERT_UNREACHABLE(
"Somehow an accessible got added as a child of itself!");
}
ShutdownOrPrepareForMove(child); ShutdownOrPrepareForMove(child);
} }
} }
@ -603,6 +643,18 @@ mozilla::ipc::IPCResult DocAccessibleParent::RecvMutationEvents(
mozilla::ipc::IPCResult DocAccessibleParent::RecvRequestAckMutationEvents() { mozilla::ipc::IPCResult DocAccessibleParent::RecvRequestAckMutationEvents() {
if (!mShutdown) { 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(); Unused << SendAckMutationEvents();
} }
return IPC_OK(); return IPC_OK();
@ -864,7 +916,10 @@ mozilla::ipc::IPCResult DocAccessibleParent::RecvBindChildDoc(
MOZ_ASSERT(CheckDocTree()); MOZ_ASSERT(CheckDocTree());
auto childDoc = static_cast<DocAccessibleParent*>(aChildDoc.get()); auto childDoc = static_cast<DocAccessibleParent*>(aChildDoc.get());
childDoc->Unbind(); if (childDoc->IsShutdown()) {
return IPC_FAIL(this, "Attempt to bind a shutdown child doc");
}
ipc::IPCResult result = AddChildDoc(childDoc, aID, false); ipc::IPCResult result = AddChildDoc(childDoc, aID, false);
MOZ_ASSERT(result); MOZ_ASSERT(result);
MOZ_ASSERT(CheckDocTree()); MOZ_ASSERT(CheckDocTree());
@ -882,6 +937,15 @@ mozilla::ipc::IPCResult DocAccessibleParent::RecvBindChildDoc(
ipc::IPCResult DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc, ipc::IPCResult DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc,
uint64_t aParentID, uint64_t aParentID,
bool aCreating) { 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 // We do not use GetAccessible here because we want to be sure to not get the
// document it self. // document it self.
ProxyEntry* e = mAccessibles.GetEntry(aParentID); ProxyEntry* e = mAccessibles.GetEntry(aParentID);
@ -930,11 +994,20 @@ ipc::IPCResult DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc,
aChildDoc->SetEmulatedWindowHandle(mEmulatedWindowHandle); aChildDoc->SetEmulatedWindowHandle(mEmulatedWindowHandle);
} }
#endif // defined(XP_WIN) #endif // defined(XP_WIN)
// We need to fire a reorder event on the outer doc accessible. }
// For same-process documents, this is fired by the content process, but // We need to fire a reorder event on the embedder. We do this here rather
// this isn't possible when the document is in a different process to its // than in the content process for two reasons:
// embedder. // 1. It isn't possible for the content process to fire a reorder event on the
// FireEvent fires both OS and XPCOM events. // 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) {
FireEvent(outerDoc, nsIAccessibleEvent::EVENT_REORDER); FireEvent(outerDoc, nsIAccessibleEvent::EVENT_REORDER);
} }
@ -975,6 +1048,9 @@ void DocAccessibleParent::Destroy() {
// If we are already shutdown that is because our containing tab parent is // 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. // shutting down in which case we don't need to do anything.
if (mShutdown) { if (mShutdown) {
// Just in case there is a cycle in the document heirarchy.
mParent = nullptr;
mIndexInParent = -1;
return; return;
} }
@ -1012,6 +1088,8 @@ void DocAccessibleParent::Destroy() {
RemoteAccessible* acc = iter.Get()->mProxy; RemoteAccessible* acc = iter.Get()->mProxy;
MOZ_ASSERT(acc != this); MOZ_ASSERT(acc != this);
if (acc->IsTable()) { if (acc->IsTable()) {
// Prevents the invalidation code from trying to walk up the tree.
acc->SetParent(nullptr);
CachedTableAccessible::Invalidate(acc); CachedTableAccessible::Invalidate(acc);
} }
ProxyDestroyed(acc); ProxyDestroyed(acc);
@ -1057,6 +1135,9 @@ void DocAccessibleParent::ActorDestroy(ActorDestroyReason aWhy) {
if (!mShutdown) { if (!mShutdown) {
ACQUIRE_ANDROID_LOCK ACQUIRE_ANDROID_LOCK
Destroy(); Destroy();
} else if (RemoteParent()) {
ACQUIRE_ANDROID_LOCK
Unbind();
} }
} }

View file

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

View file

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

View file

@ -0,0 +1,29 @@
/* 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,25 +16,9 @@ function getSiteBlockedErrorDetails(docShell) {
Ci.nsIClassifiedChannel Ci.nsIClassifiedChannel
); );
if (classifiedChannel) { 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 = { blockedInfo = {
list: classifiedChannel.matchedList, list: classifiedChannel.matchedList,
triggeringPrincipal,
provider: classifiedChannel.matchedProvider, provider: classifiedChannel.matchedProvider,
uri: reportUri.asciiSpec,
}; };
} }
} }

View file

@ -177,8 +177,11 @@ export class BlockedSiteParent extends EscapablePageParent {
// site, so that they don't lose track after, e.g., tab switching. // 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 // We can't use browser.contentPrincipal which is principal of about:blocked
// Create one from uri with current principal origin attributes // 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( let principal = Services.scriptSecurityManager.createContentPrincipal(
Services.io.newURI(blockedInfo.uri), uri,
browsingContext.currentWindowGlobal.documentPrincipal.originAttributes browsingContext.currentWindowGlobal.documentPrincipal.originAttributes
); );
Services.perms.addFromPrincipal( Services.perms.addFromPrincipal(
@ -206,10 +209,10 @@ export class BlockedSiteParent extends EscapablePageParent {
let title; let title;
let chromeWin = browsingContext.topChromeWindow; let chromeWin = browsingContext.topChromeWindow;
if (reason === "malware") { if (reason === "malware") {
let reportUrl = lazy.SafeBrowsing.getReportURL( let reportUrl = lazy.SafeBrowsing.getReportURL("MalwareMistake", {
"MalwareMistake", ...blockedInfo,
blockedInfo uri: uri.asciiSpec,
); });
title = lazy.browserBundle.GetStringFromName( title = lazy.browserBundle.GetStringFromName(
"safebrowsing.reportedAttackSite" "safebrowsing.reportedAttackSite"
); );
@ -233,10 +236,10 @@ export class BlockedSiteParent extends EscapablePageParent {
}; };
} }
} else if (reason === "phishing") { } else if (reason === "phishing") {
let reportUrl = lazy.SafeBrowsing.getReportURL( let reportUrl = lazy.SafeBrowsing.getReportURL("PhishMistake", {
"PhishMistake", ...blockedInfo,
blockedInfo uri: uri.asciiSpec,
); });
title = lazy.browserBundle.GetStringFromName( title = lazy.browserBundle.GetStringFromName(
"safebrowsing.deceptiveSite" "safebrowsing.deceptiveSite"
); );
@ -281,16 +284,15 @@ export class BlockedSiteParent extends EscapablePageParent {
buttons buttons
); );
// Allow users to override and continue through to the site. let activeSHEntry = browsingContext.activeSessionHistoryEntry;
// Note that we have to use the passed URI info and can't just if (!activeSHEntry) {
// rely on the document URI, because the latter contains console.error("No active session history entry found");
// additional query parameters that should be stripped. return;
let triggeringPrincipal = }
blockedInfo.triggeringPrincipal ||
Services.scriptSecurityManager.createNullPrincipal({});
browsingContext.fixupAndLoadURIString(blockedInfo.uri, { // Allow users to override and continue through to the site.
triggeringPrincipal, browsingContext.loadURI(uri, {
triggeringPrincipal: activeSHEntry.triggeringPrincipal,
loadFlags: Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CLASSIFIER, loadFlags: Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CLASSIFIER,
}); });
} }

View file

@ -142,9 +142,7 @@ export class DOMFullscreenParent extends JSWindowActorParent {
case "DOMFullscreen:NewOrigin": { case "DOMFullscreen:NewOrigin": {
// Don't show the warning if we've already exited fullscreen. // Don't show the warning if we've already exited fullscreen.
if (window.document.fullscreen) { if (window.document.fullscreen) {
window.PointerlockFsWarning.showFullScreen( window.PointerlockFsWarning.showFullScreen(topBrowsingContext);
aMessage.data.originNoSuffix
);
} }
this.updateFullscreenWindowReference(window); this.updateFullscreenWindowReference(window);
break; break;
@ -222,7 +220,7 @@ export class DOMFullscreenParent extends JSWindowActorParent {
if (!this.hasBeenDestroyed() && this.requestOrigin) { if (!this.hasBeenDestroyed() && this.requestOrigin) {
window.PointerlockFsWarning.showFullScreen( window.PointerlockFsWarning.showFullScreen(
this.requestOrigin.manager.documentPrincipal.originNoSuffix this.requestOrigin.browsingContext
); );
} }
break; break;

View file

@ -11,7 +11,6 @@
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/CmdLineAndEnvUtils.h" #include "mozilla/CmdLineAndEnvUtils.h"
#include "mozilla/DebugOnly.h" #include "mozilla/DebugOnly.h"
#include "mozilla/DynamicallyLinkedFunctionPtr.h"
#include "mozilla/glue/Debug.h" #include "mozilla/glue/Debug.h"
#include "mozilla/GeckoArgs.h" #include "mozilla/GeckoArgs.h"
#include "mozilla/Maybe.h" #include "mozilla/Maybe.h"
@ -19,12 +18,14 @@
#include "mozilla/SafeMode.h" #include "mozilla/SafeMode.h"
#include "mozilla/UniquePtr.h" #include "mozilla/UniquePtr.h"
#include "mozilla/WindowsConsole.h" #include "mozilla/WindowsConsole.h"
#include "mozilla/WindowsProcessMitigations.h"
#include "mozilla/WindowsVersion.h" #include "mozilla/WindowsVersion.h"
#include "mozilla/WinHeaderOnlyUtils.h" #include "mozilla/WinHeaderOnlyUtils.h"
#include "nsWindowsHelpers.h" #include "nsWindowsHelpers.h"
#include <windows.h> #include <windows.h>
#include <processthreadsapi.h> #include <processthreadsapi.h>
#include <shlwapi.h>
#include "DllBlocklistInit.h" #include "DllBlocklistInit.h"
#include "ErrorHandler.h" #include "ErrorHandler.h"
@ -111,16 +112,82 @@ static nsReturnRef<HANDLE> CreateJobAndAssignProcess(HANDLE aProcess) {
return job.out(); return job.out();
} }
#if !defined( \ enum class VCRuntimeDLLDir : bool {
PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON) Application,
# define PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON \ System,
(0x00000001ULL << 60) };
#endif // !defined(PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON) static bool GetMSVCP140VersionInfo(VCRuntimeDLLDir aDir,
uint64_t& aOutVersion) {
wchar_t dllPath[MAX_PATH];
if (aDir == VCRuntimeDLLDir::Application) {
DWORD size = ::GetModuleFileNameW(nullptr, dllPath, MAX_PATH);
if (!size ||
(size == MAX_PATH && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) ||
!::PathRemoveFileSpecW(dllPath)) {
return false;
}
} else {
MOZ_ASSERT(aDir == VCRuntimeDLLDir::System);
UINT size = ::GetSystemDirectoryW(dllPath, MAX_PATH);
if (!size || size >= MAX_PATH) {
return false;
}
}
#if !defined(PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_OFF) if (!::PathAppendW(dllPath, L"msvcp140.dll")) {
# define PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_OFF \ return false;
(0x00000002ULL << 40) }
#endif // !defined(PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_OFF) HMODULE crt =
::LoadLibraryExW(dllPath, nullptr, LOAD_LIBRARY_AS_IMAGE_RESOURCE);
if (!crt) {
return false;
}
mozilla::nt::PEHeaders headers{crt};
bool result = headers.GetVersionInfo(aOutVersion);
::FreeLibrary(crt);
return result;
}
/**
* Choose whether we want to favor loading DLLs from the system directory over
* the application directory. This choice automatically propagates to all child
* processes. In particular, it determines whether child processes will load
* Visual C++ runtime DLLs from the system or the application directory at
* startup.
*
* Whenever possible, we want all processes to favor loading DLLs from the
* system directory. But if old Visual C++ runtime DLLs are installed
* system-wide, then we must favor loading from the application directory
* instead to ensure compatibility, at least during startup. So in this case we
* only apply the delayed variant of the mitigation and only in sandboxed
* processes, which is the best compromise (see SandboxBroker::LaunchApp).
*
* This function is called from the launcher process *and* the browser process.
* This is because if the launcher process is disabled, we still want the
* browser process to go through this code so that it enforces the correct
* choice for itself and for child processes.
*/
static void EnablePreferLoadFromSystem32IfCompatible() {
// We may already have the mitigation if we are the browser process and we
// inherited it from the launcher process.
if (!mozilla::IsPreferLoadFromSystem32Available() ||
mozilla::IsPreferLoadFromSystem32Enabled()) {
return;
}
// Only bail out if (1) there is a conflict because the two DLLs exist *and*
// (2) the version of the system DLL is problematic.
uint64_t systemDirVersion = 0, appDirVersion = 0;
if (GetMSVCP140VersionInfo(VCRuntimeDLLDir::System, systemDirVersion) &&
GetMSVCP140VersionInfo(VCRuntimeDLLDir::Application, appDirVersion) &&
systemDirVersion < appDirVersion) {
return;
}
mozilla::DebugOnly<bool> setOk = mozilla::EnablePreferLoadFromSystem32();
MOZ_ASSERT(setOk);
}
/** /**
* Any mitigation policies that should be set on the browser process should go * Any mitigation policies that should be set on the browser process should go
@ -128,10 +195,11 @@ static nsReturnRef<HANDLE> CreateJobAndAssignProcess(HANDLE aProcess) {
*/ */
static void SetMitigationPolicies(mozilla::ProcThreadAttributes& aAttrs, static void SetMitigationPolicies(mozilla::ProcThreadAttributes& aAttrs,
const bool aIsSafeMode) { const bool aIsSafeMode) {
if (mozilla::IsWin10AnniversaryUpdateOrLater()) { // Note: Do *not* handle IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON here. For this
aAttrs.AddMitigationPolicy( // mitigation we rely on EnablePreferLoadFromSystem32IfCompatible().
PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON); // The launcher process or the browser process will choose whether we
} // want to apply the mitigation or not, and child processes will
// automatically inherit that choice.
#if defined(_M_ARM64) #if defined(_M_ARM64)
// Disable CFG on older versions of ARM64 Windows to avoid a crash in COM. // Disable CFG on older versions of ARM64 Windows to avoid a crash in COM.
@ -286,6 +354,9 @@ Maybe<int> LauncherMain(int& argc, wchar_t* argv[],
return Nothing(); return Nothing();
} }
// Called from the launcher process *and* the browser process.
EnablePreferLoadFromSystem32IfCompatible();
#if defined(MOZ_LAUNCHER_PROCESS) #if defined(MOZ_LAUNCHER_PROCESS)
LauncherRegistryInfo regInfo; LauncherRegistryInfo regInfo;
Maybe<bool> runAsLauncher = RunAsLauncherProcess(regInfo, argc, argv); Maybe<bool> runAsLauncher = RunAsLauncherProcess(regInfo, argc, argv);
@ -309,22 +380,6 @@ Maybe<int> LauncherMain(int& argc, wchar_t* argv[],
return Nothing(); return Nothing();
} }
// Make sure that the launcher process itself has image load policies set
if (IsWin10AnniversaryUpdateOrLater()) {
static const StaticDynamicallyLinkedFunctionPtr<
decltype(&SetProcessMitigationPolicy)>
pSetProcessMitigationPolicy(L"kernel32.dll",
"SetProcessMitigationPolicy");
if (pSetProcessMitigationPolicy) {
PROCESS_MITIGATION_IMAGE_LOAD_POLICY imgLoadPol = {};
imgLoadPol.PreferSystem32Images = 1;
DebugOnly<BOOL> setOk = pSetProcessMitigationPolicy(
ProcessImageLoadPolicy, &imgLoadPol, sizeof(imgLoadPol));
MOZ_ASSERT(setOk);
}
}
#if defined(MOZ_SANDBOX) #if defined(MOZ_SANDBOX)
// Ensure the relevant mitigations are enforced. // Ensure the relevant mitigations are enforced.
mozilla::sandboxing::ApplyParentProcessMitigations(); mozilla::sandboxing::ApplyParentProcessMitigations();

View file

@ -24,6 +24,7 @@ OS_LIBS += [
"oleaut32", "oleaut32",
"ole32", "ole32",
"rpcrt4", "rpcrt4",
"shlwapi",
"version", "version",
] ]

View file

@ -49,10 +49,16 @@ var PointerlockFsWarning = {
} }
}, },
showFullScreen(aOrigin) { // Show info that top level has entered fullscreen. Ultimately, it is always
// ancestors who are in control and can with various means make the user believe
// a site has entered fullscreen while displaying it's own content.
// We try to make it clear to the user that it's the top level that is actually in fullscreen
showFullScreen(browsingContext) {
const origin =
browsingContext.top.currentWindowGlobal.documentPrincipal.originNoSuffix;
let timeout = Services.prefs.getIntPref("full-screen-api.warning.timeout"); let timeout = Services.prefs.getIntPref("full-screen-api.warning.timeout");
let delay = Services.prefs.getIntPref("full-screen-api.warning.delay"); let delay = Services.prefs.getIntPref("full-screen-api.warning.delay");
this.show(aOrigin, "fullscreen-warning", timeout, delay); this.show(origin, "fullscreen-warning", timeout, delay);
}, },
// Shows a warning that the site has entered fullscreen or // Shows a warning that the site has entered fullscreen or

View file

@ -60,6 +60,9 @@ skip-if = [
"os == 'linux' && os_version == '18.04' && processor == 'x86_64' && swgl", # Bug 1949995 "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"] ["browser_fullscreen_warning.js"]
support-files = ["fullscreen.html"] support-files = ["fullscreen.html"]
skip-if = [ skip-if = [

View file

@ -0,0 +1,184 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const FULLSCREEN_PATH =
"/browser/browser/base/content/test/fullscreen/fullscreen.html";
function getWarningDomain(warning) {
let textElem = warning.querySelector(".pointerlockfswarning-domain-text");
if (textElem.hidden) {
return null;
}
let args = textElem.getAttribute("data-l10n-args");
return args ? JSON.parse(args).domain : null;
}
async function waitForWarningState(aWarningElement, aExpectedState) {
await BrowserTestUtils.waitForAttribute(aExpectedState, aWarningElement, "");
}
add_setup(async function init() {
await SpecialPowers.pushPrefEnv({
set: [
["test.wait300msAfterTabSwitch", true],
["full-screen-api.enabled", true],
["full-screen-api.allow-trusted-requests-only", false],
],
});
});
// Bug 2021080 - Verify the fullscreen warning always displays the top-level domain,
// not the origin of the cross-origin frame that requested fullscreen.
add_task(async function test_fullscreen_warning_cross_origin_shows_toplevel() {
await BrowserTestUtils.withNewTab("https://example.com", async browser => {
let warning = document.getElementById("fullscreen-warning");
await SpecialPowers.spawn(browser, [FULLSCREEN_PATH], async path => {
let iframe = content.document.createElement("iframe");
iframe.allow = "fullscreen";
iframe.src = `https://example.org${path}`;
let loaded = new Promise(r =>
iframe.addEventListener("load", r, { once: true })
);
content.document.body.appendChild(iframe);
await loaded;
});
let warningShown = waitForWarningState(warning, "onscreen");
await SpecialPowers.spawn(browser, [], async () => {
let frame = content.document.querySelector("iframe");
frame.focus();
await SpecialPowers.spawn(frame, [], () => {
content.document.getElementById("request").click();
});
});
await warningShown;
let activeOrigin = await SpecialPowers.spawn(browser, [], async () => {
let frame = content.document.querySelector("iframe");
return SpecialPowers.spawn(frame, [], () => content.location.hostname);
});
is(
activeOrigin,
"example.org",
"Cross-origin frame (example.org) is the active fullscreen document"
);
is(
getWarningDomain(warning),
"example.com",
"Warning shows top-level domain, not the active fullscreen frame's domain"
);
let warningHidden = waitForWarningState(warning, "hidden");
let exitPromise = BrowserTestUtils.waitForEvent(
document,
"fullscreenchange",
false,
() => !document.fullscreenElement
);
document.getElementById("fullscreen-exit-button").click();
await Promise.all([exitPromise, warningHidden]);
});
});
// Bug 2021080 - Verify the fullscreen warning shows the top-level domain when each
// of three nested cross-origin frames (top, middle, inner) requests fullscreen.
add_task(async function test_fullscreen_warning_three_nested_origins() {
await BrowserTestUtils.withNewTab("https://example.com", async browser => {
let warning = document.getElementById("fullscreen-warning");
// Build a 3-level nested structure:
// example.com (div > iframe[example.org (div > iframe[example.net])])
await SpecialPowers.spawn(browser, [FULLSCREEN_PATH], async path => {
let topDiv = content.document.createElement("div");
content.document.body.appendChild(topDiv);
let middleFrame = content.document.createElement("iframe");
middleFrame.allow = "fullscreen";
middleFrame.src = `https://example.org${path}`;
let loaded = new Promise(r =>
middleFrame.addEventListener("load", r, { once: true })
);
topDiv.appendChild(middleFrame);
await loaded;
await SpecialPowers.spawn(middleFrame, [path], async innerPath => {
let middleDiv = content.document.createElement("div");
content.document.body.appendChild(middleDiv);
let innerFrame = content.document.createElement("iframe");
innerFrame.allow = "fullscreen";
innerFrame.src = `https://example.net${innerPath}`;
let innerLoaded = new Promise(r =>
innerFrame.addEventListener("load", r, { once: true })
);
middleDiv.appendChild(innerFrame);
await innerLoaded;
});
});
async function exitFullscreen() {
let warningHidden = waitForWarningState(warning, "hidden");
let exitPromise = BrowserTestUtils.waitForEvent(
document,
"fullscreenchange",
false,
() => !document.fullscreenElement
);
document.getElementById("fullscreen-exit-button").click();
await Promise.all([exitPromise, warningHidden]);
}
// Step 1: Top-level (example.com) requests fullscreen on its div.
let warningShown = waitForWarningState(warning, "onscreen");
await SpecialPowers.spawn(browser, [], () => {
content.document.querySelector("div").requestFullscreen();
});
await warningShown;
is(
getWarningDomain(warning),
"example.com",
"Top-level fullscreen: warning shows top-level domain"
);
await exitFullscreen();
// Step 2: Middle frame (example.org) requests fullscreen on its div.
warningShown = waitForWarningState(warning, "onscreen");
await SpecialPowers.spawn(browser, [], async () => {
let middleFrame = content.document.querySelector("iframe");
middleFrame.focus();
await SpecialPowers.spawn(middleFrame, [], () => {
content.document.querySelector("div").requestFullscreen();
});
});
await warningShown;
is(
getWarningDomain(warning),
"example.com",
"Middle frame fullscreen: warning shows top-level domain"
);
await exitFullscreen();
// Step 3: Inner frame (example.net) requests fullscreen on an element.
warningShown = waitForWarningState(warning, "onscreen");
await SpecialPowers.spawn(browser, [], async () => {
let middleFrame = content.document.querySelector("iframe");
await SpecialPowers.spawn(middleFrame, [], async () => {
let innerFrame = content.document.querySelector("iframe");
innerFrame.focus();
await SpecialPowers.spawn(innerFrame, [], () => {
content.document.getElementById("request").click();
});
});
});
await warningShown;
is(
getWarningDomain(warning),
"example.com",
"Inner frame fullscreen: warning shows top-level domain"
);
await exitFullscreen();
});
});

View file

@ -127,6 +127,9 @@ let JSWINDOWACTORS = {
}, },
}, },
matches: ["about:messagepreview", "about:messagepreview?*"], matches: ["about:messagepreview", "about:messagepreview?*"],
remoteTypes: ["privilegedabout"],
enablePreference:
"browser.newtabpage.activity-stream.asrouter.devtoolsEnabled",
}, },
AboutPocket: { AboutPocket: {

View file

@ -110,6 +110,7 @@ static const RedirEntry kRedirMap[] = {
{"messagepreview", {"messagepreview",
"chrome://browser/content/messagepreview/messagepreview.html", "chrome://browser/content/messagepreview/messagepreview.html",
nsIAboutModule::URI_MUST_LOAD_IN_CHILD | nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS |
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::HIDE_FROM_ABOUTABOUT}, nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::HIDE_FROM_ABOUTABOUT},
{"pocket-saved", "chrome://pocket/content/panels/saved.html", {"pocket-saved", "chrome://pocket/content/panels/saved.html",

View file

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

View file

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

View file

@ -14,8 +14,8 @@ add_task(async function test_recover_storeID() {
await SelectableProfileService.init(); await SelectableProfileService.init();
Assert.ok( Assert.ok(
!ProfilesDatastoreService.initialized, ProfilesDatastoreService.initialized,
"Didn't initialize the datastore service" "Initialized the datastore service"
); );
Assert.ok( Assert.ok(
!SelectableProfileService.initialized, !SelectableProfileService.initialized,

View file

@ -15,6 +15,7 @@
#include "mozilla/Result.h" #include "mozilla/Result.h"
#include "mozilla/ResultVariant.h" #include "mozilla/ResultVariant.h"
#include "mozilla/UniquePtr.h" #include "mozilla/UniquePtr.h"
#include "mozilla/WindowsVersion.h"
#include "mozilla/WinHeaderOnlyUtils.h" #include "mozilla/WinHeaderOnlyUtils.h"
#include "mozilla/widget/WinTaskbar.h" #include "mozilla/widget/WinTaskbar.h"
#include "WinUtils.h" #include "WinUtils.h"
@ -186,7 +187,16 @@ Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11(
Win11PinToTaskBarResult unlockStatus = Win11PinToTaskBarResult unlockStatus =
UnlockLimitedAccessFeature(Win11LimitedAccessFeatureType::Taskbar); UnlockLimitedAccessFeature(Win11LimitedAccessFeatureType::Taskbar);
if (unlockStatus.result != Win11PinToTaskBarResultStatus::Success) { if (unlockStatus.result != Win11PinToTaskBarResultStatus::Success) {
return unlockStatus; // Limited Access Feature no longer necessary for Windows 11 26200 Build
// 7840, and possibly other channels.
if (!IsWin11OrLater()) {
return unlockStatus;
}
TASKBAR_PINNING_LOG(
LogLevel::Warning,
"Limited Access Feature failed to unlock, attempting to use Taskbar "
"Pinning API assuming LAF is no longer necessary.");
} }
HRESULT hr; HRESULT hr;
@ -407,7 +417,16 @@ Win11PinToTaskBarResult IsCurrentAppPinnedToTaskbarWin11(bool aCheckOnly) {
Win11PinToTaskBarResult unlockStatus = Win11PinToTaskBarResult unlockStatus =
UnlockLimitedAccessFeature(Win11LimitedAccessFeatureType::Taskbar); UnlockLimitedAccessFeature(Win11LimitedAccessFeatureType::Taskbar);
if (unlockStatus.result != Win11PinToTaskBarResultStatus::Success) { if (unlockStatus.result != Win11PinToTaskBarResultStatus::Success) {
return unlockStatus; // Limited Access Feature no longer necessary for Windows 11 26200 Build
// 7840, and possibly other channels.
if (!IsWin11OrLater()) {
return unlockStatus;
}
TASKBAR_PINNING_LOG(
LogLevel::Warning,
"Limited Access Feature failed to unlock, attempting to use Taskbar "
"Pinning API assuming LAF is no longer necessary.");
} }
HRESULT hr; HRESULT hr;

View file

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

View file

@ -1 +1 @@
140.7.1 140.10.1

View file

@ -1 +1 @@
140.7.1esr 140.10.1esr

View file

@ -13,5 +13,5 @@ MOZ_BRANDING_DIRECTORY=browser/branding/unofficial
MOZ_OFFICIAL_BRANDING_DIRECTORY=browser/branding/official MOZ_OFFICIAL_BRANDING_DIRECTORY=browser/branding/official
# IceCat settings # IceCat settings
MOZ_APP_BASENAME=IceCat MOZ_APP_BASENAME=IceCat
MOZ_APP_VERSION=140.7.1 MOZ_APP_VERSION=140.10.1
MOZ_DATA_REPORTING=0 MOZ_DATA_REPORTING=0

View file

@ -1473,6 +1473,9 @@ async function triggerCapture(browser, submitButtonSelector, fillSelectors) {
* @param {object} patterns.captureExpectedRecord * @param {object} patterns.captureExpectedRecord
* The expected saved record after capturing the form. Keyed by field name. This * The expected saved record after capturing the form. Keyed by field name. This
* parameter is only used when `options.testCapture` is set. * parameter is only used when `options.testCapture` is set.
* @param {boolean} patterns.useTestYear
* Set to the current year to assign while running the test, useful for credit
* card expiry tests with a manual set of year options in the dropdown.
* @param {object} patterns.only * @param {object} patterns.only
* This parameter is used solely for debugging purposes. When set to true, * This parameter is used solely for debugging purposes. When set to true,
* it restricts the execution to only the specified testcase. * it restricts the execution to only the specified testcase.
@ -1597,16 +1600,32 @@ async function add_heuristic_tests(
const sleepAfterFocus = contexts.length > 1; const sleepAfterFocus = contexts.length > 1;
for (const context of contexts) { for (const context of contexts) {
await SpecialPowers.spawn(context, [], async () => { await SpecialPowers.spawn(
const elements = Array.from( context,
content.document.querySelectorAll("input, select") [testPattern.useTestYear],
); async year => {
// Focus on each field in the test document to trigger autofill field detection let FormAutofillHeuristics;
// on all the fields. if (year) {
elements.forEach(element => { FormAutofillHeuristics = ChromeUtils.importESModule(
element.focus(); "resource://gre/modules/shared/FormAutofillHeuristics.sys.mjs"
}); ).FormAutofillHeuristics;
}); FormAutofillHeuristics.useTestYear = year;
}
const elements = Array.from(
content.document.querySelectorAll("input, select")
);
// Focus on each field in the test document to trigger autofill field detection
// on all the fields.
elements.forEach(element => {
element.focus();
});
if (year) {
FormAutofillHeuristics.useTestYear = null;
}
}
);
try { try {
await BrowserTestUtils.synthesizeKey("VK_ESCAPE", {}, context); await BrowserTestUtils.synthesizeKey("VK_ESCAPE", {}, context);

View file

@ -8,7 +8,6 @@ support-files = [
["browser_BestBuy.js"] ["browser_BestBuy.js"]
["browser_CDW.js"] ["browser_CDW.js"]
skip-if = ["true"] # Bug 1939626
["browser_CostCo.js"] ["browser_CostCo.js"]

View file

@ -30,6 +30,7 @@ add_heuristic_tests(
}, },
{ {
fixturePath: "Checkout_BillingPaymentInfo.html", fixturePath: "Checkout_BillingPaymentInfo.html",
useTestYear: 2024,
expectedResult: [ expectedResult: [
{ {
default: { default: {

View file

@ -74,6 +74,7 @@ add_heuristic_tests(
}, },
{ {
fixturePath: "Payment.html", fixturePath: "Payment.html",
useTestYear: 2025,
expectedResult: [ expectedResult: [
{ {
default: { default: {

View file

@ -6,6 +6,7 @@ add_heuristic_tests(
[ [
{ {
fixturePath: "Payment.html", fixturePath: "Payment.html",
useTestYear: 2024,
expectedResult: [ expectedResult: [
{ {
default: { default: {

View file

@ -6,6 +6,7 @@ add_heuristic_tests(
[ [
{ {
fixturePath: "Checkout_Payment.html", fixturePath: "Checkout_Payment.html",
useTestYear: 2024,
expectedResult: [ expectedResult: [
{ {
default: { default: {

View file

@ -6,6 +6,7 @@ add_heuristic_tests(
[ [
{ {
fixturePath: "index.html", fixturePath: "index.html",
useTestYear: 2024,
expectedResult: [ expectedResult: [
{ {
default: { default: {

View file

@ -120,3 +120,65 @@ window.wrappedJSObject.chrome = cloneInto(
window, window,
{ cloneFunctions: true } { cloneFunctions: true }
); );
const ua = navigator.userAgent;
const mobile = ua.includes("Mobile") || ua.includes("Tablet");
// Very roughly matches Chromium's GetPlatformForUAMetadata()
let platform = "Linux";
if (mobile) {
platform = "Android";
} else if (navigator.platform.startsWith("Win")) {
platform = "Windows";
} else if (navigator.platform.startsWith("Mac")) {
platform = "macOS";
}
const version = (ua.match(/IceCat\/([0-9]+)/) || ["", "58.0"])[1];
// These match Chrome's output as of version 126.
const brands = [
{
brand: "Not/A)Brand",
version: "8",
},
{
brand: "Chromium",
version,
},
{
brand: "Google Chrome",
version,
},
];
const userAgentData = cloneInto(
{
brands,
mobile,
platform,
getHighEntropyValues() {
return window.wrappedJSObject.Promise.resolve(
cloneInto(
{
brands,
mobile,
platform,
platformVersion: "19.0.0",
},
window
)
);
},
},
window,
{ cloneFunctions: true }
);
Object.defineProperty(window.navigator.wrappedJSObject, "userAgentData", {
get: exportFunction(function () {
return userAgentData;
}, window),
set: exportFunction(function () {}, window),
});

View file

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

Binary file not shown.

Binary file not shown.

View file

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

View file

@ -157,8 +157,12 @@ ifeq (official, $(MOZ_BRANDING))
MOZ_DEFINES += -DMOZ_OFFICIAL_BRANDING MOZ_DEFINES += -DMOZ_OFFICIAL_BRANDING
endif endif
ifneq (,$(DEB_PARALLEL_JOBS)) ifneq (,$(DEB_PARALLEL_JOBS))
ifneq (,$(filter armhf, $(DEB_HOST_ARCH)))
MOZ_DEFINES += -DDEB_PARALLEL_JOBS=1
else
MOZ_DEFINES += -DDEB_PARALLEL_JOBS=$(DEB_PARALLEL_JOBS) MOZ_DEFINES += -DDEB_PARALLEL_JOBS=$(DEB_PARALLEL_JOBS)
endif endif
endif
MOZ_EXECUTABLES_$(MOZ_PKG_NAME) += $(MOZ_LIBDIR)/$(MOZ_PKG_BASENAME).sh \ MOZ_EXECUTABLES_$(MOZ_PKG_NAME) += $(MOZ_LIBDIR)/$(MOZ_PKG_BASENAME).sh \
$(NULL) $(NULL)

View file

@ -1,3 +1,27 @@
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)
-- Capitulo Mexicano de Software Libre <devel@cmxsl.org> Tue, 10 Mar 2026 23:20:02 -0600
icecat (140.7.1-1gnu1+build1-0.12.0) ecne; urgency=medium icecat (140.7.1-1gnu1+build1-0.12.0) ecne; urgency=medium
* New upstream stable release (icecat-140.7.1-1gnu1) * New upstream stable release (icecat-140.7.1-1gnu1)

View file

@ -11,7 +11,11 @@ ac_add_options --disable-updater
ac_add_options --enable-application=browser ac_add_options --enable-application=browser
ac_add_options --with-distribution-id=org.trisquel ac_add_options --with-distribution-id=org.trisquel
%%if DEB_BUILD_ARCH_BITS == 32 %%if DEB_BUILD_ARCH_BITS == 32
%%if DEB_HOST_ARCH == armhf
ac_add_options --disable-debug-symbols
%%else
ac_add_options --enable-debug-symbols=-g1 ac_add_options --enable-debug-symbols=-g1
%%endif
%%else %%else
ac_add_options --enable-debug-symbols ac_add_options --enable-debug-symbols
%%endif %%endif

View file

@ -1,22 +1,30 @@
Description: Do not enable LTO for rustc when building on arm64 and armhf, Description: Do not enable LTO for rustc when building on armhf,
to work around OOM failures on Launchpad builders. Note that this alone is not to work around OOM failures on Launchpad builders. Note that this alone is not
sufficient, because by default cargo will also enable full LTO when building sufficient, because by default cargo will also enable full LTO when building
with a release profile, so the top-level Cargo.toml file needs to be with a release profile, so the top-level Cargo.toml file needs to be
conditionally patched (this is done in debian/build/rules.mk). conditionally patched (this is done in debian/build/rules.mk).
Author: Olivier Tilloy <olivier.tilloy@canonical.com> Author: Olivier Tilloy <olivier.tilloy@canonical.com>
Author: Nathan Pratte Teodosio <nteodosio@ubuntu.com>
Forwarded: not-needed Forwarded: not-needed
--- a/config/makefiles/rust.mk --- a/config/makefiles/rust.mk
+++ b/config/makefiles/rust.mk +++ b/config/makefiles/rust.mk
@@ -70,8 +70,10 @@ ifndef MOZ_DEBUG_RUST @@ -70,10 +70,18 @@ ifndef MOZ_DEBUG_RUST
# Never enable when coverage is enabled to work around https://github.com/rust-lang/rust/issues/90045. # Never enable when coverage is enabled to work around https://github.com/rust-lang/rust/issues/90045.
ifndef MOZ_CODE_COVERAGE ifndef MOZ_CODE_COVERAGE
ifeq (,$(findstring gkrust_gtest,$(RUST_LIBRARY_FILE))) ifeq (,$(findstring gkrust_gtest,$(RUST_LIBRARY_FILE)))
+ifeq (,$(filter aarch64 arm,$(TARGET_CPU))) +ifneq (,$(filter arm,$(TARGET_CPU)))
+cargo_rustc_flags += -Clto=off
+else
cargo_rustc_flags += -Clto$(if $(filter full,$(MOZ_LTO_RUST_CROSS)),=fat) cargo_rustc_flags += -Clto$(if $(filter full,$(MOZ_LTO_RUST_CROSS)),=fat)
endif
+endif +endif
# We need -Cembed-bitcode=yes for all crates when using -Clto.
RUSTFLAGS += -Cembed-bitcode=yes
endif endif
# We need -Cembed-bitcode=yes for all crates when using -Clto.
+ifneq (,$(filter arm,$(TARGET_CPU)))
+RUSTFLAGS += -Cembed-bitcode=no
+else
RUSTFLAGS += -Cembed-bitcode=yes
+endif
endif
endif
endif

View file

@ -7,7 +7,7 @@ webrtc-fix-compiler-flags-for-armhf.patch
s390x-ycbcr.patch s390x-ycbcr.patch
reduce-rust-debuginfo.patch reduce-rust-debuginfo.patch
armhf-reduce-linker-memory-use.patch armhf-reduce-linker-memory-use.patch
armhf-rustc-thin-lto.patch armhf-rustc-lto-off.patch
ppc64el-workaround-bug-1555531.patch ppc64el-workaround-bug-1555531.patch
ppc64el-workaround-gcc-ice.patch ppc64el-workaround-gcc-ice.patch
armhf-clang-no-integrated-as-for-neon.patch armhf-clang-no-integrated-as-for-neon.patch

View file

@ -190,6 +190,7 @@ fail-if = ["a11y_checks"] # Bug 1849028 clicked element may not be focusable and
["browser_aboutdebugging_serviceworker_start.js"] ["browser_aboutdebugging_serviceworker_start.js"]
skip-if = [ 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 "os == 'linux' && os_version == '24.04' && processor == 'x86_64' && display == 'x11' && tsan", # Bug 1947358
] ]

View file

@ -96,8 +96,11 @@ fail-if = ["a11y_checks"] # Bug 1849028 clicked element may not be focusable and
["browser_application_panel_start-service-worker.js"] ["browser_application_panel_start-service-worker.js"]
fail-if = ["a11y_checks"] # Bug 1849028 clicked element may not be focusable and/or labeled fail-if = ["a11y_checks"] # Bug 1849028 clicked element may not be focusable and/or labeled
skip-if = [ skip-if = [
"os == 'linux' && os_version == '18.04' && processor == 'x86_64' && tsan", # Bug 1608640 "os == 'linux' && processor == 'x86_64' && tsan", # Bug 1608640, Bug 2030884
"os == 'linux' && os_version == '24.04' && processor == 'x86_64' && display == 'x11' && tsan", # Bug 1608640 "os == 'linux' && processor == 'x86_64' && asan", # Bug 1781479, Bug 2030884
"os == 'mac' && os_version == '14.70' && processor == 'x86_64'", # Bug 1980084, Bug 2030884
"os == 'win' && os_version == '11.26100' && processor == 'x86_64' && asan", # Bug 1781479, Bug 2030884
"os == 'win' && os_version == '11.26200' && processor == 'x86_64' && asan", # Bug 1781479, Bug 2030884
] ]
["browser_application_panel_target-switching.js"] ["browser_application_panel_target-switching.js"]

View file

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

View file

@ -2,11 +2,12 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/>. */ * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
import React, { Component } from "devtools/client/shared/vendor/react"; import React, {
import { div } from "devtools/client/shared/vendor/react-dom-factories"; Component,
createRef,
} from "devtools/client/shared/vendor/react";
import PropTypes from "devtools/client/shared/vendor/react-prop-types"; import PropTypes from "devtools/client/shared/vendor/react-prop-types";
import { connect } from "devtools/client/shared/vendor/react-redux"; import { connect } from "devtools/client/shared/vendor/react-redux";
import { basename } from "../utils/path";
import { createLocation } from "../utils/location"; import { createLocation } from "../utils/location";
const fuzzyAldrin = require("resource://devtools/client/shared/vendor/fuzzaldrin-plus.js"); const fuzzyAldrin = require("resource://devtools/client/shared/vendor/fuzzaldrin-plus.js");
@ -59,6 +60,7 @@ export class QuickOpenModal extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { results: null, selectedIndex: 0 }; this.state = { results: null, selectedIndex: 0 };
this.resultListRef = createRef();
} }
static get propTypes() { static get propTypes() {
@ -223,20 +225,14 @@ export class QuickOpenModal extends Component {
if (query == "" && !this.isShortcutQuery()) { if (query == "" && !this.isShortcutQuery()) {
this.showTopSources(); this.showTopSources();
return; } else if (this.isSymbolSearch()) {
}
if (this.isSymbolSearch()) {
await this.searchSymbols(query); await this.searchSymbols(query);
return; } else if (this.isShortcutQuery()) {
}
if (this.isShortcutQuery()) {
this.searchShortcuts(query); this.searchShortcuts(query);
return; } else {
this.searchSources(query);
} }
this.highlightQueryMatches(this.props.query);
this.searchSources(query);
} catch (e) { } catch (e) {
// Due to throttling this might get scheduled after the component and the // Due to throttling this might get scheduled after the component and the
// toolbox are destroyed. // toolbox are destroyed.
@ -394,23 +390,35 @@ export class QuickOpenModal extends Component {
isSourcesQuery = () => this.props.searchType === "sources"; isSourcesQuery = () => this.props.searchType === "sources";
isSourceSearch = () => this.isSourcesQuery() || this.isGotoSourceQuery(); isSourceSearch = () => this.isSourcesQuery() || this.isGotoSourceQuery();
/* eslint-disable react/no-danger */ highlightQueryMatches(query) {
renderHighlight(candidateString, query) {
const options = { const options = {
wrap: { wrap: {
tagOpen: '<mark class="highlight">', tagOpen: '<mark class="highlight">',
tagClose: "</mark>", tagClose: "</mark>",
}, },
}; };
const html = fuzzyAldrin.wrap(candidateString, query, options); if (this.resultListRef.current) {
return div({ const domEl = this.resultListRef.current.ref.current;
dangerouslySetInnerHTML: { for (const titleNode of domEl.querySelectorAll(".title")) {
__html: html, const htmlString = fuzzyAldrin.wrap(
}, titleNode.innerText,
}); query,
options
);
// Sanitizer API not supported in ESR 140
// Should remove at ESR 153
if ("Sanitizer" in window) {
const sanitizer = new Sanitizer({
elements: ["mark"],
attributes: ["class"],
});
titleNode.setHTML(htmlString, { sanitizer });
}
}
}
} }
highlightMatching = (query, results) => { renderResults = (query, results) => {
let newQuery = query; let newQuery = query;
if (newQuery === "") { if (newQuery === "") {
return results; return results;
@ -421,11 +429,7 @@ export class QuickOpenModal extends Component {
if (typeof result.title == "string") { if (typeof result.title == "string") {
return { return {
...result, ...result,
title: this.renderHighlight( title: result.title,
result.title,
basename(newQuery),
"title"
),
}; };
} }
return result; return result;
@ -454,7 +458,7 @@ export class QuickOpenModal extends Component {
const { query } = this.props; const { query } = this.props;
const { selectedIndex, results } = this.state; const { selectedIndex, results } = this.state;
const items = this.highlightMatching(query, results || []); const items = this.renderResults(query, results || []);
const expanded = !!items && !!items.length; const expanded = !!items && !!items.length;
return React.createElement( return React.createElement(
Modal, Modal,
@ -487,7 +491,7 @@ export class QuickOpenModal extends Component {
items, items,
selected: selectedIndex, selected: selectedIndex,
selectItem: this.selectResultItem, selectItem: this.selectResultItem,
ref: "resultList", ref: this.resultListRef,
expanded, expanded,
...(this.isSourceSearch() ? SIZE_BIG : SIZE_DEFAULT), ...(this.isSourceSearch() ? SIZE_BIG : SIZE_DEFAULT),
}) })

View file

@ -115,6 +115,9 @@ skip-if = [
["browser_dbg-call-stack.js"] ["browser_dbg-call-stack.js"]
["browser_dbg-chrome-create.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"] ["browser_dbg-console-async.js"]
@ -286,6 +289,7 @@ skip-if = [
["browser_dbg-javascript-tracer-values-preview.js"] ["browser_dbg-javascript-tracer-values-preview.js"]
skip-if = [ 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' && 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 "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,6 +94,18 @@ add_task(async function () {
pressKey(dbg, "Escape"); pressKey(dbg, "Escape");
assertQuickOpenDisabled(dbg); 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"); info("Testing goto line:column");
assertLine(dbg, 0); assertLine(dbg, 0);
assertColumn(dbg, 1); assertColumn(dbg, 1);
@ -170,3 +182,19 @@ async function assertResultIsTab(dbg, index) {
"Result should be a tab" "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,6 +112,12 @@ skip-if = [
["browser_tab_commands_factory.js"] ["browser_tab_commands_factory.js"]
["browser_tab_descriptor_fission.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"] ["browser_target_cached-front.js"]
@ -291,6 +297,9 @@ fail-if = ["a11y_checks"] # Bug 1849028 clicked element may not be focusable and
["browser_toolbox_watchedByDevTools.js"] ["browser_toolbox_watchedByDevTools.js"]
["browser_toolbox_window_global_debugging.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"] ["browser_toolbox_window_reload_target.js"]

View file

@ -150,8 +150,11 @@ fail-if = ["a11y_checks"] # Bug 1849028 clicked element may not be focusable and
["browser_animation_logic_mutations_fast.js"] ["browser_animation_logic_mutations_fast.js"]
skip-if = [ skip-if = [
"os == 'linux' && os_version == '18.04' && processor == 'x86_64' && debug", # Bug 1567800 "os == 'linux' && processor == 'x86_64' && asan", # Bug 1980142, Bug 2030884
"os == 'linux' && os_version == '24.04' && processor == 'x86_64' && display == 'x11' && debug", # Bug 1567800 "os == 'linux' && processor == 'x86_64' && debug", # Bug 1567800, Bug 2030884
"os == 'linux' && processor == 'x86_64' && tsan", # Bug 1980142, Bug 2030884
"os == 'win' && os_version == '11.26100' && processor == 'x86_64' && debug", # Bug 1980142, Bug 2030884
"os == 'win' && os_version == '11.26200' && processor == 'x86_64' && debug", # Bug 1980142, Bug 2030884
] ]
["browser_animation_logic_mutations_properties.js"] ["browser_animation_logic_mutations_properties.js"]

View file

@ -124,30 +124,34 @@ class RequestPanel extends Component {
} }
/** /**
* Mapping array to dict for TreeView usage. * This maps an array to a dictionary for TreeView usage,
* Since TreeView only support Object(dict) format. * sincs the treeView only supports the Object(dict) format.
* This function also deal with duplicate key case
* (for multiple selection and query params with same keys)
* *
* This function is not sorting result properties since it can * This function also deals with the duplicate key scenario
* results in unexpected order of params. See bug 1469533 * (i.e multiple selections and query params with same keys)
* *
* @param {Object[]} arr - key-value pair array or form params * Note: This is not sorting the result properties since it can
* @returns {Object} Rep compatible object * result in an unexpected order of parameters. See bug 1469533
*
* @param {object[]} arrOfKeyValuePairs - An array of key-value pairs or form params.
* @param {string} arrOfKeyValuePairs[].name
* @param {string|Array} arrOfKeyValuePairs[].value
*
* @returns {object} Rep compatible object
*/ */
getProperties(arr) { getProperties(arrOfKeyValuePairs) {
return arr.reduce((map, obj) => { return arrOfKeyValuePairs.reduce((dict, { name, value }) => {
const value = map[obj.name]; if (name in dict) {
if (value || value === "") { const dictValue = dict[name];
if (typeof value !== "object") { if (!Array.isArray(dictValue)) {
map[obj.name] = [value]; dict[name] = [dictValue];
} }
map[obj.name].push(obj.value); dict[name].push(value);
} else { } else {
map[obj.name] = obj.value; dict[name] = value;
} }
return map; return dict;
}, {}); }, Object.create(null));
} }
toggleRawRequestPayload() { toggleRawRequestPayload() {
@ -205,10 +209,9 @@ class RequestPanel extends Component {
// Form Data section // Form Data section
if (formDataSections && formDataSections.length) { if (formDataSections && formDataSections.length) {
const sections = formDataSections.filter(str => /\S/.test(str)).join("&");
component = PropertiesView; component = PropertiesView;
componentProps = { componentProps = {
object: this.getProperties(parseFormData(sections)), object: this.getProperties(parseFormData(formDataSections)),
filterText, filterText,
targetSearchResult, targetSearchResult,
defaultSelectFirstNode: false, defaultSelectFirstNode: false,

View file

@ -83,7 +83,6 @@ async function getFormDataSections(
} }
} }
} }
return formDataSections; return formDataSections;
} }
@ -418,28 +417,29 @@ function parseQueryString(query) {
/** /**
* Parse a string of formdata sections into its components * Parse a string of formdata sections into its components
* *
* @param {string} sections - sections of formdata joined by & * @param {Array<string>} sections Array of sections of formdata
* @return {array} array of formdata params { name, value } * e.g ["", "a=x&b=y", "c=z"]
* @return {Array<object>} Array of formdata params
* e.g [{ name: 'a', value: 'x' }, { name: 'b', value: 'y'}, { name: 'c', value: 'z'}]
*/ */
function parseFormData(sections) { function parseFormData(sections) {
if (!sections) { if (!sections || !sections.length) {
return []; return [];
} }
const formDataParams = [];
const searchStr = sections
// Filter out empty sections
.filter(str => /\S/.test(str))
.join("&");
return sections const params = new URLSearchParams(searchStr);
.replace(/^&/, "") for (const [key, value] of params) {
.split("&") formDataParams.push({
.map(e => { name: getUnicodeUrlPath(key),
const firstEqualSignIndex = e.indexOf("="); value: getUnicodeUrlPath(value),
const paramName =
firstEqualSignIndex !== -1 ? e.slice(0, firstEqualSignIndex) : e;
const paramValue =
firstEqualSignIndex !== -1 ? e.slice(firstEqualSignIndex + 1) : "";
return {
name: paramName ? getUnicodeUrlPath(paramName) : "",
value: paramValue ? getUnicodeUrlPath(paramValue) : "",
};
}); });
}
return formDataParams;
} }
/** /**

View file

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

View file

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

View file

@ -20,7 +20,7 @@ add_task(async function () {
store.dispatch(Actions.batchEnable(false)); store.dispatch(Actions.batchEnable(false));
// Execute requests. // Execute requests.
await performRequests(monitor, tab, 12); await performRequests(monitor, tab, 13);
const requestListItems = document.querySelectorAll( const requestListItems = document.querySelectorAll(
".network-monitor .request-list-item" ".network-monitor .request-list-item"
@ -49,7 +49,7 @@ add_task(async function () {
await testRequestWithFormattedView( await testRequestWithFormattedView(
monitor, monitor,
requestListItems[2], requestListItems[2],
"?foo", "foo",
"bar=123=xyz", "bar=123=xyz",
"?foo=bar=123=xyz", "?foo=bar=123=xyz",
1 1
@ -92,6 +92,14 @@ add_task(async function () {
'{ "foo": "bar" }', '{ "foo": "bar" }',
1 1
); );
await testRequestWithFormattedView(
monitor,
requestListItems[12],
"__proto__",
"evil_value",
"__proto__=evil_value",
1
);
await teardown(monitor); await teardown(monitor);
}); });

View file

@ -7,7 +7,7 @@
* Tests if Copy as Fetch works. * Tests if Copy as Fetch works.
*/ */
add_task(async function () { add_task(async function testBasicCopyAsFetch() {
const { tab, monitor } = await initNetMonitor(HTTPS_CURL_URL, { const { tab, monitor } = await initNetMonitor(HTTPS_CURL_URL, {
requestCount: 1, requestCount: 1,
}); });
@ -15,7 +15,9 @@ add_task(async function () {
// GET request, no cookies (first request) // GET request, no cookies (first request)
await performRequest("GET"); await performRequest("GET");
await testClipboardContent(`await fetch("https://example.com/browser/devtools/client/netmonitor/test/sjs_simple-test-server.sjs", { await testClipboardContent(
monitor,
`await fetch("https://example.com/browser/devtools/client/netmonitor/test/sjs_simple-test-server.sjs", {
"credentials": "omit", "credentials": "omit",
"headers": { "headers": {
"User-Agent": "${navigator.userAgent}", "User-Agent": "${navigator.userAgent}",
@ -33,7 +35,8 @@ add_task(async function () {
"referrer": "https://example.com/browser/devtools/client/netmonitor/test/html_copy-as-curl.html", "referrer": "https://example.com/browser/devtools/client/netmonitor/test/html_copy-as-curl.html",
"method": "GET", "method": "GET",
"mode": "cors" "mode": "cors"
});`); });`
);
await teardown(monitor); await teardown(monitor);
@ -54,39 +57,71 @@ add_task(async function () {
); );
await waitRequest; await waitRequest;
} }
async function testClipboardContent(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;
}
return expectedResult === result;
}
);
info("Clipboard contains a fetch command for item " + (items.length - 1));
}
}); });
/**
* 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... ");
const waitRequest = waitForNetworkEvents(monitor, 1);
await SpecialPowers.spawn(
gBrowser.selectedBrowser,
['data:text/html,"+alert(document.domain)+"'],
url => {
content.fetch(url);
}
);
await waitRequest;
await testClipboardContent(
monitor,
`await fetch("data:text/html,\\"+alert(document.domain)+\\"", {
"credentials": "omit",
"headers": {},
"method": "GET",
"mode": "cors"
});`
);
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;
}
return expectedResult === result;
}
);
info("Clipboard contains a fetch command for item " + (items.length - 1));
}

View file

@ -326,10 +326,10 @@ function testEscapeStringWin() {
"Percent signs should be escaped." "Percent signs should be escaped."
); );
const backslashes = "\\A simple string\\"; const backslashes = " - \\A simple string\\ - ";
is( is(
CurlUtils.escapeStringWin(backslashes), CurlUtils.escapeStringWin(backslashes),
'^\"^\\A simple string^\\^\"', '^\" - ^\\^\\A simple string^\\^\\ - ^\"',
"Backslashes should be escaped." "Backslashes should be escaped."
); );

View file

@ -71,6 +71,7 @@
await get("baz", "?species=in=(52,60)"); await get("baz", "?species=in=(52,60)");
await get("baz", "?a=&a=b"); await get("baz", "?a=&a=b");
await get("baz", "?a=b&a=c&d=1"); await get("baz", "?a=b&a=c&d=1");
await post("baz", "", urlencoded, "__proto__=evil_value");
} }
</script> </script>
</body> </body>

View file

@ -10,15 +10,13 @@ const DEFAULT_DPPX = window.devicePixelRatio;
/* eslint-disable max-len */ /* eslint-disable max-len */
const TEST_DEVICE = { const TEST_DEVICE = {
name: "iPhone 6/7/8", name: "iPhone 17 / 17 Pro",
width: 375, width: 402,
height: 667, height: 874,
pixelRatio: 2, pixelRatio: 3,
userAgent: userAgent:
"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", "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",
touch: true, touch: true,
icecatOS: false,
os: "iOS",
featured: true, featured: true,
}; };
/* eslint-enable max-len */ /* eslint-enable max-len */

View file

@ -458,6 +458,9 @@ const CurlUtils = {
return ( return (
encapsChars + encapsChars +
str str
// Replace all the \ (used as the escape character in the next replace) with \\
.replace(/\\/g, "\\\\")
// Replace all " with \" to ensure the first parser does not remove it. // Replace all " with \" to ensure the first parser does not remove it.
.replace(/"/g, '\\"') .replace(/"/g, '\\"')

View file

@ -587,7 +587,9 @@ support-files = ["browser_webconsole_object_inspector_entries.snapshot.mjs"]
https_first_disabled = true # JS HttpServer doesn't support https https_first_disabled = true # JS HttpServer doesn't support https
skip-if = [ skip-if = [
"http3", # JS HttpServer doesn't support http3 "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 == '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"] ["browser_webconsole_object_inspector_getters.js"]

View file

@ -179,17 +179,17 @@ function getCleanedPacket(key, packet) {
res.startedDateTime = existingPacket.startedDateTime; res.startedDateTime = existingPacket.startedDateTime;
} }
if (res.totalTime && existingPacket.totalTime) {
res.totalTime = existingPacket.totalTime;
}
if (res.securityState && existingPacket.securityState) { if (res.securityState && existingPacket.securityState) {
res.securityState = existingPacket.securityState; res.securityState = existingPacket.securityState;
} }
// waitingTime can be very small and rounded to 0. However this is still a // totalTime and waitingTime can be very small and rounded to 0. However this
// valid waiting time, so check isNaN instead of a simple truthy check. // is still a valid time value, so check isNaN instead of a simple truthy check.
if (!isNaN(res.waitingTime) && existingPacket.waitingTime) { if (!isNaN(res.totalTime) && !isNaN(existingPacket.totalTime)) {
res.totalTime = existingPacket.totalTime;
}
if (!isNaN(res.waitingTime) && !isNaN(existingPacket.waitingTime)) {
res.waitingTime = existingPacket.waitingTime; res.waitingTime = existingPacket.waitingTime;
} }

View file

@ -1937,6 +1937,19 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(BrowsingContext)
return IsCertainlyAliveForCC(tmp); return IsCertainlyAliveForCC(tmp);
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END 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 class RemoteLocationProxy
: public RemoteObjectProxy<BrowsingContext::LocationProxy, : public RemoteObjectProxy<BrowsingContext::LocationProxy,
Location_Binding::sCrossOriginProperties> { Location_Binding::sCrossOriginProperties> {
@ -2786,6 +2799,11 @@ 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) { void BrowsingContext::DidSet(FieldIndex<IDX_InRDMPane>, bool aOldValue) {
MOZ_ASSERT(IsTop(), MOZ_ASSERT(IsTop(),
"Should only set InRDMPane in the top-level browsing context"); "Should only set InRDMPane in the top-level browsing context");
@ -4049,6 +4067,10 @@ bool IPDLParamTraits<dom::MaybeDiscarded<dom::BrowsingContext>>::Read(
if (id == 0) { if (id == 0) {
*aResult = nullptr; *aResult = nullptr;
} else if (RefPtr<dom::BrowsingContext> bc = dom::BrowsingContext::Get(id)) { } else if (RefPtr<dom::BrowsingContext> bc = dom::BrowsingContext::Get(id)) {
if (!bc->Group()->IsKnownForMessageReader(aReader)) {
return false;
}
*aResult = std::move(bc); *aResult = std::move(bc);
} else { } else {
aResult->SetDiscarded(id); aResult->SetDiscarded(id);

View file

@ -734,6 +734,9 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
mWindowProxy = aWindowProxy; mWindowProxy = aWindowProxy;
} }
// Since mWindowProxy is a weak pointer it has to be updated during sweeping.
static void SweepWindowProxies(JSTracer* aTrc);
Nullable<WindowProxyHolder> GetWindow(); Nullable<WindowProxyHolder> GetWindow();
NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@ -1136,6 +1139,7 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
return IsTop(); return IsTop();
} }
bool CanSet(FieldIndex<IDX_InRDMPane>, const bool&, ContentParent* aSource);
void DidSet(FieldIndex<IDX_InRDMPane>, bool aOldValue); void DidSet(FieldIndex<IDX_InRDMPane>, bool aOldValue);
MOZ_CAN_RUN_SCRIPT_BOUNDARY void DidSet(FieldIndex<IDX_ForceDesktopViewport>, MOZ_CAN_RUN_SCRIPT_BOUNDARY void DidSet(FieldIndex<IDX_ForceDesktopViewport>,
bool aOldValue); bool aOldValue);
@ -1377,10 +1381,8 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
RefPtr<nsGeolocationService> mGeolocationServiceOverride; RefPtr<nsGeolocationService> mGeolocationServiceOverride;
// This is not a strong reference, but using a JS::Heap for that should be // This is a weak reference. It will be updated automatically during sweeping
// fine. The JSObject stored in here should be a proxy with a // by SweepWindowProxies.
// nsOuterWindowProxy handler, which will update the pointer from its
// objectMoved hook and clear it from its finalize hook.
JS::Heap<JSObject*> mWindowProxy; JS::Heap<JSObject*> mWindowProxy;
LocationProxy mLocation; LocationProxy mLocation;

View file

@ -251,6 +251,42 @@ ContentParent* BrowsingContextGroup::GetHostProcess(
return mHosts.GetWeak(aRemoteType); return mHosts.GetWeak(aRemoteType);
} }
bool BrowsingContextGroup::IsKnownForMessageReader(
IPC::MessageReader* aReader) {
if (!aReader->GetActor()) {
aReader->FatalError(
"No actor for BrowsingContextGroup::IsKnownForMessageReader");
return false;
}
mozilla::ipc::IToplevelProtocol* topActor =
aReader->GetActor()->ToplevelProtocol();
switch (topActor->GetProtocolId()) {
case PInProcessMsgStart:
// PInProcess always exists only within a single process, so we don't need
// to do any validation on it.
return true;
case PContentMsgStart:
// The process should only be able to name this BCG if it is
// subscribed, or if the BCG has been destroyed (and has therefore
// stopped tracking subscribers).
if (topActor->GetSide() == mozilla::ipc::ParentSide && !mDestroyed &&
!mSubscribers.Contains(static_cast<ContentParent*>(topActor))) {
aReader->FatalError(
"Process is not subscribed to this BrowsingContextGroup");
return false;
}
return true;
default:
aReader->FatalError(
"Unsupported toplevel actor for "
"BrowsingContextGroup::IsKnownForMessageReader");
return false;
}
}
void BrowsingContextGroup::UpdateToplevelsSuspendedIfNeeded() { void BrowsingContextGroup::UpdateToplevelsSuspendedIfNeeded() {
if (!StaticPrefs::dom_suspend_inactive_enabled()) { if (!StaticPrefs::dom_suspend_inactive_enabled()) {
return; return;
@ -296,8 +332,8 @@ void BrowsingContextGroup::Destroy() {
!sBrowsingContextGroups->Contains(Id()) || !sBrowsingContextGroups->Contains(Id()) ||
*sBrowsingContextGroups->Lookup(Id()) != this); *sBrowsingContextGroups->Lookup(Id()) != this);
} }
mDestroyed = true;
#endif #endif
mDestroyed = true;
// Make sure to call `RemoveBrowsingContextGroup` for every entry in both // Make sure to call `RemoveBrowsingContextGroup` for every entry in both
// `mHosts` and `mSubscribers`. This will visit most entries twice, but // `mHosts` and `mSubscribers`. This will visit most entries twice, but

View file

@ -87,6 +87,12 @@ class BrowsingContextGroup final : public nsWrapperCache {
// BrowsingContextGroup, if possible. // BrowsingContextGroup, if possible.
ContentParent* GetHostProcess(const nsACString& aRemoteType); ContentParent* GetHostProcess(const nsACString& aRemoteType);
// Check if the process which sent the message being read from aReader is
// aware of this BrowsingContextGroup's existence.
// If this returns false, it will first set a fatal error on aReader with more
// details.
bool IsKnownForMessageReader(IPC::MessageReader* aReader);
// When a BrowsingContext is being discarded, we may want to keep the // When a BrowsingContext is being discarded, we may want to keep the
// corresponding BrowsingContextGroup alive until the other process // corresponding BrowsingContextGroup alive until the other process
// acknowledges that the BrowsingContext has been discarded. A `KeepAlive` // acknowledges that the BrowsingContext has been discarded. A `KeepAlive`
@ -260,9 +266,7 @@ class BrowsingContextGroup final : public nsWrapperCache {
uint32_t mKeepAliveCount = 0; uint32_t mKeepAliveCount = 0;
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
bool mDestroyed = false; bool mDestroyed = false;
#endif
// A BrowsingContextGroup contains a series of {Browsing,Window}Context // A BrowsingContextGroup contains a series of {Browsing,Window}Context
// objects. They are addressed using a hashtable to avoid linear lookup when // objects. They are addressed using a hashtable to avoid linear lookup when

View file

@ -764,6 +764,10 @@ bool IPDLParamTraits<dom::MaybeDiscarded<dom::WindowContext>>::Read(
if (id == 0) { if (id == 0) {
*aResult = nullptr; *aResult = nullptr;
} else if (RefPtr<dom::WindowContext> wc = dom::WindowContext::GetById(id)) { } else if (RefPtr<dom::WindowContext> wc = dom::WindowContext::GetById(id)) {
if (!wc->Group()->IsKnownForMessageReader(aReader)) {
return false;
}
*aResult = std::move(wc); *aResult = std::move(wc);
} else { } else {
aResult->SetDiscarded(id); aResult->SetDiscarded(id);

View file

@ -38,6 +38,11 @@ void AbortSignalImpl::GetReason(JSContext* aCx,
} }
MaybeAssignAbortError(aCx); MaybeAssignAbortError(aCx);
aReason.set(mReason); 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(); } JS::Value AbortSignalImpl::RawReason() const { return mReason.get(); }
@ -75,7 +80,7 @@ void AbortSignalImpl::RunAbortSteps() {
// https://dom.spec.whatwg.org/#abortsignal-remove could be invoked in an // https://dom.spec.whatwg.org/#abortsignal-remove could be invoked in an
// earlier algorithm to remove a later algorithm, so |mFollowers| must be a // earlier algorithm to remove a later algorithm, so |mFollowers| must be a
// |nsTObserverArray| to defend against mutation. // |nsTObserverArray| to defend against mutation.
for (RefPtr<AbortFollower>& follower : mFollowers.ForwardRange()) { for (RefPtr<AbortFollower> follower : mFollowers.ForwardRange()) {
MOZ_ASSERT(follower->mFollowingSignal == this); MOZ_ASSERT(follower->mFollowingSignal == this);
follower->RunAbortAlgorithm(); follower->RunAbortAlgorithm();
} }

View file

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

View file

@ -466,6 +466,7 @@ class Animation : public DOMEventTargetHelper,
friend class AsyncFinishNotification; friend class AsyncFinishNotification;
void DoFinishNotificationImmediately(MicroTaskRunnable* aAsync = nullptr); void DoFinishNotificationImmediately(MicroTaskRunnable* aAsync = nullptr);
void QueuePlaybackEvent(nsAtom* aOnEvent, TimeStamp&& aScheduledEventTime); void QueuePlaybackEvent(nsAtom* aOnEvent, TimeStamp&& aScheduledEventTime);
void MaybeResolvePromiseWithThis(Promise*);
/** /**
* Remove this animation from the pending animation tracker and reset * Remove this animation from the pending animation tracker and reset

View file

@ -687,7 +687,10 @@ class SimpleHTMLCollection final : public nsSimpleContentList,
} }
virtual uint32_t Length() override { return nsSimpleContentList::Length(); } virtual uint32_t Length() override { return nsSimpleContentList::Length(); }
virtual Element* GetElementAt(uint32_t aIndex) override { virtual Element* GetElementAt(uint32_t aIndex) override {
return mElements.SafeElementAt(aIndex)->AsElement(); if (nsIContent* content = mElements.SafeElementAt(aIndex)) {
return content->AsElement();
}
return nullptr;
} }
virtual Element* GetFirstNamedElement(const nsAString& aName, virtual Element* GetFirstNamedElement(const nsAString& aName,
@ -10661,23 +10664,25 @@ void nsDOMAttributeMap::BlastSubtreeToPieces(nsINode* aNode) {
mozilla::DebugOnly<nsresult> rv = mozilla::DebugOnly<nsresult> rv =
element->UnsetAttr(attr->NodeInfo()->NamespaceID(), element->UnsetAttr(attr->NodeInfo()->NamespaceID(),
attr->NodeInfo()->NameAtom(), false); attr->NodeInfo()->NameAtom(), true);
// XXX Should we abort here? // XXX Should we abort here?
NS_ASSERTION(NS_SUCCEEDED(rv), "Uh-oh, UnsetAttr shouldn't fail!"); NS_ASSERTION(NS_SUCCEEDED(rv), "Uh-oh, UnsetAttr shouldn't fail!");
} }
} }
if (mozilla::dom::ShadowRoot* shadow = element->GetShadowRoot()) { // Hold the strong reference to be sure, since we may notify
if (RefPtr<mozilla::dom::ShadowRoot> shadow = element->GetShadowRoot()) {
BlastSubtreeToPieces(shadow); BlastSubtreeToPieces(shadow);
element->UnattachShadow(); element->UnattachShadow();
} }
} }
while (aNode->HasChildren()) { while (aNode->HasChildren()) {
nsIContent* node = aNode->GetFirstChild(); // Hold the strong reference to be sure, since we are notifying.
nsCOMPtr<nsIContent> node = aNode->GetFirstChild();
BlastSubtreeToPieces(node); BlastSubtreeToPieces(node);
aNode->RemoveChildNode(node, false); aNode->RemoveChildNode(node, true);
} }
} }
@ -16272,11 +16277,16 @@ void Document::RequestFullscreenInParentProcess(
/* static */ /* static */
bool Document::HandlePendingFullscreenRequests(Document* aDoc) { 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; bool handled = false;
PendingFullscreenChangeList::Iterator<FullscreenRequest> iter( for (UniquePtr<FullscreenRequest>& request : requests) {
aDoc, PendingFullscreenChangeList::eDocumentsWithSameRoot);
while (!iter.AtEnd()) {
UniquePtr<FullscreenRequest> request = iter.TakeAndNext();
Document* doc = request->Document(); Document* doc = request->Document();
if (doc->ApplyFullscreen(std::move(request))) { if (doc->ApplyFullscreen(std::move(request))) {
handled = true; handled = true;

View file

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

View file

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

View file

@ -279,8 +279,9 @@ nsIFrame* nsIContent::GetPrimaryFrame(mozilla::FlushType aType) {
return nullptr; return nullptr;
} }
RefPtr<mozilla::PresShell> presShell = frame->PresShell();
if (aType == mozilla::FlushType::Layout) { if (aType == mozilla::FlushType::Layout) {
frame->PresShell()->EnsureReflowIfFrameHasHiddenContent(frame); presShell->EnsureReflowIfFrameHasHiddenContent(frame);
frame = GetPrimaryFrame(); frame = GetPrimaryFrame();
} }
@ -2807,6 +2808,7 @@ bool Element::OnlyNotifySameValueSet(int32_t aNamespaceID, nsAtom* aName,
} }
nsAutoScriptBlocker scriptBlocker; nsAutoScriptBlocker scriptBlocker;
OnAttrSetButNotChanged(aNamespaceID, aName, aValue, aNotify);
MutationObservers::NotifyAttributeSetToCurrentValue(this, aNamespaceID, MutationObservers::NotifyAttributeSetToCurrentValue(this, aNamespaceID,
aName); aName);
return true; return true;
@ -2856,7 +2858,6 @@ nsresult Element::SetAttr(int32_t aNamespaceID, nsAtom* aName, nsAtom* aPrefix,
if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify, if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
oldValue, &modType, &hasListeners, oldValue, &modType, &hasListeners,
&oldValueSet)) { &oldValueSet)) {
OnAttrSetButNotChanged(aNamespaceID, aName, value, aNotify);
return NS_OK; return NS_OK;
} }
} }
@ -2906,7 +2907,6 @@ nsresult Element::SetParsedAttr(int32_t aNamespaceID, nsAtom* aName,
if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify, if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
oldValue, &modType, &hasListeners, oldValue, &modType, &hasListeners,
&oldValueSet)) { &oldValueSet)) {
OnAttrSetButNotChanged(aNamespaceID, aName, value, aNotify);
return NS_OK; return NS_OK;
} }
} }

View file

@ -341,8 +341,8 @@ nsresult ImageEncoder::ExtractDataInternal(
return NS_ERROR_INVALID_ARG; return NS_ERROR_INVALID_ARG;
} }
auto size = data->GetSize(); auto size = data->GetSize();
rv = aEncoder->InitFromData(map.mData, size.width * size.height * 4, rv = aEncoder->InitFromData(map.mData, map.mStride * size.height,
size.width, size.height, size.width * 4, size.width, size.height, map.mStride,
imgIEncoder::INPUT_FORMAT_HOSTARGB, aOptions); imgIEncoder::INPUT_FORMAT_HOSTARGB, aOptions);
data->Unmap(); data->Unmap();
} }
@ -374,8 +374,8 @@ nsresult ImageEncoder::ExtractDataInternal(
} }
rv = aEncoder->InitFromData(data.Elements(), rv = aEncoder->InitFromData(data.Elements(),
aSize.width * aSize.height * 4, aSize.width, length, aSize.width,
aSize.height, aSize.width * 4, aSize.height, stride,
imgIEncoder::INPUT_FORMAT_HOSTARGB, aOptions); imgIEncoder::INPUT_FORMAT_HOSTARGB, aOptions);
} else { } else {
if (BufferSizeFromDimensions(aSize.width, aSize.height, 4) == 0) { if (BufferSizeFromDimensions(aSize.width, aSize.height, 4) == 0) {
@ -391,8 +391,8 @@ nsresult ImageEncoder::ExtractDataInternal(
return NS_ERROR_INVALID_ARG; return NS_ERROR_INVALID_ARG;
} }
auto size = dataSurface->GetSize(); auto size = dataSurface->GetSize();
rv = aEncoder->InitFromData(map.mData, size.width * size.height * 4, rv = aEncoder->InitFromData(map.mData, map.mStride * size.height,
size.width, size.height, size.width * 4, size.width, size.height, map.mStride,
imgIEncoder::INPUT_FORMAT_HOSTARGB, aOptions); imgIEncoder::INPUT_FORMAT_HOSTARGB, aOptions);
dataSurface->Unmap(); dataSurface->Unmap();
} }
@ -421,13 +421,13 @@ nsresult ImageEncoder::ExtractDataInternal(
if (!emptyCanvas->Map(DataSourceSurface::MapType::WRITE, &map)) { if (!emptyCanvas->Map(DataSourceSurface::MapType::WRITE, &map)) {
return NS_ERROR_INVALID_ARG; return NS_ERROR_INVALID_ARG;
} }
auto size = map.mStride * aSize.height;
if (aUsePlaceholder) { if (aUsePlaceholder) {
auto size = 4 * aSize.width * aSize.height;
auto* data = map.mData; auto* data = map.mData;
GeneratePlaceholderCanvasData(size, data); GeneratePlaceholderCanvasData(size, data);
} }
rv = aEncoder->InitFromData(map.mData, aSize.width * aSize.height * 4, rv = aEncoder->InitFromData(map.mData, size, aSize.width, aSize.height,
aSize.width, aSize.height, aSize.width * 4, map.mStride,
imgIEncoder::INPUT_FORMAT_HOSTARGB, aOptions); imgIEncoder::INPUT_FORMAT_HOSTARGB, aOptions);
emptyCanvas->Unmap(); emptyCanvas->Unmap();
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {

View file

@ -271,6 +271,7 @@ template <typename char_type>
const nsTSubstring<char_type>& aMimeType, const nsTSubstring<char_type>& aMimeType,
nsTSubstring<char_type>& aOutEssence, nsTSubstring<char_type>& aOutEssence,
nsTSubstring<char_type>& aOutCharset) { 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 char_type kCHARSET[] = {'c', 'h', 'a', 'r', 's', 'e', 't'};
static nsTDependentSubstring<char_type> kCharset(kCHARSET, 7); static nsTDependentSubstring<char_type> kCharset(kCHARSET, 7);
@ -278,8 +279,8 @@ template <typename char_type>
nsTAutoString<char_type> prevContentType; nsTAutoString<char_type> prevContentType;
nsTAutoString<char_type> prevCharset; nsTAutoString<char_type> prevCharset;
prevContentType.Assign(aOutEssence); aOutEssence.Truncate();
prevCharset.Assign(aOutCharset); aOutCharset.Truncate();
nsTArray<nsTDependentSubstring<char_type>> mimeTypeParts = nsTArray<nsTDependentSubstring<char_type>> mimeTypeParts =
SplitMimetype(aMimeType); SplitMimetype(aMimeType);
@ -292,9 +293,7 @@ template <typename char_type>
parsed = Parse(mimeTypeString); parsed = Parse(mimeTypeString);
if (!parsed) { if (!parsed) {
aOutEssence.Truncate(); continue;
aOutCharset.Truncate();
return false;
} }
parsed->GetEssence(aOutEssence); parsed->GetEssence(aOutEssence);
@ -322,6 +321,10 @@ template <typename char_type>
} }
} }
if (aOutEssence.IsEmpty()) {
return false;
}
return true; return true;
} }

View file

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

View file

@ -33,8 +33,13 @@ class ScreenOrientation final : public DOMEventTargetHelper {
// Called when the orientation may have changed. // Called when the orientation may have changed.
void MaybeChanged(); void MaybeChanged();
private:
ScreenOrientation(nsPIDOMWindowInner* aWindow, nsScreen* aScreen); ScreenOrientation(nsPIDOMWindowInner* aWindow, nsScreen* aScreen);
public:
static already_AddRefed<ScreenOrientation> Create(nsPIDOMWindowInner* aWindow,
nsScreen* aScreen);
already_AddRefed<Promise> Lock(OrientationLockType aOrientation, already_AddRefed<Promise> Lock(OrientationLockType aOrientation,
ErrorResult& aRv); ErrorResult& aRv);
@ -107,8 +112,8 @@ class ScreenOrientation final : public DOMEventTargetHelper {
RefPtr<nsScreen> mScreen; RefPtr<nsScreen> mScreen;
RefPtr<FullscreenEventListener> mFullscreenListener; RefPtr<FullscreenEventListener> mFullscreenListener;
RefPtr<VisibleEventListener> mVisibleListener; RefPtr<VisibleEventListener> mVisibleListener;
OrientationType mType; OrientationType mType{};
uint16_t mAngle; uint16_t mAngle{};
// Whether we've tried to call into hal to lock the device orientation. This // Whether we've tried to call into hal to lock the device orientation. This
// is needed because you don't want calling UnlockDeviceOrientation() during // is needed because you don't want calling UnlockDeviceOrientation() during
// shutdown to initialize PHal if it hasn't been initialized earlier. Also, // 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) { void ShadowRoot::InvalidateStyleAndLayoutOnSubtree(Element* aElement) {
MOZ_ASSERT(aElement); MOZ_ASSERT(aElement);
Document* doc = GetComposedDoc(); Document* doc = aElement->GetComposedDoc();
if (!doc) { if (!doc) {
return; 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 * 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. * around, so that layout knows the actual tree that it needs to invalidate.
*/ */
void InvalidateStyleAndLayoutOnSubtree(Element*); static void InvalidateStyleAndLayoutOnSubtree(Element*);
private: private:
void InsertSheetIntoAuthorData(size_t aIndex, StyleSheet&, void InsertSheetIntoAuthorData(size_t aIndex, StyleSheet&,

View file

@ -15,8 +15,10 @@
#include "js/Wrapper.h" #include "js/Wrapper.h"
#include "jsapi.h" #include "jsapi.h"
#include "mozilla/Assertions.h" #include "mozilla/Assertions.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/ErrorResult.h" #include "mozilla/ErrorResult.h"
#include "mozilla/Maybe.h" #include "mozilla/Maybe.h"
#include "mozilla/Span.h"
#include "mozilla/UniquePtr.h" #include "mozilla/UniquePtr.h"
#include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/BlobImpl.h" #include "mozilla/dom/BlobImpl.h"
@ -173,7 +175,8 @@ bool StructuredCloneBlob::Holder::ReadStructuredCloneInternal(
return false; return false;
} }
#endif #endif
BlobImpls().AppendElements(&aHolder->BlobImpls()[blobOffset], blobCount); BlobImpls().AppendElements(
Span(aHolder->BlobImpls()).Subspan(blobOffset, blobCount));
} }
JSStructuredCloneData data(mStructuredCloneScope); JSStructuredCloneData data(mStructuredCloneScope);
@ -212,8 +215,13 @@ bool StructuredCloneBlob::WriteStructuredClone(JSContext* aCx,
bool StructuredCloneBlob::Holder::WriteStructuredClone( bool StructuredCloneBlob::Holder::WriteStructuredClone(
JSContext* aCx, JSStructuredCloneWriter* aWriter, JSContext* aCx, JSStructuredCloneWriter* aWriter,
StructuredCloneHolder* aHolder) { StructuredCloneHolder* aHolder) {
auto& data = mBuffer->data(); const auto& data = mBuffer->data();
if (!JS_WriteUint32Pair(aWriter, data.Size(), JS_STRUCTURED_CLONE_VERSION) || CheckedUint32 dataSize(data.Size());
if (!dataSize.isValid()) {
return false;
}
if (!JS_WriteUint32Pair(aWriter, dataSize.value(),
JS_STRUCTURED_CLONE_VERSION) ||
!JS_WriteUint32Pair(aWriter, aHolder->BlobImpls().Length(), !JS_WriteUint32Pair(aWriter, aHolder->BlobImpls().Length(),
BlobImpls().Length())) { BlobImpls().Length())) {
return false; return false;

View file

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

View file

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

View file

@ -1333,7 +1333,11 @@ void nsAttrValue::ParseAtom(const nsAString& aValue) {
void nsAttrValue::ParseAtomArray(nsAtom* aValue) { void nsAttrValue::ParseAtomArray(nsAtom* aValue) {
if (MiscContainer* cont = AtomArrayCache::Lookup(aValue)) { if (MiscContainer* cont = AtomArrayCache::Lookup(aValue)) {
// Set our MiscContainer to the cached one. // 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); NS_ADDREF(cont);
ResetIfSet();
SetPtrValueAndType(cont, eOtherBase); SetPtrValueAndType(cont, eOtherBase);
return; return;
} }
@ -1933,7 +1937,11 @@ bool nsAttrValue::ParseStyleAttribute(const nsAString& aString,
if (cachingAllowed) { if (cachingAllowed) {
if (MiscContainer* cont = attrStyles->LookupStyleAttr(aString)) { if (MiscContainer* cont = attrStyles->LookupStyleAttr(aString)) {
// Set our MiscContainer to the cached one. // 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); NS_ADDREF(cont);
ResetIfSet();
SetPtrValueAndType(cont, eOtherBase); SetPtrValueAndType(cont, eOtherBase);
return true; return true;
} }

View file

@ -592,7 +592,8 @@ Element* nsContentList::NamedItem(const nsAString& aName, bool aDoFlush) {
return mNamedItemsCache->Get(name); return mNamedItemsCache->Get(name);
} }
void nsContentList::GetSupportedNames(nsTArray<nsString>& aNames) { void nsContentList::GetSupportedNames(nsTArray<nsString>& aNames,
FilterElementWithName aFilter) {
BringSelfUpToDate(true); BringSelfUpToDate(true);
AutoTArray<nsAtom*, 8> atoms; AutoTArray<nsAtom*, 8> atoms;
@ -606,14 +607,14 @@ void nsContentList::GetSupportedNames(nsTArray<nsString>& aNames) {
} }
} }
nsGenericHTMLElement* el = nsGenericHTMLElement::FromNode(content); if (nsGenericHTMLElement* el = nsGenericHTMLElement::FromNode(content)) {
if (el) {
// XXXbz should we be checking for particular tags here? How // XXXbz should we be checking for particular tags here? How
// stable is this part of the spec? // stable is this part of the spec?
// Note: nsINode::HasName means the name is exposed on the document, // Note: nsINode::HasName means the name is exposed on the document,
// which is false for options, so we don't check it here. // which is false for options, so we don't check it here.
const nsAttrValue* val = el->GetParsedAttr(nsGkAtoms::name); const nsAttrValue* val = el->GetParsedAttr(nsGkAtoms::name);
if (val && val->Type() == nsAttrValue::eAtom) { if (val && val->Type() == nsAttrValue::eAtom &&
(!aFilter || aFilter(el))) {
nsAtom* name = val->GetAtomValue(); nsAtom* name = val->GetAtomValue();
MOZ_ASSERT(name != nsGkAtoms::_empty, "Empty names don't get atomized"); MOZ_ASSERT(name != nsGkAtoms::_empty, "Empty names don't get atomized");
if (!atoms.Contains(name)) { if (!atoms.Contains(name)) {

View file

@ -296,13 +296,21 @@ class nsContentList : public nsBaseContentList,
aFound = !!item; aFound = !!item;
return item; return item;
} }
void GetSupportedNames(nsTArray<nsString>& aNames) override; void GetSupportedNames(nsTArray<nsString>& aNames) override {
GetSupportedNames(aNames, nullptr);
}
// nsContentList public methods // nsContentList public methods
uint32_t Length(bool aDoFlush); uint32_t Length(bool aDoFlush);
nsIContent* Item(uint32_t aIndex, bool aDoFlush); nsIContent* Item(uint32_t aIndex, bool aDoFlush);
Element* NamedItem(const nsAString& aName, 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 // nsIMutationObserver
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED

View file

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

View file

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

View file

@ -4533,10 +4533,9 @@ nsDOMWindowUtils::WrCapture() {
} }
NS_IMETHODIMP NS_IMETHODIMP
nsDOMWindowUtils::WrStartCaptureSequence(const nsACString& aPath, nsDOMWindowUtils::WrStartCaptureSequence(uint32_t aFlags) {
uint32_t aFlags) {
if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) { if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) {
wrbc->StartCaptureSequence(nsCString(aPath), aFlags); wrbc->StartCaptureSequence(aFlags);
} }
return NS_OK; 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 // 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 // we recreate the frame loader, this is not what we want, so add our own
// blocker until the process is complete. // blocker until the process is complete.
Document* doc = owner->OwnerDoc(); RefPtr<Document> doc = owner->OwnerDoc();
doc->BlockOnload(); doc->BlockOnload();
auto cleanup = MakeScopeExit([&]() { doc->UnblockOnload(false); }); auto cleanup = MakeScopeExit([&]() { doc->UnblockOnload(false); });

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