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,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
chromeOnlyNodes: true,
|
||||
});
|
||||
this.mutationObserver = observer;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,8 +69,7 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMMutationRecord, mTarget,
|
|||
// Observer
|
||||
|
||||
bool nsMutationReceiverBase::IsObservable(nsIContent* aContent) {
|
||||
return !aContent->ChromeOnlyAccess() &&
|
||||
(Observer()->IsChrome() || !aContent->IsInNativeAnonymousSubtree());
|
||||
return !aContent->ChromeOnlyAccess() || ChromeOnlyNodes();
|
||||
}
|
||||
|
||||
bool nsMutationReceiverBase::ObservesAttr(nsINode* aRegisterTarget,
|
||||
|
|
@ -629,7 +628,7 @@ void nsDOMMutationObserver::RescheduleForRun() {
|
|||
void nsDOMMutationObserver::Observe(nsINode& aTarget,
|
||||
const MutationObserverInit& aOptions,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
mozilla::ErrorResult& aRv) {
|
||||
ErrorResult& aRv) {
|
||||
bool childList = aOptions.mChildList;
|
||||
bool attributes =
|
||||
aOptions.mAttributes.WasPassed() && aOptions.mAttributes.Value();
|
||||
|
|
@ -642,6 +641,7 @@ void nsDOMMutationObserver::Observe(nsINode& aTarget,
|
|||
bool characterDataOldValue = aOptions.mCharacterDataOldValue.WasPassed() &&
|
||||
aOptions.mCharacterDataOldValue.Value();
|
||||
bool animations = aOptions.mAnimations;
|
||||
bool chromeOnlyNodes = aOptions.mChromeOnlyNodes;
|
||||
|
||||
if (!aOptions.mAttributes.WasPassed() &&
|
||||
(aOptions.mAttributeOldValue.WasPassed() ||
|
||||
|
|
@ -707,6 +707,7 @@ void nsDOMMutationObserver::Observe(nsINode& aTarget,
|
|||
r->SetAttributeFilter(std::move(filters));
|
||||
r->SetAllAttributes(allAttrs);
|
||||
r->SetAnimations(animations);
|
||||
r->SetChromeOnlyNodes(chromeOnlyNodes);
|
||||
r->RemoveClones();
|
||||
|
||||
if (!aSubjectPrincipal.IsSystemPrincipal() &&
|
||||
|
|
@ -793,10 +794,7 @@ already_AddRefed<nsDOMMutationObserver> nsDOMMutationObserver::Constructor(
|
|||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
bool isChrome = nsContentUtils::IsChromeDoc(window->GetExtantDoc());
|
||||
RefPtr<nsDOMMutationObserver> observer =
|
||||
new nsDOMMutationObserver(std::move(window), aCb, isChrome);
|
||||
return observer.forget();
|
||||
return MakeAndAddRef<nsDOMMutationObserver>(std::move(window), aCb);
|
||||
}
|
||||
|
||||
bool nsDOMMutationObserver::MergeableAttributeRecord(
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ class nsMutationReceiverBase : public nsStubAnimationObserver {
|
|||
mCharacterData = aCharacterData;
|
||||
}
|
||||
|
||||
bool CharacterDataOldValue() {
|
||||
bool CharacterDataOldValue() const {
|
||||
return mParent ? mParent->CharacterDataOldValue() : mCharacterDataOldValue;
|
||||
}
|
||||
void SetCharacterDataOldValue(bool aOldValue) {
|
||||
|
|
@ -153,7 +153,7 @@ class nsMutationReceiverBase : public nsStubAnimationObserver {
|
|||
mCharacterDataOldValue = aOldValue;
|
||||
}
|
||||
|
||||
bool NativeAnonymousChildList() {
|
||||
bool NativeAnonymousChildList() const {
|
||||
return mParent ? mParent->NativeAnonymousChildList()
|
||||
: mNativeAnonymousChildList;
|
||||
}
|
||||
|
|
@ -162,13 +162,15 @@ class nsMutationReceiverBase : public nsStubAnimationObserver {
|
|||
mNativeAnonymousChildList = aOldValue;
|
||||
}
|
||||
|
||||
bool Attributes() { return mParent ? mParent->Attributes() : mAttributes; }
|
||||
bool Attributes() const {
|
||||
return mParent ? mParent->Attributes() : mAttributes;
|
||||
}
|
||||
void SetAttributes(bool aAttributes) {
|
||||
NS_ASSERTION(!mParent, "Shouldn't have parent");
|
||||
mAttributes = aAttributes;
|
||||
}
|
||||
|
||||
bool AllAttributes() {
|
||||
bool AllAttributes() const {
|
||||
return mParent ? mParent->AllAttributes() : mAllAttributes;
|
||||
}
|
||||
void SetAllAttributes(bool aAll) {
|
||||
|
|
@ -176,13 +178,15 @@ class nsMutationReceiverBase : public nsStubAnimationObserver {
|
|||
mAllAttributes = aAll;
|
||||
}
|
||||
|
||||
bool Animations() { return mParent ? mParent->Animations() : mAnimations; }
|
||||
bool Animations() const {
|
||||
return mParent ? mParent->Animations() : mAnimations;
|
||||
}
|
||||
void SetAnimations(bool aAnimations) {
|
||||
NS_ASSERTION(!mParent, "Shouldn't have parent");
|
||||
mAnimations = aAnimations;
|
||||
}
|
||||
|
||||
bool AttributeOldValue() {
|
||||
bool AttributeOldValue() const {
|
||||
return mParent ? mParent->AttributeOldValue() : mAttributeOldValue;
|
||||
}
|
||||
void SetAttributeOldValue(bool aOldValue) {
|
||||
|
|
@ -190,6 +194,15 @@ class nsMutationReceiverBase : public nsStubAnimationObserver {
|
|||
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; }
|
||||
void SetAttributeFilter(nsTArray<RefPtr<nsAtom>>&& aFilter) {
|
||||
NS_ASSERTION(!mParent, "Shouldn't have parent");
|
||||
|
|
@ -235,7 +248,8 @@ class nsMutationReceiverBase : public nsStubAnimationObserver {
|
|||
mAttributes(false),
|
||||
mAllAttributes(false),
|
||||
mAttributeOldValue(false),
|
||||
mAnimations(false) {
|
||||
mAnimations(false),
|
||||
mChromeOnlyNodes(false) {
|
||||
NS_ASSERTION(mParent->Subtree(), "Should clone a non-subtree observer!");
|
||||
}
|
||||
|
||||
|
|
@ -265,16 +279,17 @@ class nsMutationReceiverBase : public nsStubAnimationObserver {
|
|||
nsCOMPtr<nsINode> mKungFuDeathGrip;
|
||||
|
||||
private:
|
||||
bool mSubtree;
|
||||
bool mChildList;
|
||||
bool mCharacterData;
|
||||
bool mCharacterDataOldValue;
|
||||
bool mNativeAnonymousChildList;
|
||||
bool mAttributes;
|
||||
bool mAllAttributes;
|
||||
bool mAttributeOldValue;
|
||||
bool mAnimations;
|
||||
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 {
|
||||
|
|
@ -412,13 +427,12 @@ class nsAnimationReceiver : public nsMutationReceiver {
|
|||
class nsDOMMutationObserver final : public nsISupports, public nsWrapperCache {
|
||||
public:
|
||||
nsDOMMutationObserver(nsCOMPtr<nsPIDOMWindowInner>&& aOwner,
|
||||
mozilla::dom::MutationCallback& aCb, bool aChrome)
|
||||
mozilla::dom::MutationCallback& aCb)
|
||||
: mOwner(std::move(aOwner)),
|
||||
mLastPendingMutation(nullptr),
|
||||
mPendingMutationCount(0),
|
||||
mCallback(&aCb),
|
||||
mWaitingForRun(false),
|
||||
mIsChrome(aChrome),
|
||||
mMergeAttributeRecords(false),
|
||||
mId(++sCount) {}
|
||||
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)
|
||||
|
||||
static already_AddRefed<nsDOMMutationObserver> Constructor(
|
||||
const mozilla::dom::GlobalObject& aGlobal,
|
||||
mozilla::dom::MutationCallback& aCb, mozilla::ErrorResult& aRv);
|
||||
const mozilla::dom::GlobalObject&, mozilla::dom::MutationCallback&,
|
||||
mozilla::ErrorResult&);
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override {
|
||||
|
|
@ -436,8 +450,6 @@ class nsDOMMutationObserver final : public nsISupports, public nsWrapperCache {
|
|||
|
||||
nsISupports* GetParentObject() const { return mOwner; }
|
||||
|
||||
bool IsChrome() const { return mIsChrome; }
|
||||
|
||||
void Observe(nsINode& aTarget,
|
||||
const mozilla::dom::MutationObserverInit& aOptions,
|
||||
nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aRv);
|
||||
|
|
@ -561,7 +573,6 @@ class nsDOMMutationObserver final : public nsISupports, public nsWrapperCache {
|
|||
RefPtr<mozilla::dom::MutationCallback> mCallback;
|
||||
|
||||
bool mWaitingForRun;
|
||||
const bool mIsChrome;
|
||||
bool mMergeAttributeRecords;
|
||||
|
||||
uint64_t mId;
|
||||
|
|
|
|||
|
|
@ -68,6 +68,8 @@ dictionary MutationObserverInit {
|
|||
[ChromeOnly]
|
||||
boolean nativeAnonymousChildList = false;
|
||||
[ChromeOnly]
|
||||
boolean chromeOnlyNodes = false;
|
||||
[ChromeOnly]
|
||||
boolean animations = false;
|
||||
sequence<DOMString> attributeFilter;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ support-files =
|
|||
[test_audiocontrols_dimensions.html]
|
||||
[test_audiocontrols_fullscreen.html]
|
||||
[test_mousecapture_area.html]
|
||||
[test_nac_mutations.html]
|
||||
[test_panel_list_shadow_node_anchor.html]
|
||||
support-files =
|
||||
../../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