forked from mirrors/gecko-dev
Bug 1827856 - Allow chrome code to properly observe UA widgets / NAC. r=smaug,devtools-reviewers,nchevobbe
Differential Revision: https://phabricator.services.mozilla.com/D175356
This commit is contained in:
parent
1d0d56d427
commit
b8c9b55367
6 changed files with 108 additions and 30 deletions
|
|
@ -271,6 +271,7 @@ class NodeActor extends Actor {
|
||||||
characterDataOldValue: true,
|
characterDataOldValue: true,
|
||||||
childList: true,
|
childList: true,
|
||||||
subtree: true,
|
subtree: true,
|
||||||
|
chromeOnlyNodes: true,
|
||||||
});
|
});
|
||||||
this.mutationObserver = observer;
|
this.mutationObserver = observer;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,8 +69,7 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMMutationRecord, mTarget,
|
||||||
// Observer
|
// Observer
|
||||||
|
|
||||||
bool nsMutationReceiverBase::IsObservable(nsIContent* aContent) {
|
bool nsMutationReceiverBase::IsObservable(nsIContent* aContent) {
|
||||||
return !aContent->ChromeOnlyAccess() &&
|
return !aContent->ChromeOnlyAccess() || ChromeOnlyNodes();
|
||||||
(Observer()->IsChrome() || !aContent->IsInNativeAnonymousSubtree());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nsMutationReceiverBase::ObservesAttr(nsINode* aRegisterTarget,
|
bool nsMutationReceiverBase::ObservesAttr(nsINode* aRegisterTarget,
|
||||||
|
|
@ -629,7 +628,7 @@ void nsDOMMutationObserver::RescheduleForRun() {
|
||||||
void nsDOMMutationObserver::Observe(nsINode& aTarget,
|
void nsDOMMutationObserver::Observe(nsINode& aTarget,
|
||||||
const MutationObserverInit& aOptions,
|
const MutationObserverInit& aOptions,
|
||||||
nsIPrincipal& aSubjectPrincipal,
|
nsIPrincipal& aSubjectPrincipal,
|
||||||
mozilla::ErrorResult& aRv) {
|
ErrorResult& aRv) {
|
||||||
bool childList = aOptions.mChildList;
|
bool childList = aOptions.mChildList;
|
||||||
bool attributes =
|
bool attributes =
|
||||||
aOptions.mAttributes.WasPassed() && aOptions.mAttributes.Value();
|
aOptions.mAttributes.WasPassed() && aOptions.mAttributes.Value();
|
||||||
|
|
@ -642,6 +641,7 @@ void nsDOMMutationObserver::Observe(nsINode& aTarget,
|
||||||
bool characterDataOldValue = aOptions.mCharacterDataOldValue.WasPassed() &&
|
bool characterDataOldValue = aOptions.mCharacterDataOldValue.WasPassed() &&
|
||||||
aOptions.mCharacterDataOldValue.Value();
|
aOptions.mCharacterDataOldValue.Value();
|
||||||
bool animations = aOptions.mAnimations;
|
bool animations = aOptions.mAnimations;
|
||||||
|
bool chromeOnlyNodes = aOptions.mChromeOnlyNodes;
|
||||||
|
|
||||||
if (!aOptions.mAttributes.WasPassed() &&
|
if (!aOptions.mAttributes.WasPassed() &&
|
||||||
(aOptions.mAttributeOldValue.WasPassed() ||
|
(aOptions.mAttributeOldValue.WasPassed() ||
|
||||||
|
|
@ -707,6 +707,7 @@ void nsDOMMutationObserver::Observe(nsINode& aTarget,
|
||||||
r->SetAttributeFilter(std::move(filters));
|
r->SetAttributeFilter(std::move(filters));
|
||||||
r->SetAllAttributes(allAttrs);
|
r->SetAllAttributes(allAttrs);
|
||||||
r->SetAnimations(animations);
|
r->SetAnimations(animations);
|
||||||
|
r->SetChromeOnlyNodes(chromeOnlyNodes);
|
||||||
r->RemoveClones();
|
r->RemoveClones();
|
||||||
|
|
||||||
if (!aSubjectPrincipal.IsSystemPrincipal() &&
|
if (!aSubjectPrincipal.IsSystemPrincipal() &&
|
||||||
|
|
@ -793,10 +794,7 @@ already_AddRefed<nsDOMMutationObserver> nsDOMMutationObserver::Constructor(
|
||||||
aRv.Throw(NS_ERROR_FAILURE);
|
aRv.Throw(NS_ERROR_FAILURE);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
bool isChrome = nsContentUtils::IsChromeDoc(window->GetExtantDoc());
|
return MakeAndAddRef<nsDOMMutationObserver>(std::move(window), aCb);
|
||||||
RefPtr<nsDOMMutationObserver> observer =
|
|
||||||
new nsDOMMutationObserver(std::move(window), aCb, isChrome);
|
|
||||||
return observer.forget();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nsDOMMutationObserver::MergeableAttributeRecord(
|
bool nsDOMMutationObserver::MergeableAttributeRecord(
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ class nsMutationReceiverBase : public nsStubAnimationObserver {
|
||||||
mCharacterData = aCharacterData;
|
mCharacterData = aCharacterData;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CharacterDataOldValue() {
|
bool CharacterDataOldValue() const {
|
||||||
return mParent ? mParent->CharacterDataOldValue() : mCharacterDataOldValue;
|
return mParent ? mParent->CharacterDataOldValue() : mCharacterDataOldValue;
|
||||||
}
|
}
|
||||||
void SetCharacterDataOldValue(bool aOldValue) {
|
void SetCharacterDataOldValue(bool aOldValue) {
|
||||||
|
|
@ -153,7 +153,7 @@ class nsMutationReceiverBase : public nsStubAnimationObserver {
|
||||||
mCharacterDataOldValue = aOldValue;
|
mCharacterDataOldValue = aOldValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NativeAnonymousChildList() {
|
bool NativeAnonymousChildList() const {
|
||||||
return mParent ? mParent->NativeAnonymousChildList()
|
return mParent ? mParent->NativeAnonymousChildList()
|
||||||
: mNativeAnonymousChildList;
|
: mNativeAnonymousChildList;
|
||||||
}
|
}
|
||||||
|
|
@ -162,13 +162,15 @@ class nsMutationReceiverBase : public nsStubAnimationObserver {
|
||||||
mNativeAnonymousChildList = aOldValue;
|
mNativeAnonymousChildList = aOldValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Attributes() { return mParent ? mParent->Attributes() : mAttributes; }
|
bool Attributes() const {
|
||||||
|
return mParent ? mParent->Attributes() : mAttributes;
|
||||||
|
}
|
||||||
void SetAttributes(bool aAttributes) {
|
void SetAttributes(bool aAttributes) {
|
||||||
NS_ASSERTION(!mParent, "Shouldn't have parent");
|
NS_ASSERTION(!mParent, "Shouldn't have parent");
|
||||||
mAttributes = aAttributes;
|
mAttributes = aAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AllAttributes() {
|
bool AllAttributes() const {
|
||||||
return mParent ? mParent->AllAttributes() : mAllAttributes;
|
return mParent ? mParent->AllAttributes() : mAllAttributes;
|
||||||
}
|
}
|
||||||
void SetAllAttributes(bool aAll) {
|
void SetAllAttributes(bool aAll) {
|
||||||
|
|
@ -176,13 +178,15 @@ class nsMutationReceiverBase : public nsStubAnimationObserver {
|
||||||
mAllAttributes = aAll;
|
mAllAttributes = aAll;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Animations() { return mParent ? mParent->Animations() : mAnimations; }
|
bool Animations() const {
|
||||||
|
return mParent ? mParent->Animations() : mAnimations;
|
||||||
|
}
|
||||||
void SetAnimations(bool aAnimations) {
|
void SetAnimations(bool aAnimations) {
|
||||||
NS_ASSERTION(!mParent, "Shouldn't have parent");
|
NS_ASSERTION(!mParent, "Shouldn't have parent");
|
||||||
mAnimations = aAnimations;
|
mAnimations = aAnimations;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AttributeOldValue() {
|
bool AttributeOldValue() const {
|
||||||
return mParent ? mParent->AttributeOldValue() : mAttributeOldValue;
|
return mParent ? mParent->AttributeOldValue() : mAttributeOldValue;
|
||||||
}
|
}
|
||||||
void SetAttributeOldValue(bool aOldValue) {
|
void SetAttributeOldValue(bool aOldValue) {
|
||||||
|
|
@ -190,6 +194,15 @@ class nsMutationReceiverBase : public nsStubAnimationObserver {
|
||||||
mAttributeOldValue = aOldValue;
|
mAttributeOldValue = aOldValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ChromeOnlyNodes() const {
|
||||||
|
return mParent ? mParent->ChromeOnlyNodes() : mChromeOnlyNodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetChromeOnlyNodes(bool aChromeOnlyNodes) {
|
||||||
|
NS_ASSERTION(!mParent, "Shouldn't have parent");
|
||||||
|
mChromeOnlyNodes = aChromeOnlyNodes;
|
||||||
|
}
|
||||||
|
|
||||||
nsTArray<RefPtr<nsAtom>>& AttributeFilter() { return mAttributeFilter; }
|
nsTArray<RefPtr<nsAtom>>& AttributeFilter() { return mAttributeFilter; }
|
||||||
void SetAttributeFilter(nsTArray<RefPtr<nsAtom>>&& aFilter) {
|
void SetAttributeFilter(nsTArray<RefPtr<nsAtom>>&& aFilter) {
|
||||||
NS_ASSERTION(!mParent, "Shouldn't have parent");
|
NS_ASSERTION(!mParent, "Shouldn't have parent");
|
||||||
|
|
@ -235,7 +248,8 @@ class nsMutationReceiverBase : public nsStubAnimationObserver {
|
||||||
mAttributes(false),
|
mAttributes(false),
|
||||||
mAllAttributes(false),
|
mAllAttributes(false),
|
||||||
mAttributeOldValue(false),
|
mAttributeOldValue(false),
|
||||||
mAnimations(false) {
|
mAnimations(false),
|
||||||
|
mChromeOnlyNodes(false) {
|
||||||
NS_ASSERTION(mParent->Subtree(), "Should clone a non-subtree observer!");
|
NS_ASSERTION(mParent->Subtree(), "Should clone a non-subtree observer!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -265,16 +279,17 @@ class nsMutationReceiverBase : public nsStubAnimationObserver {
|
||||||
nsCOMPtr<nsINode> mKungFuDeathGrip;
|
nsCOMPtr<nsINode> mKungFuDeathGrip;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool mSubtree;
|
|
||||||
bool mChildList;
|
|
||||||
bool mCharacterData;
|
|
||||||
bool mCharacterDataOldValue;
|
|
||||||
bool mNativeAnonymousChildList;
|
|
||||||
bool mAttributes;
|
|
||||||
bool mAllAttributes;
|
|
||||||
bool mAttributeOldValue;
|
|
||||||
bool mAnimations;
|
|
||||||
nsTArray<RefPtr<nsAtom>> mAttributeFilter;
|
nsTArray<RefPtr<nsAtom>> mAttributeFilter;
|
||||||
|
bool mSubtree : 1;
|
||||||
|
bool mChildList : 1;
|
||||||
|
bool mCharacterData : 1;
|
||||||
|
bool mCharacterDataOldValue : 1;
|
||||||
|
bool mNativeAnonymousChildList : 1;
|
||||||
|
bool mAttributes : 1;
|
||||||
|
bool mAllAttributes : 1;
|
||||||
|
bool mAttributeOldValue : 1;
|
||||||
|
bool mAnimations : 1;
|
||||||
|
bool mChromeOnlyNodes : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
class nsMutationReceiver : public nsMutationReceiverBase {
|
class nsMutationReceiver : public nsMutationReceiverBase {
|
||||||
|
|
@ -412,13 +427,12 @@ class nsAnimationReceiver : public nsMutationReceiver {
|
||||||
class nsDOMMutationObserver final : public nsISupports, public nsWrapperCache {
|
class nsDOMMutationObserver final : public nsISupports, public nsWrapperCache {
|
||||||
public:
|
public:
|
||||||
nsDOMMutationObserver(nsCOMPtr<nsPIDOMWindowInner>&& aOwner,
|
nsDOMMutationObserver(nsCOMPtr<nsPIDOMWindowInner>&& aOwner,
|
||||||
mozilla::dom::MutationCallback& aCb, bool aChrome)
|
mozilla::dom::MutationCallback& aCb)
|
||||||
: mOwner(std::move(aOwner)),
|
: mOwner(std::move(aOwner)),
|
||||||
mLastPendingMutation(nullptr),
|
mLastPendingMutation(nullptr),
|
||||||
mPendingMutationCount(0),
|
mPendingMutationCount(0),
|
||||||
mCallback(&aCb),
|
mCallback(&aCb),
|
||||||
mWaitingForRun(false),
|
mWaitingForRun(false),
|
||||||
mIsChrome(aChrome),
|
|
||||||
mMergeAttributeRecords(false),
|
mMergeAttributeRecords(false),
|
||||||
mId(++sCount) {}
|
mId(++sCount) {}
|
||||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
|
|
@ -426,8 +440,8 @@ class nsDOMMutationObserver final : public nsISupports, public nsWrapperCache {
|
||||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOM_MUTATION_OBSERVER_IID)
|
NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOM_MUTATION_OBSERVER_IID)
|
||||||
|
|
||||||
static already_AddRefed<nsDOMMutationObserver> Constructor(
|
static already_AddRefed<nsDOMMutationObserver> Constructor(
|
||||||
const mozilla::dom::GlobalObject& aGlobal,
|
const mozilla::dom::GlobalObject&, mozilla::dom::MutationCallback&,
|
||||||
mozilla::dom::MutationCallback& aCb, mozilla::ErrorResult& aRv);
|
mozilla::ErrorResult&);
|
||||||
|
|
||||||
JSObject* WrapObject(JSContext* aCx,
|
JSObject* WrapObject(JSContext* aCx,
|
||||||
JS::Handle<JSObject*> aGivenProto) override {
|
JS::Handle<JSObject*> aGivenProto) override {
|
||||||
|
|
@ -436,8 +450,6 @@ class nsDOMMutationObserver final : public nsISupports, public nsWrapperCache {
|
||||||
|
|
||||||
nsISupports* GetParentObject() const { return mOwner; }
|
nsISupports* GetParentObject() const { return mOwner; }
|
||||||
|
|
||||||
bool IsChrome() const { return mIsChrome; }
|
|
||||||
|
|
||||||
void Observe(nsINode& aTarget,
|
void Observe(nsINode& aTarget,
|
||||||
const mozilla::dom::MutationObserverInit& aOptions,
|
const mozilla::dom::MutationObserverInit& aOptions,
|
||||||
nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aRv);
|
nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aRv);
|
||||||
|
|
@ -561,7 +573,6 @@ class nsDOMMutationObserver final : public nsISupports, public nsWrapperCache {
|
||||||
RefPtr<mozilla::dom::MutationCallback> mCallback;
|
RefPtr<mozilla::dom::MutationCallback> mCallback;
|
||||||
|
|
||||||
bool mWaitingForRun;
|
bool mWaitingForRun;
|
||||||
const bool mIsChrome;
|
|
||||||
bool mMergeAttributeRecords;
|
bool mMergeAttributeRecords;
|
||||||
|
|
||||||
uint64_t mId;
|
uint64_t mId;
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,8 @@ dictionary MutationObserverInit {
|
||||||
[ChromeOnly]
|
[ChromeOnly]
|
||||||
boolean nativeAnonymousChildList = false;
|
boolean nativeAnonymousChildList = false;
|
||||||
[ChromeOnly]
|
[ChromeOnly]
|
||||||
|
boolean chromeOnlyNodes = false;
|
||||||
|
[ChromeOnly]
|
||||||
boolean animations = false;
|
boolean animations = false;
|
||||||
sequence<DOMString> attributeFilter;
|
sequence<DOMString> attributeFilter;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ support-files =
|
||||||
[test_audiocontrols_dimensions.html]
|
[test_audiocontrols_dimensions.html]
|
||||||
[test_audiocontrols_fullscreen.html]
|
[test_audiocontrols_fullscreen.html]
|
||||||
[test_mousecapture_area.html]
|
[test_mousecapture_area.html]
|
||||||
|
[test_nac_mutations.html]
|
||||||
[test_panel_list_shadow_node_anchor.html]
|
[test_panel_list_shadow_node_anchor.html]
|
||||||
support-files =
|
support-files =
|
||||||
../../widgets/panel-item.css
|
../../widgets/panel-item.css
|
||||||
|
|
|
||||||
65
toolkit/content/tests/widgets/test_nac_mutations.html
Normal file
65
toolkit/content/tests/widgets/test_nac_mutations.html
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<title>UA Widget mutation observer test</title>
|
||||||
|
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
||||||
|
<link rel="stylesheet" href="/tests/SimpleTest/test.css" />
|
||||||
|
<video controls id="video"></video>
|
||||||
|
<div style="overflow: scroll; width: 100px; height: 100px" id="scroller"></div>
|
||||||
|
<script>
|
||||||
|
const video = document.getElementById("video");
|
||||||
|
const scroller = document.getElementById("scroller");
|
||||||
|
|
||||||
|
async function test_mutations_internal(observedNode, elementToMutate, expectMutations) {
|
||||||
|
let resolveMutations;
|
||||||
|
let mutations = new Promise(r => {
|
||||||
|
resolveMutations = r;
|
||||||
|
});
|
||||||
|
|
||||||
|
let observer = new MutationObserver(function(m) {
|
||||||
|
ok(expectMutations, "Mutations should be expected");
|
||||||
|
resolveMutations(m)
|
||||||
|
});
|
||||||
|
|
||||||
|
SpecialPowers.wrap(observer).observe(observedNode, {
|
||||||
|
subtree: true,
|
||||||
|
attributes: true,
|
||||||
|
chromeOnlyNodes: expectMutations,
|
||||||
|
});
|
||||||
|
|
||||||
|
elementToMutate.setAttribute("unlikely", `value-${expectMutations}`);
|
||||||
|
|
||||||
|
if (expectMutations) {
|
||||||
|
await mutations;
|
||||||
|
} else {
|
||||||
|
await new Promise(r => SimpleTest.executeSoon(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
observer.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function test_mutations(observedNode, elementToMutate) {
|
||||||
|
for (let chromeOnlyNodes of [true, false]) {
|
||||||
|
info(`Testing chromeOnlyNodes: ${chromeOnlyNodes}`);
|
||||||
|
await test_mutations_internal(observedNode, elementToMutate, chromeOnlyNodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add_task(async function test_ua_mutations() {
|
||||||
|
let shadow = SpecialPowers.wrap(video).openOrClosedShadowRoot;
|
||||||
|
ok(!!shadow, "UA Widget ShadowRoot exists");
|
||||||
|
|
||||||
|
await test_mutations(shadow, shadow.querySelector("*"));
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function test_scrollbar_mutations_same_anon_tree() {
|
||||||
|
let scrollbar = SpecialPowers.wrap(window).InspectorUtils.getChildrenForNode(scroller, true, false)[0];
|
||||||
|
is(scrollbar.tagName, "scrollbar", "should find a scrollbar");
|
||||||
|
await test_mutations(scrollbar, scrollbar);
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function test_scrollbar_mutations_same_tree() {
|
||||||
|
let scrollbar = SpecialPowers.wrap(window).InspectorUtils.getChildrenForNode(scroller, true, false)[0];
|
||||||
|
is(scrollbar.tagName, "scrollbar", "should find a scrollbar");
|
||||||
|
await test_mutations(scroller, scrollbar);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
Loading…
Reference in a new issue