LCOV - code coverage report
Current view: top level - dom/base - nsDOMMutationObserver.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 98 625 15.7 %
Date: 2017-07-14 16:53:18 Functions: 14 64 21.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       5             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsDOMMutationObserver.h"
       8             : 
       9             : #include "mozilla/AnimationTarget.h"
      10             : #include "mozilla/Maybe.h"
      11             : #include "mozilla/OwningNonNull.h"
      12             : 
      13             : #include "mozilla/dom/Animation.h"
      14             : #include "mozilla/dom/KeyframeEffectReadOnly.h"
      15             : 
      16             : #include "nsContentUtils.h"
      17             : #include "nsCSSPseudoElements.h"
      18             : #include "nsError.h"
      19             : #include "nsIDOMMutationEvent.h"
      20             : #include "nsIScriptGlobalObject.h"
      21             : #include "nsServiceManagerUtils.h"
      22             : #include "nsTextFragment.h"
      23             : #include "nsThreadUtils.h"
      24             : 
      25             : using mozilla::Maybe;
      26             : using mozilla::Move;
      27             : using mozilla::NonOwningAnimationTarget;
      28             : using mozilla::dom::TreeOrderComparator;
      29             : using mozilla::dom::Animation;
      30             : using mozilla::dom::Element;
      31             : 
      32             : AutoTArray<RefPtr<nsDOMMutationObserver>, 4>*
      33             :   nsDOMMutationObserver::sScheduledMutationObservers = nullptr;
      34             : 
      35             : nsDOMMutationObserver* nsDOMMutationObserver::sCurrentObserver = nullptr;
      36             : 
      37             : uint32_t nsDOMMutationObserver::sMutationLevel = 0;
      38             : uint64_t nsDOMMutationObserver::sCount = 0;
      39             : 
      40             : AutoTArray<AutoTArray<RefPtr<nsDOMMutationObserver>, 4>, 4>*
      41             : nsDOMMutationObserver::sCurrentlyHandlingObservers = nullptr;
      42             : 
      43             : nsINodeList*
      44           0 : nsDOMMutationRecord::AddedNodes()
      45             : {
      46           0 :   if (!mAddedNodes) {
      47           0 :     mAddedNodes = new nsSimpleContentList(mTarget);
      48             :   }
      49           0 :   return mAddedNodes;
      50             : }
      51             : 
      52             : nsINodeList*
      53           0 : nsDOMMutationRecord::RemovedNodes()
      54             : {
      55           0 :   if (!mRemovedNodes) {
      56           0 :     mRemovedNodes = new nsSimpleContentList(mTarget);
      57             :   }
      58           0 :   return mRemovedNodes;
      59             : }
      60             : 
      61           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMMutationRecord)
      62           0 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
      63           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
      64           0 : NS_INTERFACE_MAP_END
      65             : 
      66           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMMutationRecord)
      67           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMMutationRecord)
      68             : 
      69           0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMMutationRecord,
      70             :                                       mTarget,
      71             :                                       mPreviousSibling, mNextSibling,
      72             :                                       mAddedNodes, mRemovedNodes,
      73             :                                       mAddedAnimations, mRemovedAnimations,
      74             :                                       mChangedAnimations,
      75             :                                       mNext, mOwner)
      76             : 
      77             : // Observer
      78             : 
      79             : bool
      80           0 : nsMutationReceiverBase::IsObservable(nsIContent* aContent)
      81             : {
      82           0 :   return !aContent->ChromeOnlyAccess() &&
      83           0 :     (Observer()->IsChrome() || !aContent->IsInAnonymousSubtree());
      84             : }
      85             : 
      86           1 : NS_IMPL_ADDREF(nsMutationReceiver)
      87           0 : NS_IMPL_RELEASE(nsMutationReceiver)
      88             : 
      89           0 : NS_INTERFACE_MAP_BEGIN(nsMutationReceiver)
      90           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
      91           0 :   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
      92           0 : NS_INTERFACE_MAP_END
      93             : 
      94           1 : nsMutationReceiver::nsMutationReceiver(nsINode* aTarget,
      95           1 :                                        nsDOMMutationObserver* aObserver)
      96           1 : : nsMutationReceiverBase(aTarget, aObserver)
      97             : {
      98           1 :   mTarget->BindObject(aObserver);
      99           1 : }
     100             : 
     101             : void
     102           0 : nsMutationReceiver::Disconnect(bool aRemoveFromObserver)
     103             : {
     104           0 :   if (mRegisterTarget) {
     105           0 :     mRegisterTarget->RemoveMutationObserver(this);
     106           0 :     mRegisterTarget = nullptr;
     107             :   }
     108             : 
     109           0 :   mParent = nullptr;
     110           0 :   nsINode* target = mTarget;
     111           0 :   mTarget = nullptr;
     112           0 :   nsDOMMutationObserver* observer = mObserver;
     113           0 :   mObserver = nullptr;
     114           0 :   RemoveClones();
     115             : 
     116           0 :   if (target && observer) {
     117           0 :     if (aRemoveFromObserver) {
     118           0 :       static_cast<nsDOMMutationObserver*>(observer)->RemoveReceiver(this);
     119             :     }
     120             :     // UnbindObject may delete 'this'!
     121           0 :     target->UnbindObject(observer);
     122             :   }
     123           0 : }
     124             : 
     125             : void
     126           0 : nsMutationReceiver::NativeAnonymousChildListChange(nsIDocument* aDocument,
     127             :                                                    nsIContent* aContent,
     128             :                                                    bool aIsRemove) {
     129           0 :   if (!NativeAnonymousChildList()) {
     130           0 :     return;
     131             :   }
     132             : 
     133           0 :   nsINode* parent = aContent->GetParentNode();
     134           0 :   if (!parent ||
     135           0 :       (!Subtree() && Target() != parent) ||
     136           0 :       (Subtree() && RegisterTarget()->SubtreeRoot() != parent->SubtreeRoot())) {
     137           0 :     return;
     138             :   }
     139             : 
     140             :   nsDOMMutationRecord* m =
     141           0 :     Observer()->CurrentRecord(nsGkAtoms::nativeAnonymousChildList);
     142             : 
     143           0 :   if (m->mTarget) {
     144           0 :     return;
     145             :   }
     146           0 :   m->mTarget = parent;
     147             : 
     148           0 :   if (aIsRemove) {
     149           0 :     m->mRemovedNodes = new nsSimpleContentList(parent);
     150           0 :     m->mRemovedNodes->AppendElement(aContent);
     151             :   } else {
     152           0 :     m->mAddedNodes = new nsSimpleContentList(parent);
     153           0 :     m->mAddedNodes->AppendElement(aContent);
     154             :   }
     155             : }
     156             : 
     157             : void
     158           0 : nsMutationReceiver::AttributeWillChange(nsIDocument* aDocument,
     159             :                                         mozilla::dom::Element* aElement,
     160             :                                         int32_t aNameSpaceID,
     161             :                                         nsIAtom* aAttribute,
     162             :                                         int32_t aModType,
     163             :                                         const nsAttrValue* aNewValue)
     164             : {
     165           0 :   if (nsAutoMutationBatch::IsBatching() ||
     166           0 :       !ObservesAttr(RegisterTarget(), aElement, aNameSpaceID, aAttribute)) {
     167           0 :     return;
     168             :   }
     169             : 
     170             :   nsDOMMutationRecord* m =
     171           0 :     Observer()->CurrentRecord(nsGkAtoms::attributes);
     172             : 
     173           0 :   NS_ASSERTION(!m->mTarget || m->mTarget == aElement,
     174             :                "Wrong target!");
     175           0 :   NS_ASSERTION(!m->mAttrName || m->mAttrName == aAttribute,
     176             :                "Wrong attribute!");
     177           0 :   if (!m->mTarget) {
     178           0 :     m->mTarget = aElement;
     179           0 :     m->mAttrName = aAttribute;
     180           0 :     if (aNameSpaceID == kNameSpaceID_None) {
     181           0 :       m->mAttrNamespace.SetIsVoid(true);
     182             :     } else {
     183           0 :       nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID,
     184           0 :                                                           m->mAttrNamespace);
     185             :     }
     186             :   }
     187             : 
     188           0 :   if (AttributeOldValue() && m->mPrevValue.IsVoid()) {
     189           0 :     if (!aElement->GetAttr(aNameSpaceID, aAttribute, m->mPrevValue)) {
     190           0 :       m->mPrevValue.SetIsVoid(true);
     191             :     }
     192             :   }
     193             : }
     194             : 
     195             : void
     196           0 : nsMutationReceiver::CharacterDataWillChange(nsIDocument *aDocument,
     197             :                                             nsIContent* aContent,
     198             :                                             CharacterDataChangeInfo* aInfo)
     199             : {
     200           0 :   if (nsAutoMutationBatch::IsBatching() ||
     201           0 :       !CharacterData() ||
     202           0 :       (!Subtree() && aContent != Target()) ||
     203           0 :       (Subtree() && RegisterTarget()->SubtreeRoot() != aContent->SubtreeRoot()) ||
     204           0 :       !IsObservable(aContent)) {
     205           0 :     return;
     206             :   }
     207             : 
     208             :   nsDOMMutationRecord* m =
     209           0 :     Observer()->CurrentRecord(nsGkAtoms::characterData);
     210             : 
     211           0 :   NS_ASSERTION(!m->mTarget || m->mTarget == aContent,
     212             :                "Wrong target!");
     213             : 
     214           0 :   if (!m->mTarget) {
     215           0 :     m->mTarget = aContent;
     216             :   }
     217           0 :   if (CharacterDataOldValue() && m->mPrevValue.IsVoid()) {
     218           0 :     aContent->GetText()->AppendTo(m->mPrevValue);
     219             :   }
     220             : }
     221             : 
     222             : void
     223           0 : nsMutationReceiver::ContentAppended(nsIDocument* aDocument,
     224             :                                     nsIContent* aContainer,
     225             :                                     nsIContent* aFirstNewContent,
     226             :                                     int32_t aNewIndexInContainer)
     227             : {
     228           0 :   nsINode* parent = NODE_FROM(aContainer, aDocument);
     229             :   bool wantsChildList =
     230           0 :     ChildList() &&
     231           0 :     ((Subtree() && RegisterTarget()->SubtreeRoot() == parent->SubtreeRoot()) ||
     232           0 :      parent == Target());
     233           0 :   if (!wantsChildList || !IsObservable(aFirstNewContent)) {
     234           0 :     return;
     235             :   }
     236             : 
     237           0 :   if (nsAutoMutationBatch::IsBatching()) {
     238           0 :     if (parent == nsAutoMutationBatch::GetBatchTarget()) {
     239           0 :       nsAutoMutationBatch::UpdateObserver(Observer(), wantsChildList);
     240             :     }
     241           0 :     return;
     242             :   }
     243             : 
     244             :   nsDOMMutationRecord* m =
     245           0 :     Observer()->CurrentRecord(nsGkAtoms::childList);
     246           0 :   NS_ASSERTION(!m->mTarget || m->mTarget == parent,
     247             :                "Wrong target!");
     248           0 :   if (m->mTarget) {
     249             :     // Already handled case.
     250           0 :     return;
     251             :   }
     252           0 :   m->mTarget = parent;
     253           0 :   m->mAddedNodes = new nsSimpleContentList(parent);
     254             : 
     255           0 :   nsINode* n = aFirstNewContent;
     256           0 :   while (n) {
     257           0 :     m->mAddedNodes->AppendElement(static_cast<nsIContent*>(n));
     258           0 :     n = n->GetNextSibling();
     259             :   }
     260           0 :   m->mPreviousSibling = aFirstNewContent->GetPreviousSibling();
     261             : }
     262             : 
     263             : void
     264           0 : nsMutationReceiver::ContentInserted(nsIDocument* aDocument,
     265             :                                     nsIContent* aContainer,
     266             :                                     nsIContent* aChild,
     267             :                                     int32_t aIndexInContainer)
     268             : {
     269           0 :   nsINode* parent = NODE_FROM(aContainer, aDocument);
     270             :   bool wantsChildList =
     271           0 :     ChildList() &&
     272           0 :     ((Subtree() && RegisterTarget()->SubtreeRoot() == parent->SubtreeRoot()) ||
     273           0 :      parent == Target());
     274           0 :   if (!wantsChildList || !IsObservable(aChild)) {
     275           0 :     return;
     276             :   }
     277             : 
     278           0 :   if (nsAutoMutationBatch::IsBatching()) {
     279           0 :     if (parent == nsAutoMutationBatch::GetBatchTarget()) {
     280           0 :       nsAutoMutationBatch::UpdateObserver(Observer(), wantsChildList);
     281             :     }
     282           0 :     return;
     283             :   }
     284             : 
     285             :   nsDOMMutationRecord* m =
     286           0 :     Observer()->CurrentRecord(nsGkAtoms::childList);
     287           0 :   if (m->mTarget) {
     288             :     // Already handled case.
     289           0 :     return;
     290             :   }
     291           0 :   m->mTarget = parent;
     292           0 :   m->mAddedNodes = new nsSimpleContentList(parent);
     293           0 :   m->mAddedNodes->AppendElement(aChild);
     294           0 :   m->mPreviousSibling = aChild->GetPreviousSibling();
     295           0 :   m->mNextSibling = aChild->GetNextSibling();
     296             : }
     297             : 
     298             : void
     299           0 : nsMutationReceiver::ContentRemoved(nsIDocument* aDocument,
     300             :                                    nsIContent* aContainer,
     301             :                                    nsIContent* aChild,
     302             :                                    int32_t aIndexInContainer,
     303             :                                    nsIContent* aPreviousSibling)
     304             : {
     305           0 :   if (!IsObservable(aChild)) {
     306           0 :     return;
     307             :   }
     308             : 
     309           0 :   nsINode* parent = NODE_FROM(aContainer, aDocument);
     310           0 :   if (Subtree() && parent->SubtreeRoot() != RegisterTarget()->SubtreeRoot()) {
     311           0 :     return;
     312             :   }
     313           0 :   if (nsAutoMutationBatch::IsBatching()) {
     314           0 :     if (nsAutoMutationBatch::IsRemovalDone()) {
     315             :       // This can happen for example if HTML parser parses to
     316             :       // context node, but needs to move elements around.
     317           0 :       return;
     318             :     }
     319           0 :     if (nsAutoMutationBatch::GetBatchTarget() != parent) {
     320           0 :       return;
     321             :     }
     322             : 
     323           0 :     bool wantsChildList = ChildList() && (Subtree() || parent == Target());
     324           0 :     if (wantsChildList || Subtree()) {
     325           0 :       nsAutoMutationBatch::NodeRemoved(aChild);
     326           0 :       nsAutoMutationBatch::UpdateObserver(Observer(), wantsChildList);
     327             :     }
     328             : 
     329           0 :     return;
     330             :   }
     331             : 
     332           0 :   if (Subtree()) {
     333             :     // Try to avoid creating transient observer if the node
     334             :     // already has an observer observing the same set of nodes.
     335           0 :     nsMutationReceiver* orig = GetParent() ? GetParent() : this;
     336           0 :     if (Observer()->GetReceiverFor(aChild, false, false) != orig) {
     337           0 :       bool transientExists = false;
     338           0 :       bool isNewEntry = false;
     339             :       nsCOMArray<nsMutationReceiver>* transientReceivers =
     340           0 :         Observer()->mTransientReceivers.LookupForAdd(aChild).OrInsert(
     341           0 :           [&isNewEntry] () {
     342           0 :             isNewEntry = true;
     343           0 :             return new nsCOMArray<nsMutationReceiver>();
     344           0 :           });
     345           0 :       if (!isNewEntry) {
     346           0 :         for (int32_t i = 0; i < transientReceivers->Count(); ++i) {
     347           0 :           nsMutationReceiver* r = transientReceivers->ObjectAt(i);
     348           0 :           if (r->GetParent() == orig) {
     349           0 :             transientExists = true;
     350             :           }
     351             :         }
     352             :       }
     353           0 :       if (!transientExists) {
     354             :         // Make sure the elements which are removed from the
     355             :         // subtree are kept in the same observation set.
     356             :         nsMutationReceiver* tr;
     357           0 :         if (orig->Animations()) {
     358           0 :           tr = nsAnimationReceiver::Create(aChild, orig);
     359             :         } else {
     360           0 :           tr = nsMutationReceiver::Create(aChild, orig);
     361             :         }
     362           0 :         transientReceivers->AppendObject(tr);
     363             :       }
     364             :     }
     365             :   }
     366             : 
     367           0 :   if (ChildList() && (Subtree() || parent == Target())) {
     368             :     nsDOMMutationRecord* m =
     369           0 :       Observer()->CurrentRecord(nsGkAtoms::childList);
     370           0 :     if (m->mTarget) {
     371             :       // Already handled case.
     372           0 :       return;
     373             :     }
     374           0 :     m->mTarget = parent;
     375           0 :     m->mRemovedNodes = new nsSimpleContentList(parent);
     376           0 :     m->mRemovedNodes->AppendElement(aChild);
     377           0 :     m->mPreviousSibling = aPreviousSibling;
     378           0 :     m->mNextSibling = parent->GetChildAt(aIndexInContainer);
     379             :   }
     380             :   // We need to schedule always, so that after microtask mTransientReceivers
     381             :   // can be cleared correctly.
     382           0 :   Observer()->ScheduleForRun();
     383             : }
     384             : 
     385           0 : void nsMutationReceiver::NodeWillBeDestroyed(const nsINode *aNode)
     386             : {
     387           0 :   NS_ASSERTION(!mParent, "Shouldn't have mParent here!");
     388           0 :   Disconnect(true);
     389           0 : }
     390             : 
     391             : void
     392           0 : nsAnimationReceiver::RecordAnimationMutation(Animation* aAnimation,
     393             :                                              AnimationMutation aMutationType)
     394             : {
     395           0 :   mozilla::dom::AnimationEffectReadOnly* effect = aAnimation->GetEffect();
     396           0 :   if (!effect) {
     397           0 :     return;
     398             :   }
     399             : 
     400             :   mozilla::dom::KeyframeEffectReadOnly* keyframeEffect =
     401           0 :     effect->AsKeyframeEffect();
     402           0 :   if (!keyframeEffect) {
     403           0 :     return;
     404             :   }
     405             : 
     406           0 :   Maybe<NonOwningAnimationTarget> animationTarget = keyframeEffect->GetTarget();
     407           0 :   if (!animationTarget) {
     408           0 :     return;
     409             :   }
     410             : 
     411           0 :   Element* elem = animationTarget->mElement;
     412           0 :   if (!Animations() || !(Subtree() || elem == Target()) ||
     413           0 :       elem->ChromeOnlyAccess()) {
     414           0 :     return;
     415             :   }
     416             : 
     417             :   // Record animations targeting to a pseudo element only when subtree is true.
     418           0 :   if (animationTarget->mPseudoType != mozilla::CSSPseudoElementType::NotPseudo &&
     419           0 :       !Subtree()) {
     420           0 :     return;
     421             :   }
     422             : 
     423           0 :   if (nsAutoAnimationMutationBatch::IsBatching()) {
     424           0 :     switch (aMutationType) {
     425             :       case eAnimationMutation_Added:
     426           0 :         nsAutoAnimationMutationBatch::AnimationAdded(aAnimation, elem);
     427           0 :         break;
     428             :       case eAnimationMutation_Changed:
     429           0 :         nsAutoAnimationMutationBatch::AnimationChanged(aAnimation, elem);
     430           0 :         break;
     431             :       case eAnimationMutation_Removed:
     432           0 :         nsAutoAnimationMutationBatch::AnimationRemoved(aAnimation, elem);
     433           0 :         break;
     434             :     }
     435             : 
     436           0 :     nsAutoAnimationMutationBatch::AddObserver(Observer());
     437           0 :     return;
     438             :   }
     439             : 
     440             :   nsDOMMutationRecord* m =
     441           0 :     Observer()->CurrentRecord(nsGkAtoms::animations);
     442             : 
     443           0 :   NS_ASSERTION(!m->mTarget, "Wrong target!");
     444             : 
     445           0 :   m->mTarget = elem;
     446             : 
     447           0 :   switch (aMutationType) {
     448             :     case eAnimationMutation_Added:
     449           0 :       m->mAddedAnimations.AppendElement(aAnimation);
     450           0 :       break;
     451             :     case eAnimationMutation_Changed:
     452           0 :       m->mChangedAnimations.AppendElement(aAnimation);
     453           0 :       break;
     454             :     case eAnimationMutation_Removed:
     455           0 :       m->mRemovedAnimations.AppendElement(aAnimation);
     456           0 :       break;
     457             :   }
     458             : }
     459             : 
     460             : void
     461           0 : nsAnimationReceiver::AnimationAdded(Animation* aAnimation)
     462             : {
     463           0 :   RecordAnimationMutation(aAnimation, eAnimationMutation_Added);
     464           0 : }
     465             : 
     466             : void
     467           0 : nsAnimationReceiver::AnimationChanged(Animation* aAnimation)
     468             : {
     469           0 :   RecordAnimationMutation(aAnimation, eAnimationMutation_Changed);
     470           0 : }
     471             : 
     472             : void
     473           0 : nsAnimationReceiver::AnimationRemoved(Animation* aAnimation)
     474             : {
     475           0 :   RecordAnimationMutation(aAnimation, eAnimationMutation_Removed);
     476           0 : }
     477             : 
     478           0 : NS_IMPL_ISUPPORTS_INHERITED(nsAnimationReceiver, nsMutationReceiver,
     479             :                             nsIAnimationObserver)
     480             : 
     481             : // Observer
     482             : 
     483          10 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMMutationObserver)
     484           1 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     485           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     486           0 :   NS_INTERFACE_MAP_ENTRY(nsDOMMutationObserver)
     487           0 : NS_INTERFACE_MAP_END
     488             : 
     489           3 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMMutationObserver)
     490           1 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMMutationObserver)
     491             : 
     492             : NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMMutationObserver)
     493             : 
     494           2 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMMutationObserver)
     495           2 :   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
     496           2 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
     497             : 
     498           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMMutationObserver)
     499           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
     500           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
     501           0 :   for (int32_t i = 0; i < tmp->mReceivers.Count(); ++i) {
     502           0 :     tmp->mReceivers[i]->Disconnect(false);
     503             :   }
     504           0 :   tmp->mReceivers.Clear();
     505           0 :   tmp->ClearPendingRecords();
     506           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback)
     507             :   // No need to handle mTransientReceivers
     508           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     509             : 
     510           1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMMutationObserver)
     511           1 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
     512           1 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReceivers)
     513           1 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFirstPendingMutation)
     514           1 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback)
     515             :   // No need to handle mTransientReceivers
     516           1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     517             : 
     518             : nsMutationReceiver*
     519           1 : nsDOMMutationObserver::GetReceiverFor(nsINode* aNode, bool aMayCreate,
     520             :                                       bool aWantsAnimations)
     521             : {
     522           1 :   MOZ_ASSERT(aMayCreate || !aWantsAnimations,
     523             :              "the value of aWantsAnimations doesn't matter when aMayCreate is "
     524             :              "false, so just pass in false for it");
     525             : 
     526           1 :   if (!aMayCreate && !aNode->MayHaveDOMMutationObserver()) {
     527           0 :     return nullptr;
     528             :   }
     529             : 
     530           1 :   for (int32_t i = 0; i < mReceivers.Count(); ++i) {
     531           0 :     if (mReceivers[i]->Target() == aNode) {
     532           0 :       return mReceivers[i];
     533             :     }
     534             :   }
     535           1 :   if (!aMayCreate) {
     536           0 :     return nullptr;
     537             :   }
     538             : 
     539             :   nsMutationReceiver* r;
     540           1 :   if (aWantsAnimations) {
     541           0 :     r = nsAnimationReceiver::Create(aNode, this);
     542             :   } else {
     543           1 :     r = nsMutationReceiver::Create(aNode, this);
     544             :   }
     545           1 :   mReceivers.AppendObject(r);
     546           1 :   return r;
     547             : }
     548             : 
     549             : void
     550           0 : nsDOMMutationObserver::RemoveReceiver(nsMutationReceiver* aReceiver)
     551             : {
     552           0 :   mReceivers.RemoveObject(aReceiver);
     553           0 : }
     554             : 
     555             : void
     556           0 : nsDOMMutationObserver::GetAllSubtreeObserversFor(nsINode* aNode,
     557             :                                                  nsTArray<nsMutationReceiver*>&
     558             :                                                    aReceivers)
     559             : {
     560           0 :   nsINode* n = aNode;
     561           0 :   while (n) {
     562           0 :     if (n->MayHaveDOMMutationObserver()) {
     563           0 :       nsMutationReceiver* r = GetReceiverFor(n, false, false);
     564           0 :       if (r && r->Subtree() && !aReceivers.Contains(r)) {
     565           0 :         aReceivers.AppendElement(r);
     566             :         // If we've found all the receivers the observer has,
     567             :         // no need to search for more.
     568           0 :         if (mReceivers.Count() == int32_t(aReceivers.Length())) {
     569           0 :           return;
     570             :         }
     571             :       }
     572           0 :       nsCOMArray<nsMutationReceiver>* transientReceivers = nullptr;
     573           0 :       if (mTransientReceivers.Get(n, &transientReceivers) && transientReceivers) {
     574           0 :         for (int32_t i = 0; i < transientReceivers->Count(); ++i) {
     575           0 :           nsMutationReceiver* r = transientReceivers->ObjectAt(i);
     576           0 :           nsMutationReceiver* parent = r->GetParent();
     577           0 :           if (r->Subtree() && parent && !aReceivers.Contains(parent)) {
     578           0 :             aReceivers.AppendElement(parent);
     579             :           }
     580             :         }
     581           0 :         if (mReceivers.Count() == int32_t(aReceivers.Length())) {
     582           0 :           return;
     583             :         }
     584             :       }
     585             :     }
     586           0 :     n = n->GetParentNode();
     587             :   }
     588             : }
     589             : 
     590             : void
     591           0 : nsDOMMutationObserver::ScheduleForRun()
     592             : {
     593           0 :   nsDOMMutationObserver::AddCurrentlyHandlingObserver(this, sMutationLevel);
     594             : 
     595           0 :   if (mWaitingForRun) {
     596           0 :     return;
     597             :   }
     598           0 :   mWaitingForRun = true;
     599           0 :   RescheduleForRun();
     600             : }
     601             : 
     602             : void
     603           0 : nsDOMMutationObserver::RescheduleForRun()
     604             : {
     605           0 :   if (!sScheduledMutationObservers) {
     606           0 :     sScheduledMutationObservers = new AutoTArray<RefPtr<nsDOMMutationObserver>, 4>;
     607             :   }
     608             : 
     609           0 :   bool didInsert = false;
     610           0 :   for (uint32_t i = 0; i < sScheduledMutationObservers->Length(); ++i) {
     611           0 :     if (static_cast<nsDOMMutationObserver*>((*sScheduledMutationObservers)[i])
     612           0 :           ->mId > mId) {
     613           0 :       sScheduledMutationObservers->InsertElementAt(i, this);
     614           0 :       didInsert = true;
     615           0 :       break;
     616             :     }
     617             :   }
     618           0 :   if (!didInsert) {
     619           0 :     sScheduledMutationObservers->AppendElement(this);
     620             :   }
     621           0 : }
     622             : 
     623             : void
     624           1 : nsDOMMutationObserver::Observe(nsINode& aTarget,
     625             :                                const mozilla::dom::MutationObserverInit& aOptions,
     626             :                                mozilla::ErrorResult& aRv)
     627             : {
     628             : 
     629           1 :   bool childList = aOptions.mChildList;
     630             :   bool attributes =
     631           1 :     aOptions.mAttributes.WasPassed() &&
     632           1 :     aOptions.mAttributes.Value();
     633             :   bool characterData =
     634           1 :     aOptions.mCharacterData.WasPassed() &&
     635           1 :     aOptions.mCharacterData.Value();
     636           1 :   bool subtree = aOptions.mSubtree;
     637             :   bool attributeOldValue =
     638           1 :     aOptions.mAttributeOldValue.WasPassed() &&
     639           1 :     aOptions.mAttributeOldValue.Value();
     640           1 :   bool nativeAnonymousChildList = aOptions.mNativeAnonymousChildList;
     641             :   bool characterDataOldValue =
     642           1 :     aOptions.mCharacterDataOldValue.WasPassed() &&
     643           1 :     aOptions.mCharacterDataOldValue.Value();
     644           1 :   bool animations = aOptions.mAnimations;
     645             : 
     646           2 :   if (!aOptions.mAttributes.WasPassed() &&
     647           2 :       (aOptions.mAttributeOldValue.WasPassed() ||
     648           1 :        aOptions.mAttributeFilter.WasPassed())) {
     649           0 :     attributes = true;
     650             :   }
     651             : 
     652           2 :   if (!aOptions.mCharacterData.WasPassed() &&
     653           1 :       aOptions.mCharacterDataOldValue.WasPassed()) {
     654           0 :     characterData = true;
     655             :   }
     656             : 
     657           1 :   if (!(childList || attributes || characterData || animations ||
     658           0 :         nativeAnonymousChildList)) {
     659           0 :     aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
     660           0 :     return;
     661             :   }
     662             : 
     663           2 :   if (aOptions.mAttributeOldValue.WasPassed() &&
     664           0 :       aOptions.mAttributeOldValue.Value() &&
     665           1 :       aOptions.mAttributes.WasPassed() &&
     666           0 :       !aOptions.mAttributes.Value()) {
     667           0 :     aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
     668           0 :     return;
     669             :   }
     670             : 
     671           2 :   if (aOptions.mAttributeFilter.WasPassed() &&
     672           1 :       aOptions.mAttributes.WasPassed() &&
     673           0 :       !aOptions.mAttributes.Value()) {
     674           0 :     aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
     675           0 :     return;
     676             :   }
     677             : 
     678           2 :   if (aOptions.mCharacterDataOldValue.WasPassed() &&
     679           0 :       aOptions.mCharacterDataOldValue.Value() &&
     680           1 :       aOptions.mCharacterData.WasPassed() &&
     681           0 :       !aOptions.mCharacterData.Value()) {
     682           0 :     aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
     683           0 :     return;
     684             :   }
     685             : 
     686           2 :   nsCOMArray<nsIAtom> filters;
     687           1 :   bool allAttrs = true;
     688           1 :   if (aOptions.mAttributeFilter.WasPassed()) {
     689           0 :     allAttrs = false;
     690             :     const mozilla::dom::Sequence<nsString>& filtersAsString =
     691           0 :       aOptions.mAttributeFilter.Value();
     692           0 :     uint32_t len = filtersAsString.Length();
     693           0 :     filters.SetCapacity(len);
     694             : 
     695           0 :     for (uint32_t i = 0; i < len; ++i) {
     696           0 :       filters.AppendElement(NS_Atomize(filtersAsString[i]));
     697             :     }
     698             :   }
     699             : 
     700           1 :   nsMutationReceiver* r = GetReceiverFor(&aTarget, true, animations);
     701           1 :   r->SetChildList(childList);
     702           1 :   r->SetAttributes(attributes);
     703           1 :   r->SetCharacterData(characterData);
     704           1 :   r->SetSubtree(subtree);
     705           1 :   r->SetAttributeOldValue(attributeOldValue);
     706           1 :   r->SetCharacterDataOldValue(characterDataOldValue);
     707           1 :   r->SetNativeAnonymousChildList(nativeAnonymousChildList);
     708           1 :   r->SetAttributeFilter(Move(filters));
     709           1 :   r->SetAllAttributes(allAttrs);
     710           1 :   r->SetAnimations(animations);
     711           1 :   r->RemoveClones();
     712             : 
     713             : #ifdef DEBUG
     714           2 :   for (int32_t i = 0; i < mReceivers.Count(); ++i) {
     715           1 :     NS_WARNING_ASSERTION(mReceivers[i]->Target(),
     716             :                          "All the receivers should have a target!");
     717             :   }
     718             : #endif
     719             : }
     720             : 
     721             : void
     722           0 : nsDOMMutationObserver::Disconnect()
     723             : {
     724           0 :   for (int32_t i = 0; i < mReceivers.Count(); ++i) {
     725           0 :     mReceivers[i]->Disconnect(false);
     726             :   }
     727           0 :   mReceivers.Clear();
     728           0 :   mCurrentMutations.Clear();
     729           0 :   ClearPendingRecords();
     730           0 : }
     731             : 
     732             : void
     733           0 : nsDOMMutationObserver::TakeRecords(
     734             :                          nsTArray<RefPtr<nsDOMMutationRecord> >& aRetVal)
     735             : {
     736           0 :   aRetVal.Clear();
     737           0 :   aRetVal.SetCapacity(mPendingMutationCount);
     738           0 :   RefPtr<nsDOMMutationRecord> current;
     739           0 :   current.swap(mFirstPendingMutation);
     740           0 :   for (uint32_t i = 0; i < mPendingMutationCount; ++i) {
     741           0 :     RefPtr<nsDOMMutationRecord> next;
     742           0 :     current->mNext.swap(next);
     743           0 :     if (!mMergeAttributeRecords ||
     744           0 :         !MergeableAttributeRecord(aRetVal.SafeLastElement(nullptr),
     745             :                                   current)) {
     746           0 :       *aRetVal.AppendElement() = current.forget();
     747             :     }
     748           0 :     current.swap(next);
     749             :   }
     750           0 :   ClearPendingRecords();
     751           0 : }
     752             : 
     753             : void
     754           0 : nsDOMMutationObserver::GetObservingInfo(
     755             :                          nsTArray<Nullable<MutationObservingInfo>>& aResult,
     756             :                          mozilla::ErrorResult& aRv)
     757             : {
     758           0 :   aResult.SetCapacity(mReceivers.Count());
     759           0 :   for (int32_t i = 0; i < mReceivers.Count(); ++i) {
     760           0 :     MutationObservingInfo& info = aResult.AppendElement()->SetValue();
     761           0 :     nsMutationReceiver* mr = mReceivers[i];
     762           0 :     info.mChildList = mr->ChildList();
     763           0 :     info.mAttributes.Construct(mr->Attributes());
     764           0 :     info.mCharacterData.Construct(mr->CharacterData());
     765           0 :     info.mSubtree = mr->Subtree();
     766           0 :     info.mAttributeOldValue.Construct(mr->AttributeOldValue());
     767           0 :     info.mCharacterDataOldValue.Construct(mr->CharacterDataOldValue());
     768           0 :     info.mNativeAnonymousChildList = mr->NativeAnonymousChildList();
     769           0 :     info.mAnimations = mr->Animations();
     770           0 :     nsCOMArray<nsIAtom>& filters = mr->AttributeFilter();
     771           0 :     if (filters.Count()) {
     772           0 :       info.mAttributeFilter.Construct();
     773             :       mozilla::dom::Sequence<nsString>& filtersAsStrings =
     774           0 :         info.mAttributeFilter.Value();
     775           0 :       nsString* strings = filtersAsStrings.AppendElements(filters.Count(),
     776           0 :                                                           mozilla::fallible);
     777           0 :       if (!strings) {
     778           0 :         aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     779           0 :         return;
     780             :       }
     781           0 :       for (int32_t j = 0; j < filters.Count(); ++j) {
     782           0 :         filters[j]->ToString(strings[j]);
     783             :       }
     784             :     }
     785           0 :     info.mObservedNode = mr->Target();
     786             :   }
     787             : }
     788             : 
     789             : // static
     790             : already_AddRefed<nsDOMMutationObserver>
     791           1 : nsDOMMutationObserver::Constructor(const mozilla::dom::GlobalObject& aGlobal,
     792             :                                    mozilla::dom::MutationCallback& aCb,
     793             :                                    mozilla::ErrorResult& aRv)
     794             : {
     795           2 :   nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
     796           1 :   if (!window) {
     797           0 :     aRv.Throw(NS_ERROR_FAILURE);
     798           0 :     return nullptr;
     799             :   }
     800           1 :   MOZ_ASSERT(window->IsInnerWindow());
     801           1 :   bool isChrome = nsContentUtils::IsChromeDoc(window->GetExtantDoc());
     802             :   RefPtr<nsDOMMutationObserver> observer =
     803           3 :     new nsDOMMutationObserver(window.forget(), aCb, isChrome);
     804           1 :   return observer.forget();
     805             : }
     806             : 
     807             : 
     808             : bool
     809           0 : nsDOMMutationObserver::MergeableAttributeRecord(nsDOMMutationRecord* aOldRecord,
     810             :                                                 nsDOMMutationRecord* aRecord)
     811             : {
     812           0 :   MOZ_ASSERT(mMergeAttributeRecords);
     813             :   return
     814           0 :     aOldRecord &&
     815           0 :     aOldRecord->mType == nsGkAtoms::attributes &&
     816           0 :     aOldRecord->mType == aRecord->mType &&
     817           0 :     aOldRecord->mTarget == aRecord->mTarget &&
     818           0 :     aOldRecord->mAttrName == aRecord->mAttrName &&
     819           0 :     aOldRecord->mAttrNamespace.Equals(aRecord->mAttrNamespace);
     820             : }
     821             : 
     822             : void
     823           0 : nsDOMMutationObserver::HandleMutation()
     824             : {
     825           0 :   NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), "Whaat!");
     826           0 :   NS_ASSERTION(mCurrentMutations.IsEmpty(),
     827             :                "Still generating MutationRecords?");
     828             : 
     829           0 :   mWaitingForRun = false;
     830             : 
     831           0 :   for (int32_t i = 0; i < mReceivers.Count(); ++i) {
     832           0 :     mReceivers[i]->RemoveClones();
     833             :   }
     834           0 :   mTransientReceivers.Clear();
     835             : 
     836           0 :   nsPIDOMWindowOuter* outer = mOwner->GetOuterWindow();
     837           0 :   if (!mPendingMutationCount || !outer ||
     838           0 :       outer->GetCurrentInnerWindow() != mOwner) {
     839           0 :     ClearPendingRecords();
     840           0 :     return;
     841             :   }
     842             : 
     843             :   mozilla::dom::Sequence<mozilla::OwningNonNull<nsDOMMutationRecord> >
     844           0 :     mutations;
     845           0 :   if (mutations.SetCapacity(mPendingMutationCount, mozilla::fallible)) {
     846             :     // We can't use TakeRecords easily here, because it deals with a
     847             :     // different type of array, and we want to optimize out any extra copying.
     848           0 :     RefPtr<nsDOMMutationRecord> current;
     849           0 :     current.swap(mFirstPendingMutation);
     850           0 :     for (uint32_t i = 0; i < mPendingMutationCount; ++i) {
     851           0 :       RefPtr<nsDOMMutationRecord> next;
     852           0 :       current->mNext.swap(next);
     853           0 :       if (!mMergeAttributeRecords ||
     854           0 :           !MergeableAttributeRecord(mutations.Length() ?
     855           0 :                                       mutations.LastElement().get() : nullptr,
     856             :                                     current)) {
     857           0 :         *mutations.AppendElement(mozilla::fallible) = current;
     858             :       }
     859           0 :       current.swap(next);
     860             :     }
     861             :   }
     862           0 :   ClearPendingRecords();
     863             : 
     864           0 :   mCallback->Call(this, mutations, *this);
     865             : }
     866             : 
     867           0 : class AsyncMutationHandler : public mozilla::Runnable
     868             : {
     869             : public:
     870           0 :   AsyncMutationHandler() : mozilla::Runnable("AsyncMutationHandler") {}
     871           0 :   NS_IMETHOD Run() override
     872             :   {
     873           0 :     nsDOMMutationObserver::HandleMutations();
     874           0 :     return NS_OK;
     875             :   }
     876             : };
     877             : 
     878             : void
     879           0 : nsDOMMutationObserver::HandleMutationsInternal()
     880             : {
     881           0 :   if (!nsContentUtils::IsSafeToRunScript()) {
     882           0 :     nsContentUtils::AddScriptRunner(new AsyncMutationHandler());
     883           0 :     return;
     884             :   }
     885           0 :   static RefPtr<nsDOMMutationObserver> sCurrentObserver;
     886           0 :   if (sCurrentObserver && !sCurrentObserver->Suppressed()) {
     887             :     // In normal cases sScheduledMutationObservers will be handled
     888             :     // after previous mutations are handled. But in case some
     889             :     // callback calls a sync API, which spins the eventloop, we need to still
     890             :     // process other mutations happening during that sync call.
     891             :     // This does *not* catch all cases, but should work for stuff running
     892             :     // in separate tabs.
     893           0 :     return;
     894             :   }
     895             : 
     896           0 :   mozilla::AutoSlowOperation aso;
     897             : 
     898           0 :   nsTArray<RefPtr<nsDOMMutationObserver> >* suppressedObservers = nullptr;
     899             : 
     900           0 :   while (sScheduledMutationObservers) {
     901             :     AutoTArray<RefPtr<nsDOMMutationObserver>, 4>* observers =
     902           0 :       sScheduledMutationObservers;
     903           0 :     sScheduledMutationObservers = nullptr;
     904           0 :     for (uint32_t i = 0; i < observers->Length(); ++i) {
     905           0 :       sCurrentObserver = static_cast<nsDOMMutationObserver*>((*observers)[i]);
     906           0 :       if (!sCurrentObserver->Suppressed()) {
     907           0 :         sCurrentObserver->HandleMutation();
     908             :       } else {
     909           0 :         if (!suppressedObservers) {
     910           0 :           suppressedObservers = new nsTArray<RefPtr<nsDOMMutationObserver> >;
     911             :         }
     912           0 :         if (!suppressedObservers->Contains(sCurrentObserver)) {
     913           0 :           suppressedObservers->AppendElement(sCurrentObserver);
     914             :         }
     915             :       }
     916             :     }
     917           0 :     delete observers;
     918           0 :     aso.CheckForInterrupt();
     919             :   }
     920             : 
     921           0 :   if (suppressedObservers) {
     922           0 :     for (uint32_t i = 0; i < suppressedObservers->Length(); ++i) {
     923           0 :       static_cast<nsDOMMutationObserver*>(suppressedObservers->ElementAt(i))->
     924           0 :         RescheduleForRun();
     925             :     }
     926           0 :     delete suppressedObservers;
     927           0 :     suppressedObservers = nullptr;
     928             :   }
     929           0 :   sCurrentObserver = nullptr;
     930             : }
     931             : 
     932             : nsDOMMutationRecord*
     933           0 : nsDOMMutationObserver::CurrentRecord(nsIAtom* aType)
     934             : {
     935           0 :   NS_ASSERTION(sMutationLevel > 0, "Unexpected mutation level!");
     936             : 
     937           0 :   while (mCurrentMutations.Length() < sMutationLevel) {
     938           0 :     mCurrentMutations.AppendElement(static_cast<nsDOMMutationRecord*>(nullptr));
     939             :   }
     940             : 
     941           0 :   uint32_t last = sMutationLevel - 1;
     942           0 :   if (!mCurrentMutations[last]) {
     943           0 :     RefPtr<nsDOMMutationRecord> r = new nsDOMMutationRecord(aType, GetParentObject());
     944           0 :     mCurrentMutations[last] = r;
     945           0 :     AppendMutationRecord(r.forget());
     946           0 :     ScheduleForRun();
     947             :   }
     948             : 
     949             : #ifdef DEBUG
     950           0 :   MOZ_ASSERT(sCurrentlyHandlingObservers->Length() == sMutationLevel);
     951           0 :   for (size_t i = 0; i < sCurrentlyHandlingObservers->Length(); ++i) {
     952           0 :     MOZ_ASSERT(sCurrentlyHandlingObservers->ElementAt(i).Contains(this),
     953             :                "MutationObserver should be added as an observer of all the "
     954             :                "nested mutations!");
     955             :   }
     956             : #endif
     957             : 
     958           0 :   NS_ASSERTION(mCurrentMutations[last]->mType == aType,
     959             :                "Unexpected MutationRecord type!");
     960             : 
     961           0 :   return mCurrentMutations[last];
     962             : }
     963             : 
     964           0 : nsDOMMutationObserver::~nsDOMMutationObserver()
     965             : {
     966           0 :   for (int32_t i = 0; i < mReceivers.Count(); ++i) {
     967           0 :     mReceivers[i]->RemoveClones();
     968             :   }
     969           0 : }
     970             : 
     971             : void
     972        1043 : nsDOMMutationObserver::EnterMutationHandling()
     973             : {
     974        1043 :   ++sMutationLevel;
     975        1043 : }
     976             : 
     977             : // Leave the current mutation level (there can be several levels if in case
     978             : // of nested calls to the nsIMutationObserver methods).
     979             : // The most recent mutation record is removed from mCurrentMutations, so
     980             : // that is doesn't get modified anymore by receivers.
     981             : void
     982        1043 : nsDOMMutationObserver::LeaveMutationHandling()
     983             : {
     984        1043 :   if (sCurrentlyHandlingObservers &&
     985        1043 :       sCurrentlyHandlingObservers->Length() == sMutationLevel) {
     986             :     nsTArray<RefPtr<nsDOMMutationObserver> >& obs =
     987           0 :       sCurrentlyHandlingObservers->ElementAt(sMutationLevel - 1);
     988           0 :     for (uint32_t i = 0; i < obs.Length(); ++i) {
     989             :       nsDOMMutationObserver* o =
     990           0 :         static_cast<nsDOMMutationObserver*>(obs[i]);
     991           0 :       if (o->mCurrentMutations.Length() == sMutationLevel) {
     992             :         // It is already in pending mutations.
     993           0 :         o->mCurrentMutations.RemoveElementAt(sMutationLevel - 1);
     994             :       }
     995             :     }
     996           0 :     sCurrentlyHandlingObservers->RemoveElementAt(sMutationLevel - 1);
     997             :   }
     998        1043 :   --sMutationLevel;
     999        1043 : }
    1000             : 
    1001             : void
    1002           0 : nsDOMMutationObserver::AddCurrentlyHandlingObserver(nsDOMMutationObserver* aObserver,
    1003             :                                                     uint32_t aMutationLevel)
    1004             : {
    1005           0 :   NS_ASSERTION(aMutationLevel > 0, "Unexpected mutation level!");
    1006             : 
    1007           0 :   if (aMutationLevel > 1) {
    1008             :     // MutationObserver must be in the currently handling observer list
    1009             :     // in all the nested levels.
    1010           0 :     AddCurrentlyHandlingObserver(aObserver, aMutationLevel - 1);
    1011             :   }
    1012             : 
    1013           0 :   if (!sCurrentlyHandlingObservers) {
    1014           0 :     sCurrentlyHandlingObservers =
    1015           0 :       new AutoTArray<AutoTArray<RefPtr<nsDOMMutationObserver>, 4>, 4>;
    1016             :   }
    1017             : 
    1018           0 :   while (sCurrentlyHandlingObservers->Length() < aMutationLevel) {
    1019           0 :     sCurrentlyHandlingObservers->InsertElementAt(
    1020           0 :       sCurrentlyHandlingObservers->Length());
    1021             :   }
    1022             : 
    1023           0 :   uint32_t index = aMutationLevel - 1;
    1024           0 :   if (!sCurrentlyHandlingObservers->ElementAt(index).Contains(aObserver)) {
    1025           0 :     sCurrentlyHandlingObservers->ElementAt(index).AppendElement(aObserver);
    1026             :   }
    1027           0 : }
    1028             : 
    1029             : void
    1030           0 : nsDOMMutationObserver::Shutdown()
    1031             : {
    1032           0 :   delete sCurrentlyHandlingObservers;
    1033           0 :   sCurrentlyHandlingObservers = nullptr;
    1034           0 :   delete sScheduledMutationObservers;
    1035           0 :   sScheduledMutationObservers = nullptr;
    1036           0 : }
    1037             : 
    1038             : nsAutoMutationBatch*
    1039             : nsAutoMutationBatch::sCurrentBatch = nullptr;
    1040             : 
    1041             : void
    1042          10 : nsAutoMutationBatch::Done()
    1043             : {
    1044          10 :   if (sCurrentBatch != this) {
    1045           0 :     return;
    1046             :   }
    1047             : 
    1048          10 :   sCurrentBatch = mPreviousBatch;
    1049          10 :   if (mObservers.IsEmpty()) {
    1050          10 :     nsDOMMutationObserver::LeaveMutationHandling();
    1051             :     // Nothing to do.
    1052          10 :     return;
    1053             :   }
    1054             : 
    1055           0 :   uint32_t len = mObservers.Length();
    1056           0 :   for (uint32_t i = 0; i < len; ++i) {
    1057           0 :     nsDOMMutationObserver* ob = mObservers[i].mObserver;
    1058           0 :     bool wantsChildList = mObservers[i].mWantsChildList;
    1059             : 
    1060           0 :     RefPtr<nsSimpleContentList> removedList;
    1061           0 :     if (wantsChildList) {
    1062           0 :       removedList = new nsSimpleContentList(mBatchTarget);
    1063             :     }
    1064             : 
    1065           0 :     nsTArray<nsMutationReceiver*> allObservers;
    1066           0 :     ob->GetAllSubtreeObserversFor(mBatchTarget, allObservers);
    1067             : 
    1068           0 :     int32_t j = mFromFirstToLast ? 0 : mRemovedNodes.Length() - 1;
    1069           0 :     int32_t end = mFromFirstToLast ? mRemovedNodes.Length() : -1;
    1070           0 :     for (; j != end; mFromFirstToLast ? ++j : --j) {
    1071           0 :       nsCOMPtr<nsIContent> removed = mRemovedNodes[j];
    1072           0 :       if (removedList) {
    1073           0 :         removedList->AppendElement(removed);
    1074             :       }
    1075             : 
    1076           0 :       if (allObservers.Length()) {
    1077             :         nsCOMArray<nsMutationReceiver>* transientReceivers =
    1078           0 :           ob->mTransientReceivers.LookupForAdd(removed).OrInsert(
    1079           0 :             [] () { return new nsCOMArray<nsMutationReceiver>(); });
    1080           0 :         for (uint32_t k = 0; k < allObservers.Length(); ++k) {
    1081           0 :           nsMutationReceiver* r = allObservers[k];
    1082           0 :           nsMutationReceiver* orig = r->GetParent() ? r->GetParent() : r;
    1083           0 :           if (ob->GetReceiverFor(removed, false, false) != orig) {
    1084             :             // Make sure the elements which are removed from the
    1085             :             // subtree are kept in the same observation set.
    1086             :             nsMutationReceiver* tr;
    1087           0 :             if (orig->Animations()) {
    1088           0 :               tr = nsAnimationReceiver::Create(removed, orig);
    1089             :             } else {
    1090           0 :               tr = nsMutationReceiver::Create(removed, orig);
    1091             :             }
    1092           0 :             transientReceivers->AppendObject(tr);
    1093             :           }
    1094             :         }
    1095             :       }
    1096             :     }
    1097           0 :     if (wantsChildList && (mRemovedNodes.Length() || mAddedNodes.Length())) {
    1098             :       RefPtr<nsSimpleContentList> addedList =
    1099           0 :         new nsSimpleContentList(mBatchTarget);
    1100           0 :       for (uint32_t i = 0; i < mAddedNodes.Length(); ++i) {
    1101           0 :         addedList->AppendElement(mAddedNodes[i]);
    1102             :       }
    1103             :       RefPtr<nsDOMMutationRecord> m =
    1104             :         new nsDOMMutationRecord(nsGkAtoms::childList,
    1105           0 :                                 ob->GetParentObject());
    1106           0 :       m->mTarget = mBatchTarget;
    1107           0 :       m->mRemovedNodes = removedList;
    1108           0 :       m->mAddedNodes = addedList;
    1109           0 :       m->mPreviousSibling = mPrevSibling;
    1110           0 :       m->mNextSibling = mNextSibling;
    1111           0 :       ob->AppendMutationRecord(m.forget());
    1112             :     }
    1113             :     // Always schedule the observer so that transient receivers are
    1114             :     // removed correctly.
    1115           0 :     ob->ScheduleForRun();
    1116             :   }
    1117           0 :   nsDOMMutationObserver::LeaveMutationHandling();
    1118             : }
    1119             : 
    1120             : nsAutoAnimationMutationBatch*
    1121             : nsAutoAnimationMutationBatch::sCurrentBatch = nullptr;
    1122             : 
    1123             : void
    1124          86 : nsAutoAnimationMutationBatch::Done()
    1125             : {
    1126          86 :   if (sCurrentBatch != this) {
    1127          13 :     return;
    1128             :   }
    1129             : 
    1130          73 :   sCurrentBatch = nullptr;
    1131          73 :   if (mObservers.IsEmpty()) {
    1132          73 :     nsDOMMutationObserver::LeaveMutationHandling();
    1133             :     // Nothing to do.
    1134          73 :     return;
    1135             :   }
    1136             : 
    1137           0 :   mBatchTargets.Sort(TreeOrderComparator());
    1138             : 
    1139           0 :   for (nsDOMMutationObserver* ob : mObservers) {
    1140           0 :     bool didAddRecords = false;
    1141             : 
    1142           0 :     for (nsINode* target : mBatchTargets) {
    1143           0 :       EntryArray* entries = mEntryTable.Get(target);
    1144           0 :       MOZ_ASSERT(entries,
    1145             :         "Targets in entry table and targets list should match");
    1146             : 
    1147             :       RefPtr<nsDOMMutationRecord> m =
    1148           0 :         new nsDOMMutationRecord(nsGkAtoms::animations, ob->GetParentObject());
    1149           0 :       m->mTarget = target;
    1150             : 
    1151           0 :       for (const Entry& e : *entries) {
    1152           0 :         if (e.mState == eState_Added) {
    1153           0 :           m->mAddedAnimations.AppendElement(e.mAnimation);
    1154           0 :         } else if (e.mState == eState_Removed) {
    1155           0 :           m->mRemovedAnimations.AppendElement(e.mAnimation);
    1156           0 :         } else if (e.mState == eState_RemainedPresent && e.mChanged) {
    1157           0 :           m->mChangedAnimations.AppendElement(e.mAnimation);
    1158             :         }
    1159             :       }
    1160             : 
    1161           0 :       if (!m->mAddedAnimations.IsEmpty() ||
    1162           0 :           !m->mChangedAnimations.IsEmpty() ||
    1163           0 :           !m->mRemovedAnimations.IsEmpty()) {
    1164           0 :         ob->AppendMutationRecord(m.forget());
    1165           0 :         didAddRecords = true;
    1166             :       }
    1167             :     }
    1168             : 
    1169           0 :     if (didAddRecords) {
    1170           0 :       ob->ScheduleForRun();
    1171             :     }
    1172             :   }
    1173           0 :   nsDOMMutationObserver::LeaveMutationHandling();
    1174             : }

Generated by: LCOV version 1.13