void nsMutationReceiver::ContentInserted(nsIDocument* aDocument, nsIContent* aContainer, nsIContent* aChild, int32_t aIndexInContainer) { nsINode* parent = NODE_FROM(aContainer, aDocument); bool wantsChildList = ChildList() && (Subtree() || parent == Target()); if (!wantsChildList || aChild->ChromeOnlyAccess()) { return; } if (nsAutoMutationBatch::IsBatching()) { if (parent == nsAutoMutationBatch::GetBatchTarget()) { nsAutoMutationBatch::UpdateObserver(Observer(), wantsChildList); } return; } nsDOMMutationRecord* m = Observer()->CurrentRecord(NS_LITERAL_STRING("childList")); if (m->mTarget) { // Already handled case. return; } m->mTarget = parent; m->mAddedNodes = new nsSimpleContentList(parent); m->mAddedNodes->AppendElement(aChild); m->mPreviousSibling = aChild->GetPreviousSibling(); m->mNextSibling = aChild->GetNextSibling(); }
void nsMutationReceiver::ContentAppended(nsIDocument* aDocument, nsIContent* aContainer, nsIContent* aFirstNewContent, int32_t aNewIndexInContainer) { nsINode* parent = NODE_FROM(aContainer, aDocument); bool wantsChildList = ChildList() && ((Subtree() && RegisterTarget()->SubtreeRoot() == parent->SubtreeRoot()) || parent == Target()); if (!wantsChildList || !IsObservable(aFirstNewContent)) { return; } if (nsAutoMutationBatch::IsBatching()) { if (parent == nsAutoMutationBatch::GetBatchTarget()) { nsAutoMutationBatch::UpdateObserver(Observer(), wantsChildList); } return; } nsDOMMutationRecord* m = Observer()->CurrentRecord(nsGkAtoms::childList); NS_ASSERTION(!m->mTarget || m->mTarget == parent, "Wrong target!"); if (m->mTarget) { // Already handled case. return; } m->mTarget = parent; m->mAddedNodes = new nsSimpleContentList(parent); nsINode* n = aFirstNewContent; while (n) { m->mAddedNodes->AppendElement(static_cast<nsIContent*>(n)); n = n->GetNextSibling(); } m->mPreviousSibling = aFirstNewContent->GetPreviousSibling(); }
void nsMutationReceiver::ContentRemoved(nsIDocument* aDocument, nsIContent* aContainer, nsIContent* aChild, int32_t aIndexInContainer, nsIContent* aPreviousSibling) { if (aChild->ChromeOnlyAccess()) { return; } nsINode* parent = NODE_FROM(aContainer, aDocument); if (nsAutoMutationBatch::IsBatching()) { if (nsAutoMutationBatch::IsRemovalDone()) { // This can happen for example if HTML parser parses to // context node, but needs to move elements around. return; } if (nsAutoMutationBatch::GetBatchTarget() != parent) { return; } bool wantsChildList = ChildList() && (Subtree() || parent == Target()); if (wantsChildList || Subtree()) { nsAutoMutationBatch::NodeRemoved(aChild); nsAutoMutationBatch::UpdateObserver(Observer(), wantsChildList); } return; } if (Subtree()) { // Try to avoid creating transient observer if the node // already has an observer observing the same set of nodes. nsMutationReceiver* orig = GetParent() ? GetParent() : this; if (Observer()->GetReceiverFor(aChild, false) != orig) { bool transientExists = false; nsCOMArray<nsMutationReceiver>* transientReceivers = nullptr; Observer()->mTransientReceivers.Get(aChild, &transientReceivers); if (!transientReceivers) { transientReceivers = new nsCOMArray<nsMutationReceiver>(); Observer()->mTransientReceivers.Put(aChild, transientReceivers); } else { for (int32_t i = 0; i < transientReceivers->Count(); ++i) { nsMutationReceiver* r = transientReceivers->ObjectAt(i); if (r->GetParent() == orig) { transientExists = true; } } } if (!transientExists) { // Make sure the elements which are removed from the // subtree are kept in the same observation set. transientReceivers->AppendObject(new nsMutationReceiver(aChild, orig)); } } } if (ChildList() && (Subtree() || parent == Target())) { nsDOMMutationRecord* m = Observer()->CurrentRecord(NS_LITERAL_STRING("childList")); if (m->mTarget) { // Already handled case. return; } m->mTarget = parent; m->mRemovedNodes = new nsSimpleContentList(parent); m->mRemovedNodes->AppendElement(aChild); m->mPreviousSibling = aPreviousSibling; m->mNextSibling = parent->GetChildAt(aIndexInContainer); } // We need to schedule always, so that after microtask mTransientReceivers // can be cleared correctly. Observer()->ScheduleForRun(); }