Bug 1827856 - Remove nativeAnonymousChildList observers. r=smaug,credential-management-reviewers,devtools-reviewers,sgalich,nchevobbe

You let me know if this seems appealing to you :)

Differential Revision: https://phabricator.services.mozilla.com/D175382
This commit is contained in:
Emilio Cobos Álvarez 2023-04-18 14:58:34 +00:00
Родитель 193c21ac76
Коммит 8b5b7ad998
31 изменённых файлов: 137 добавлений и 438 удалений

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

@ -796,21 +796,6 @@ void DocAccessible::AttributeWillChange(dom::Element* aElement,
}
}
void DocAccessible::NativeAnonymousChildListChange(nsIContent* aContent,
bool aIsRemove) {
if (aIsRemove) {
#ifdef A11Y_LOG
if (logging::IsEnabled(logging::eTree)) {
logging::MsgBegin("TREE", "Anonymous content removed; doc: %p", this);
logging::Node("node", aContent);
logging::MsgEnd();
}
#endif
ContentRemoved(aContent);
}
}
void DocAccessible::AttributeChanged(dom::Element* aElement,
int32_t aNameSpaceID, nsAtom* aAttribute,
int32_t aModType,

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

@ -216,10 +216,7 @@ class WalkerFront extends FrontClassWithSpec(walkerSpec) {
const emittedMutation = Object.assign(change, { target: targetFront });
if (
change.type === "childList" ||
change.type === "nativeAnonymousChildList"
) {
if (change.type === "childList") {
// Update the ownership tree according to the mutation record.
const addedFronts = [];
const removedFronts = [];
@ -287,8 +284,7 @@ class WalkerFront extends FrontClassWithSpec(walkerSpec) {
if (
change.type === "inlineTextChild" ||
change.type === "childList" ||
change.type === "shadowRootAttached" ||
change.type === "nativeAnonymousChildList"
change.type === "shadowRootAttached"
) {
if (change.inlineTextChild) {
targetFront.inlineTextChild = types

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

@ -1571,7 +1571,6 @@ MarkupView.prototype = {
container.update();
} else if (
type === "childList" ||
type === "nativeAnonymousChildList" ||
type === "slotchange" ||
type === "shadowRootAttached"
) {

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

@ -72,8 +72,7 @@ add_task(async function() {
info(
"Move the non-slotted element with class has-before and check the pseudo appears"
);
const mutated = waitForNMutations(inspector, "childList", 2);
const pseudoMutated = waitForMutation(inspector, "nativeAnonymousChildList");
const mutated = waitForNMutations(inspector, "childList", 3);
SpecialPowers.spawn(gBrowser.selectedBrowser, [], function() {
const root = content.document.querySelector(".root");
const hasBeforeEl = content.document.querySelector(
@ -82,7 +81,6 @@ add_task(async function() {
root.appendChild(hasBeforeEl);
});
await mutated;
await pseudoMutated;
// As the non-slotted has-before is moved into the tree, the before pseudo is expected
// to appear.

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

@ -70,7 +70,7 @@ __WalkerActor__
- But only has a partial knowledge of the DOM (what is currently displayed/expanded in the MarkupView). It doesn't need to walk the whole tree when you first instantiate it.
- Reflects some of the usual DOM APIs like querySelector.
- Note that methods like querySelector return arbitrarily nested NodeActors, in which case the WalkerActor also sends the list of parents to link the returned nodes to the closest known nodes, so the UI can display the tree correctly.
- Emits events when there are DOM mutations. These events are sent to the front-end and used to, for example refresh the markup-view. This uses an instance of MutationObserver (https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) configured with, in particular, nativeAnonymousChildList set to true, so that mutation events are also sent when pseudo elements are added/removed via css.
- Emits events when there are DOM mutations. These events are sent to the front-end and used to, for example refresh the markup-view. This uses an instance of MutationObserver (https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) configured with, in particular, chromeOnlyNodes set to true, so that mutation events are also sent when pseudo elements are added/removed via css.
__NodeActor__

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

@ -265,7 +265,6 @@ class NodeActor extends Actor {
const observer = new doc.defaultView.MutationObserver(callback);
observer.mergeAttributeRecords = true;
observer.observe(node, {
nativeAnonymousChildList: true,
attributes: true,
characterData: true,
characterDataOldValue: true,

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

@ -215,6 +215,7 @@ class WalkerActor extends Actor {
this._pendingMutations = [];
this._activePseudoClassLocks = new Set();
this._mutationBreakpoints = new WeakMap();
this._anonParents = new WeakMap();
this.customElementWatcher = new CustomElementWatcher(
targetActor.chromeEventHandler
);
@ -247,6 +248,8 @@ class WalkerActor extends Actor {
this.onMutations = this.onMutations.bind(this);
this.onSlotchange = this.onSlotchange.bind(this);
this.onShadowrootattached = this.onShadowrootattached.bind(this);
this.onAnonymousrootcreated = this.onAnonymousrootcreated.bind(this);
this.onAnonymousrootremoved = this.onAnonymousrootremoved.bind(this);
this.onFrameLoad = this.onFrameLoad.bind(this);
this.onFrameUnload = this.onFrameUnload.bind(this);
this.onCustomElementDefined = this.onCustomElementDefined.bind(this);
@ -271,9 +274,17 @@ class WalkerActor extends Actor {
"shadowrootattached",
this.onShadowrootattached
);
// anonymousrootcreated is a chrome-only event. We enable it below.
this.chromeEventHandler.addEventListener(
"anonymousrootcreated",
this.onAnonymousrootcreated
);
this.chromeEventHandler.addEventListener(
"anonymousrootremoved",
this.onAnonymousrootremoved
);
for (const { document } of this.targetActor.windows) {
document.shadowRootAttachedEventEnabled = true;
document.devToolsAnonymousAndShadowEventsEnabled = true;
}
// Ensure that the root document node actor is ready and
@ -384,10 +395,18 @@ class WalkerActor extends Actor {
"shadowrootattached",
this.onShadowrootattached
);
this.chromeEventHandler.removeEventListener(
"anonymousrootcreated",
this.onAnonymousrootcreated
);
this.chromeEventHandler.removeEventListener(
"anonymousrootremoved",
this.onAnonymousrootremoved
);
// This event is just for devtools, so we can unset once we're done.
// This attribute is just for devtools, so we can unset once we're done.
for (const { document } of this.targetActor.windows) {
document.shadowRootAttachedEventEnabled = false;
document.devToolsAnonymousAndShadowEventsEnabled = false;
}
this.onFrameLoad = null;
@ -2169,7 +2188,7 @@ class WalkerActor extends Actor {
} else if (type === "characterData") {
mutation.newValue = targetNode.nodeValue;
this._maybeQueueInlineTextChildMutation(change, targetNode);
} else if (type === "childList" || type === "nativeAnonymousChildList") {
} else if (type === "childList") {
// Get the list of removed and added actors that the client has seen
// so that it can keep its ownership tree up to date.
const removedActors = [];
@ -2262,6 +2281,52 @@ class WalkerActor extends Actor {
});
}
/**
* Fires when an anonymous root is created.
* This is needed because regular mutation observers don't fire on some kinds
* of NAC creation. We want to treat this like a regular insertion.
*/
onAnonymousrootcreated(event) {
const root = event.target;
const parent = this.rawParentNode(root);
if (!parent) {
// These events are async. The node might have been removed already, in
// which case there's nothing to do anymore.
return;
}
// By the time onAnonymousrootremoved fires, the node is already detached
// from its parent, so we need to remember it by hand.
this._anonParents.set(root, parent);
this.onMutations([
{
type: "childList",
target: parent,
addedNodes: [root],
removedNodes: [],
},
]);
}
/**
* @see onAnonymousrootcreated
*/
onAnonymousrootremoved(event) {
const root = event.target;
const parent = this._anonParents.get(root);
if (!parent) {
return;
}
this._anonParents.delete(root);
this.onMutations([
{
type: "childList",
target: parent,
addedNodes: [],
removedNodes: [root],
},
]);
}
onShadowrootattached(event) {
const actor = this.getNode(event.target);
if (!actor) {

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

@ -459,9 +459,6 @@ nsresult CharacterData::BindToTree(BindContext& aContext, nsINode& aParent) {
}
MutationObservers::NotifyParentChainChanged(this);
if (!hadParent && IsRootOfNativeAnonymousSubtree()) {
MutationObservers::NotifyNativeAnonymousChildListChange(this, false);
}
UpdateEditableState(false);
@ -488,9 +485,6 @@ void CharacterData::UnbindFromTree(bool aNullParent) {
HandleShadowDOMRelatedRemovalSteps(aNullParent);
if (aNullParent) {
if (IsRootOfNativeAnonymousSubtree()) {
MutationObservers::NotifyNativeAnonymousChildListChange(this, true);
}
if (GetParent()) {
NS_RELEASE(mParent);
} else {

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

@ -1366,7 +1366,7 @@ Document::Document(const char* aContentType)
mBFCacheDisallowed(false),
mHasHadDefaultView(false),
mStyleSheetChangeEventsEnabled(false),
mShadowRootAttachedEventEnabled(false),
mDevToolsAnonymousAndShadowEventsEnabled(false),
mIsSrcdocDocument(false),
mHasDisplayDocument(false),
mFontFaceSetDirty(true),

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

@ -3602,11 +3602,11 @@ class Document : public nsINode,
return mStyleSheetChangeEventsEnabled;
}
void SetShadowRootAttachedEventEnabled(bool aValue) {
mShadowRootAttachedEventEnabled = aValue;
void SetDevToolsAnonymousAndShadowEventsEnabled(bool aValue) {
mDevToolsAnonymousAndShadowEventsEnabled = aValue;
}
bool ShadowRootAttachedEventEnabled() const {
return mShadowRootAttachedEventEnabled;
bool DevToolsAnonymousAndShadowEventsEnabled() const {
return mDevToolsAnonymousAndShadowEventsEnabled;
}
already_AddRefed<Promise> BlockParsing(Promise& aPromise,
@ -4740,8 +4740,9 @@ class Document : public nsINode,
// Whether style sheet change events will be dispatched for this document
bool mStyleSheetChangeEventsEnabled : 1;
// Whether shadowrootattached events will be dispatched for this document.
bool mShadowRootAttachedEventEnabled : 1;
// Whether shadowrootattached/anonymousnodecreated/anonymousnoderemoved events
// will be dispatched for this document.
bool mDevToolsAnonymousAndShadowEventsEnabled : 1;
// Whether the document was created by a srcdoc iframe.
bool mIsSrcdocDocument : 1;

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

@ -1275,10 +1275,10 @@ already_AddRefed<ShadowRoot> Element::AttachShadowWithoutNameChecks(
SlotAssignmentMode aSlotAssignment) {
nsAutoScriptBlocker scriptBlocker;
auto* nim = mNodeInfo->NodeInfoManager();
RefPtr<mozilla::dom::NodeInfo> nodeInfo =
mNodeInfo->NodeInfoManager()->GetNodeInfo(
nsGkAtoms::documentFragmentNodeName, nullptr, kNameSpaceID_None,
DOCUMENT_FRAGMENT_NODE);
nim->GetNodeInfo(nsGkAtoms::documentFragmentNodeName, nullptr,
kNameSpaceID_None, DOCUMENT_FRAGMENT_NODE);
// If there are no children, the flat tree is not changing due to the presence
// of the shadow root, so we don't need to invalidate style / layout.
@ -1296,7 +1296,6 @@ already_AddRefed<ShadowRoot> Element::AttachShadowWithoutNameChecks(
* context object's node document, host is context object,
* and mode is init's mode.
*/
auto* nim = nodeInfo->NodeInfoManager();
RefPtr<ShadowRoot> shadowRoot = new (nim) ShadowRoot(
this, aMode, aDelegatesFocus, aSlotAssignment, nodeInfo.forget());
@ -1320,7 +1319,8 @@ already_AddRefed<ShadowRoot> Element::AttachShadowWithoutNameChecks(
SetShadowRoot(shadowRoot);
// Dispatch a "shadowrootattached" event for devtools if needed.
if (MOZ_UNLIKELY(nim->GetDocument()->ShadowRootAttachedEventEnabled())) {
if (MOZ_UNLIKELY(
nim->GetDocument()->DevToolsAnonymousAndShadowEventsEnabled())) {
AsyncEventDispatcher* dispatcher = new AsyncEventDispatcher(
this, u"shadowrootattached"_ns, CanBubble::eYes,
ChromeOnlyDispatch::eYes, Composed::eYes);
@ -1899,9 +1899,6 @@ nsresult Element::BindToTree(BindContext& aContext, nsINode& aParent) {
}
MutationObservers::NotifyParentChainChanged(this);
if (!hadParent && IsRootOfNativeAnonymousSubtree()) {
MutationObservers::NotifyNativeAnonymousChildListChange(this, false);
}
// Ensure we only run this once, in the case we move the ShadowRoot around.
if (aContext.SubtreeRootChanges()) {
@ -2012,10 +2009,6 @@ void Element::UnbindFromTree(bool aNullParent) {
}
if (aNullParent) {
if (IsRootOfNativeAnonymousSubtree()) {
MutationObservers::NotifyNativeAnonymousChildListChange(this, true);
}
if (GetParent()) {
RefPtr<nsINode> p;
p.swap(mParent);

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

@ -163,19 +163,6 @@ void MutationObservers::NotifyContentAppended(nsIContent* aContainer,
Notify(aContainer, notifyPresShell, notifyObserver);
}
void MutationObservers::NotifyNativeAnonymousChildListChange(
nsIContent* aContent, bool aIsRemove) {
DEFINE_NOTIFIERS(NativeAnonymousChildListChange, (aContent, aIsRemove));
if (aIsRemove) {
// We can't actually assert that we reach the document if we're connected,
// since this notification runs from UnbindFromTree.
Notify<IsRemoval::Yes, ShouldAssert::No>(aContent, notifyPresShell,
notifyObserver);
} else {
Notify(aContent, notifyPresShell, notifyObserver);
}
}
void MutationObservers::NotifyContentInserted(nsINode* aContainer,
nsIContent* aChild) {
MOZ_ASSERT(aContainer->IsContent() || aContainer->IsDocument(),

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

@ -88,15 +88,6 @@ class MutationObservers {
static void NotifyContentAppended(nsIContent* aContainer,
nsIContent* aFirstNewContent);
/**
* Send NativeAnonymousChildList notifications to nsIMutationObservers
* @param aContent Anonymous node that's been added or removed
* @param aIsRemove True if it's a removal, false if an addition
* @see nsIMutationObserver::NativeAnonymousChildListChange
*/
static void NotifyNativeAnonymousChildListChange(nsIContent* aContent,
bool aIsRemove);
/**
* Send ContentInserted notifications to nsIMutationObservers
* @param aContainer Node into which new child was inserted

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

@ -138,35 +138,6 @@ void nsMutationReceiver::Disconnect(bool aRemoveFromObserver) {
}
}
void nsMutationReceiver::NativeAnonymousChildListChange(nsIContent* aContent,
bool aIsRemove) {
if (!NativeAnonymousChildList()) {
return;
}
nsINode* parent = aContent->GetParentNode();
if (!parent || (!Subtree() && Target() != parent) ||
(Subtree() && RegisterTarget()->SubtreeRoot() != parent->SubtreeRoot())) {
return;
}
nsDOMMutationRecord* m =
Observer()->CurrentRecord(nsGkAtoms::nativeAnonymousChildList);
if (m->mTarget) {
return;
}
m->mTarget = parent;
if (aIsRemove) {
m->mRemovedNodes = new nsSimpleContentList(parent);
m->mRemovedNodes->AppendElement(aContent);
} else {
m->mAddedNodes = new nsSimpleContentList(parent);
m->mAddedNodes->AppendElement(aContent);
}
}
void nsMutationReceiver::AttributeWillChange(Element* aElement,
int32_t aNameSpaceID,
nsAtom* aAttribute,
@ -637,7 +608,6 @@ void nsDOMMutationObserver::Observe(nsINode& aTarget,
bool subtree = aOptions.mSubtree;
bool attributeOldValue = aOptions.mAttributeOldValue.WasPassed() &&
aOptions.mAttributeOldValue.Value();
bool nativeAnonymousChildList = aOptions.mNativeAnonymousChildList;
bool characterDataOldValue = aOptions.mCharacterDataOldValue.WasPassed() &&
aOptions.mCharacterDataOldValue.Value();
bool animations = aOptions.mAnimations;
@ -654,8 +624,7 @@ void nsDOMMutationObserver::Observe(nsINode& aTarget,
characterData = true;
}
if (!(childList || attributes || characterData || animations ||
nativeAnonymousChildList)) {
if (!(childList || attributes || characterData || animations)) {
aRv.ThrowTypeError(
"One of 'childList', 'attributes', 'characterData' must not be false.");
return;
@ -703,7 +672,6 @@ void nsDOMMutationObserver::Observe(nsINode& aTarget,
r->SetSubtree(subtree);
r->SetAttributeOldValue(attributeOldValue);
r->SetCharacterDataOldValue(characterDataOldValue);
r->SetNativeAnonymousChildList(nativeAnonymousChildList);
r->SetAttributeFilter(std::move(filters));
r->SetAllAttributes(allAttrs);
r->SetAnimations(animations);
@ -765,7 +733,6 @@ void nsDOMMutationObserver::GetObservingInfo(
info.mSubtree = mr->Subtree();
info.mAttributeOldValue.Construct(mr->AttributeOldValue());
info.mCharacterDataOldValue.Construct(mr->CharacterDataOldValue());
info.mNativeAnonymousChildList = mr->NativeAnonymousChildList();
info.mAnimations = mr->Animations();
nsTArray<RefPtr<nsAtom>>& filters = mr->AttributeFilter();
if (filters.Length()) {

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

@ -153,15 +153,6 @@ class nsMutationReceiverBase : public nsStubAnimationObserver {
mCharacterDataOldValue = aOldValue;
}
bool NativeAnonymousChildList() const {
return mParent ? mParent->NativeAnonymousChildList()
: mNativeAnonymousChildList;
}
void SetNativeAnonymousChildList(bool aOldValue) {
NS_ASSERTION(!mParent, "Shouldn't have parent");
mNativeAnonymousChildList = aOldValue;
}
bool Attributes() const {
return mParent ? mParent->Attributes() : mAttributes;
}
@ -227,7 +218,6 @@ class nsMutationReceiverBase : public nsStubAnimationObserver {
mChildList(false),
mCharacterData(false),
mCharacterDataOldValue(false),
mNativeAnonymousChildList(false),
mAttributes(false),
mAllAttributes(false),
mAttributeOldValue(false),
@ -244,7 +234,6 @@ class nsMutationReceiverBase : public nsStubAnimationObserver {
mChildList(false),
mCharacterData(false),
mCharacterDataOldValue(false),
mNativeAnonymousChildList(false),
mAttributes(false),
mAllAttributes(false),
mAttributeOldValue(false),
@ -284,7 +273,6 @@ class nsMutationReceiverBase : public nsStubAnimationObserver {
bool mChildList : 1;
bool mCharacterData : 1;
bool mCharacterDataOldValue : 1;
bool mNativeAnonymousChildList : 1;
bool mAttributes : 1;
bool mAllAttributes : 1;
bool mAttributeOldValue : 1;
@ -341,7 +329,6 @@ class nsMutationReceiver : public nsMutationReceiverBase {
NS_DECL_ISUPPORTS
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE
NS_DECL_NSIMUTATIONOBSERVER_NATIVEANONYMOUSCHILDLISTCHANGE
NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATAWILLCHANGE
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED

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

@ -204,16 +204,6 @@ class nsIMutationObserver
int32_t aModType,
const nsAttrValue* aOldValue) = 0;
/**
* Notification that the root of a native anonymous has been added
* or removed.
*
* @param aContent Anonymous node that's been added or removed
* @param aIsRemove True if it's a removal, false if an addition
*/
virtual void NativeAnonymousChildListChange(nsIContent* aContent,
bool aIsRemove) {}
/**
* Notification that an attribute of an element has been
* set to the value it already had.
@ -331,10 +321,6 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIMutationObserver, NS_IMUTATION_OBSERVER_IID)
int32_t aNameSpaceID, nsAtom* aAttribute, \
int32_t aModType) override;
#define NS_DECL_NSIMUTATIONOBSERVER_NATIVEANONYMOUSCHILDLISTCHANGE \
virtual void NativeAnonymousChildListChange(nsIContent* aContent, \
bool aIsRemove) override;
#define NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED \
virtual void AttributeChanged(mozilla::dom::Element* aElement, \
int32_t aNameSpaceID, nsAtom* aAttribute, \
@ -371,7 +357,6 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIMutationObserver, NS_IMUTATION_OBSERVER_IID)
NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATAWILLCHANGE \
NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED \
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE \
NS_DECL_NSIMUTATIONOBSERVER_NATIVEANONYMOUSCHILDLISTCHANGE \
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED \
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED \
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED \
@ -392,8 +377,6 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIMutationObserver, NS_IMUTATION_OBSERVER_IID)
void _class::AttributeWillChange(mozilla::dom::Element* aElement, \
int32_t aNameSpaceID, nsAtom* aAttribute, \
int32_t aModType) {} \
void _class::NativeAnonymousChildListChange(nsIContent* aContent, \
bool aIsRemove) {} \
void _class::AttributeChanged( \
mozilla::dom::Element* aElement, int32_t aNameSpaceID, \
nsAtom* aAttribute, int32_t aModType, const nsAttrValue* aOldValue) {} \

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

@ -443,6 +443,15 @@ Element* nsINode::GetAnonymousRootElementOfTextEditor(
return rootElement;
}
void nsINode::QueueDevtoolsAnonymousEvent(bool aIsRemove) {
MOZ_ASSERT(IsRootOfNativeAnonymousSubtree());
MOZ_ASSERT(OwnerDoc()->DevToolsAnonymousAndShadowEventsEnabled());
AsyncEventDispatcher* dispatcher = new AsyncEventDispatcher(
this, aIsRemove ? u"anonymousrootremoved"_ns : u"anonymousrootcreated"_ns,
CanBubble::eYes, ChromeOnlyDispatch::eYes, Composed::eYes);
dispatcher->PostDOMEvent();
}
nsINode* nsINode::GetRootNode(const GetRootNodeOptions& aOptions) {
if (aOptions.mComposed) {
if (Document* doc = GetComposedDoc()) {
@ -3615,10 +3624,16 @@ ParentObject nsINode::GetParentObject() const {
ParentObject p(OwnerDoc());
// Note that mReflectionScope is a no-op for chrome, and other places where we
// don't check this value.
if (ShouldUseUAWidgetScope(this)) {
p.mReflectionScope = ReflectionScope::UAWidget;
} else if (ShouldUseNACScope(this)) {
p.mReflectionScope = ReflectionScope::NAC;
if (IsInNativeAnonymousSubtree()) {
if (ShouldUseUAWidgetScope(this)) {
p.mReflectionScope = ReflectionScope::UAWidget;
} else {
MOZ_ASSERT(ShouldUseNACScope(this));
p.mReflectionScope = ReflectionScope::NAC;
}
} else {
MOZ_ASSERT(!ShouldUseNACScope(this));
MOZ_ASSERT(!ShouldUseUAWidgetScope(this));
}
return p;
}

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

@ -1692,6 +1692,8 @@ class nsINode : public mozilla::dom::EventTarget {
*/
MOZ_CAN_RUN_SCRIPT_BOUNDARY void FireNodeRemovedForChildren();
void QueueDevtoolsAnonymousEvent(bool aIsRemove);
private:
mozilla::dom::SVGUseElement* DoGetContainingSVGUseShadowHost() const;

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

@ -71,12 +71,6 @@ class MutationObserverWrapper final : public nsIMutationObserver {
aOldValue);
}
void NativeAnonymousChildListChange(nsIContent* aContent,
bool aIsRemove) override {
MOZ_ASSERT(mOwner);
mOwner->NativeAnonymousChildListChange(aContent, aIsRemove);
}
void AttributeSetToCurrentValue(mozilla::dom::Element* aElement,
int32_t aNameSpaceID,
nsAtom* aAttribute) override {

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

@ -840,7 +840,6 @@ skip-if = os == 'mac' || os == 'linux' || headless
skip-if =
http3
[test_mozMatchesSelector.html]
[test_mutationobserver_anonymous.html]
[test_mutationobservers.html]
[test_named_frames.html]
[test_navigator_cookieEnabled.html]

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

@ -1,265 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1034110
-->
<head>
<title>Test for Bug 1034110</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1034110">Mozilla Bug 1034110</a>
<style type="text/css">
#pseudo.before::before { content: "before"; }
#pseudo.after::after { content: "after"; }
</style>
<div id="pseudo"></div>
<video id="video"></video>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 1034110 **/
SimpleTest.waitForExplicitFinish();
function getWalker(node) {
return SpecialPowers.createDOMWalker(node, true);
}
function getFirstChild(parent) {
return SpecialPowers.unwrap(getWalker(parent).firstChild);
}
function getLastChild(parent) {
return SpecialPowers.unwrap(getWalker(parent).lastChild);
}
function assertSamePseudoElement(which, node1, node2) {
is(SpecialPowers.wrap(node1).nodeName, "_moz_generated_content_" + which,
"Correct pseudo element type");
is(node1, node2,
"Referencing the same ::after element");
}
window.onload = function () {
testOneAdded();
};
function testOneAdded() {
let parent = document.getElementById("pseudo");
var m = new MutationObserver(function(records, observer) {
is(records.length, 1, "Correct number of records");
is(records[0].type, "nativeAnonymousChildList", "Correct record type");
is(records[0].target, parent, "Correct target");
is(records[0].addedNodes.length, 1, "Should have got addedNodes");
assertSamePseudoElement("before", records[0].addedNodes[0], getFirstChild(parent));
is(records[0].removedNodes.length, 0, "Shouldn't have got removedNodes");
observer.disconnect();
testAddedAndRemoved();
});
SpecialPowers.observeMutationEvents(m, parent, true);
parent.className = "before";
}
function testAddedAndRemoved() {
let parent = document.getElementById("pseudo");
let originalBeforeElement = getFirstChild(parent);
var m = new MutationObserver(function(records, observer) {
is(records.length, 2, "Correct number of records");
is(records[0].type, "nativeAnonymousChildList", "Correct record type (1)");
is(records[1].type, "nativeAnonymousChildList", "Correct record type (2)");
is(records[0].target, parent, "Correct target (1)");
is(records[1].target, parent, "Correct target (2)");
// Two records are sent - one for removed and one for added.
is(records[0].addedNodes.length, 0, "Shouldn't have got addedNodes");
is(records[0].removedNodes.length, 1, "Should have got removedNodes");
assertSamePseudoElement("before", records[0].removedNodes[0], originalBeforeElement);
is(records[1].addedNodes.length, 1, "Should have got addedNodes");
assertSamePseudoElement("after", records[1].addedNodes[0], getLastChild(parent));
is(records[1].removedNodes.length, 0, "Shouldn't have got removedNodes");
observer.disconnect();
testRemoved();
});
SpecialPowers.observeMutationEvents(m, parent, true);
parent.className = "after";
}
function testRemoved() {
let parent = document.getElementById("pseudo");
let originalAfterElement = getLastChild(parent);
var m = new MutationObserver(function(records, observer) {
is(records.length, 1, "Correct number of records");
is(records[0].type, "nativeAnonymousChildList", "Correct record type");
is(records[0].target, parent, "Correct target");
is(records[0].addedNodes.length, 0, "Shouldn't have got addedNodes");
is(records[0].removedNodes.length, 1, "Should have got removedNodes");
assertSamePseudoElement("after", records[0].removedNodes[0], originalAfterElement);
observer.disconnect();
testMultipleAdded();
});
SpecialPowers.observeMutationEvents(m, parent, true);
parent.className = "";
}
function testMultipleAdded() {
let parent = document.getElementById("pseudo");
var m = new MutationObserver(function(records, observer) {
is(records.length, 2, "Correct number of records");
is(records[0].type, "nativeAnonymousChildList", "Correct record type (1)");
is(records[1].type, "nativeAnonymousChildList", "Correct record type (2)");
is(records[0].target, parent, "Correct target (1)");
is(records[1].target, parent, "Correct target (2)");
is(records[0].addedNodes.length, 1, "Should have got addedNodes");
assertSamePseudoElement("before", records[0].addedNodes[0], getFirstChild(parent));
is(records[0].removedNodes.length, 0, "Shouldn't have got removedNodes");
is(records[1].addedNodes.length, 1, "Should have got addedNodes");
assertSamePseudoElement("after", records[1].addedNodes[0], getLastChild(parent));
is(records[1].removedNodes.length, 0, "Shouldn't have got removedNodes");
observer.disconnect();
testRemovedDueToDisplay();
});
SpecialPowers.observeMutationEvents(m, parent, true);
parent.className = "before after";
}
function testRemovedDueToDisplay() {
let parent = document.getElementById("pseudo");
let originalBeforeElement = getFirstChild(parent);
let originalAfterElement = getLastChild(parent);
var m = new MutationObserver(function(records, observer) {
is(records.length, 2, "Correct number of records");
is(records[0].type, "nativeAnonymousChildList", "Correct record type (1)");
is(records[1].type, "nativeAnonymousChildList", "Correct record type (2)");
is(records[0].target, parent, "Correct target (1)");
is(records[1].target, parent, "Correct target (2)");
is(records[0].addedNodes.length, 0, "Shouldn't have got addedNodes");
is(records[0].removedNodes.length, 1, "Should have got removedNodes");
assertSamePseudoElement("after", records[0].removedNodes[0], originalAfterElement);
is(records[1].addedNodes.length, 0, "Shouldn't have got addedNodes");
is(records[1].removedNodes.length, 1, "Should have got removedNodes");
assertSamePseudoElement("before", records[1].removedNodes[0], originalBeforeElement);
observer.disconnect();
testAddedDueToDisplay();
});
SpecialPowers.observeMutationEvents(m, parent, true);
parent.style.display = "none";
}
function testAddedDueToDisplay() {
let parent = document.getElementById("pseudo");
var m = new MutationObserver(function(records, observer) {
is(records.length, 2, "Correct number of records");
is(records[0].type, "nativeAnonymousChildList", "Correct record type (1)");
is(records[1].type, "nativeAnonymousChildList", "Correct record type (2)");
is(records[0].target, parent, "Correct target (1)");
is(records[1].target, parent, "Correct target (2)");
is(records[0].addedNodes.length, 1, "Should have got addedNodes");
assertSamePseudoElement("before", records[0].addedNodes[0], getFirstChild(parent));
is(records[0].removedNodes.length, 0, "Shouldn't have got removedNodes");
is(records[1].addedNodes.length, 1, "Should have got addedNodes");
assertSamePseudoElement("after", records[1].addedNodes[0], getLastChild(parent));
is(records[1].removedNodes.length, 0, "Shouldn't have got removedNodes");
observer.disconnect();
testDifferentTargetNoSubtree();
});
SpecialPowers.observeMutationEvents(m, parent, true);
parent.style.display = "block";
}
function testDifferentTargetNoSubtree() {
let parent = document.getElementById("pseudo");
var m = new MutationObserver(function(records, observer) {
ok(false,
"No mutation should fire when observing on a parent without subtree option.");
});
SpecialPowers.observeMutationEvents(m, document, true);
parent.style.display = "none";
// Wait for the actual mutation to come through, making sure that
// the original observer never fires.
var m2 = new MutationObserver(function(records, observer) {
ok(!getFirstChild(parent), "Pseudo element has been removed, but no mutation");
ok(!getLastChild(parent), "Pseudo element has been removed, but no mutation");
observer.disconnect();
testSubtree();
});
SpecialPowers.observeMutationEvents(m2, parent, true);
}
function testSubtree() {
let parent = document.getElementById("pseudo");
var m = new MutationObserver(function(records, observer) {
is(records.length, 2, "Correct number of records");
is(records[0].type, "nativeAnonymousChildList", "Correct record type (1)");
is(records[1].type, "nativeAnonymousChildList", "Correct record type (2)");
is(records[0].target, parent, "Correct target (1)");
is(records[1].target, parent, "Correct target (2)");
is(records[0].addedNodes.length, 1, "Should have got addedNodes");
assertSamePseudoElement("before", records[0].addedNodes[0], getFirstChild(parent));
is(records[0].removedNodes.length, 0, "Shouldn't have got removedNodes");
is(records[1].addedNodes.length, 1, "Should have got addedNodes");
assertSamePseudoElement("after", records[1].addedNodes[0], getLastChild(parent));
is(records[1].removedNodes.length, 0, "Shouldn't have got removedNodes");
observer.disconnect();
testDictionaryWithoutChromePriv();
});
SpecialPowers.observeMutationEvents(m, document, true, true);
parent.style.display = "block";
}
function testDictionaryWithoutChromePriv()
{
var m = new MutationObserver(function() {});
try {
m.observe(document, { childList: true, get nativeAnonymousChildList() { throw "Foo1"; } } );
ok(true, "Shouldn't throw!");
} catch(ex) {
ok(false, "Did throw " + ex);
}
try {
m.observe(document, { childList: true, get animations() { throw "Foo2"; } } );
ok(true, "Shouldn't throw!");
} catch(ex) {
ok(false, "Did throw " + ex);
}
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>

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

@ -840,10 +840,10 @@ function testAttributeRecordMerging4() {
}
function testChromeOnly() {
// Content can't access nativeAnonymousChildList
// Content can't access chromeOnlyNodes
try {
var mo = new M(function(records, observer) { });
mo.observe(div, { nativeAnonymousChildList: true });
mo.observe(div, { chromeOnlyNodes: true });
ok(false, "Should have thrown when trying to observe with chrome-only init");
} catch (e) {
ok(true, "Throws when trying to observe with chrome-only init");

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

@ -441,7 +441,7 @@ partial interface Document {
attribute boolean styleSheetChangeEventsEnabled;
[ChromeOnly]
attribute boolean shadowRootAttachedEventEnabled;
attribute boolean devToolsAnonymousAndShadowEventsEnabled;
[ChromeOnly] readonly attribute DOMString contentLanguage;

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

@ -66,8 +66,6 @@ dictionary MutationObserverInit {
boolean attributeOldValue;
boolean characterDataOldValue;
[ChromeOnly]
boolean nativeAnonymousChildList = false;
[ChromeOnly]
boolean chromeOnlyNodes = false;
[ChromeOnly]
boolean animations = false;

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

@ -2161,6 +2161,16 @@ static nsIContent* GetNativeAnonymousSubtreeRoot(nsIContent* aContent) {
void PresShell::NativeAnonymousContentRemoved(nsIContent* aAnonContent) {
MOZ_ASSERT(aAnonContent->IsRootOfNativeAnonymousSubtree());
mPresContext->EventStateManager()->NativeAnonymousContentRemoved(
aAnonContent);
#ifdef ACCESSIBILITY
if (nsAccessibilityService* accService = GetAccService()) {
accService->ContentRemoved(this, aAnonContent);
}
#endif
if (mDocument->DevToolsAnonymousAndShadowEventsEnabled()) {
aAnonContent->QueueDevtoolsAnonymousEvent(/* aIsRemove = */ true);
}
if (nsIContent* root = GetNativeAnonymousSubtreeRoot(mCurrentEventContent)) {
if (aAnonContent == root) {
mCurrentEventContent = aAnonContent->GetFlattenedTreeParent();

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

@ -1896,6 +1896,10 @@ void nsCSSFrameConstructor::CreateGeneratedContentItem(
return;
}
if (mDocument->DevToolsAnonymousAndShadowEventsEnabled()) {
container->QueueDevtoolsAnonymousEvent(/* aIsRemove = */ false);
}
// Servo has already eagerly computed the style for the container, so we can
// just stick the style on the element and avoid an additional traversal.
//
@ -3999,6 +4003,13 @@ nsresult nsCSSFrameConstructor::GetAnonymousContent(
return rv;
}
if (aContent.IsEmpty()) {
return NS_OK;
}
const bool devtoolsEventsEnabled =
mDocument->DevToolsAnonymousAndShadowEventsEnabled();
MOZ_ASSERT(aParent->IsElement());
for (const auto& info : aContent) {
// get our child's content and set its parent to our content
@ -4012,6 +4023,10 @@ nsresult nsCSSFrameConstructor::GetAnonymousContent(
content->UnbindFromTree();
return rv;
}
if (devtoolsEventsEnabled) {
content->QueueDevtoolsAnonymousEvent(/* aIsRemove = */ false);
}
}
// Some situations where we don't cache anonymous content styles:

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

@ -221,7 +221,6 @@ static void SetOrUpdateRectValuedProperty(
void nsIFrame::DestroyAnonymousContent(
nsPresContext* aPresContext, already_AddRefed<nsIContent>&& aContent) {
if (nsCOMPtr<nsIContent> content = aContent) {
aPresContext->EventStateManager()->NativeAnonymousContentRemoved(content);
aPresContext->PresShell()->NativeAnonymousContentRemoved(content);
content->UnbindFromTree();
}

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

@ -2144,13 +2144,6 @@ export class SpecialPowersChild extends JSWindowActorChild {
};
}
observeMutationEvents(mo, node, nativeAnonymousChildList, subtree) {
lazy.WrapPrivileged.unwrap(mo).observe(lazy.WrapPrivileged.unwrap(node), {
nativeAnonymousChildList,
subtree,
});
}
/**
* Which commands are available can be determined by checking which commands
* are registered. See \ref

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

@ -195,9 +195,6 @@ void nsFormFillController::AttributeWillChange(mozilla::dom::Element* aElement,
nsAtom* aAttribute,
int32_t aModType) {}
void nsFormFillController::NativeAnonymousChildListChange(nsIContent* aContent,
bool aIsRemove) {}
void nsFormFillController::ParentChainChanged(nsIContent* aContent) {}
void nsFormFillController::ARIAAttributeDefaultWillChange(

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

@ -58,8 +58,6 @@ void nsMenuGroupOwnerX::NodeWillBeDestroyed(nsINode* aNode) {}
void nsMenuGroupOwnerX::AttributeWillChange(dom::Element* aElement, int32_t aNameSpaceID,
nsAtom* aAttribute, int32_t aModType) {}
void nsMenuGroupOwnerX::NativeAnonymousChildListChange(nsIContent* aContent, bool aIsRemove) {}
void nsMenuGroupOwnerX::AttributeChanged(dom::Element* aElement, int32_t aNameSpaceID,
nsAtom* aAttribute, int32_t aModType,
const nsAttrValue* aOldValue) {

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

@ -707,7 +707,6 @@ STATIC_ATOMS = [
Atom("namespaceUri", "namespace-uri"),
Atom("NaN", "NaN"),
Atom("n", "n"),
Atom("nativeAnonymousChildList", "nativeAnonymousChildList"),
Atom("nav", "nav"),
Atom("ne", "ne"),
Atom("never", "never"),