LCOV - code coverage report
Current view: top level - dom/base - nsDOMMutationObserver.h (source / functions) Hit Total Coverage
Test: output.info Lines: 122 357 34.2 %
Date: 2017-07-14 16:53:18 Functions: 37 113 32.7 %
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             : #ifndef nsDOMMutationObserver_h
       8             : #define nsDOMMutationObserver_h
       9             : 
      10             : #include "mozilla/Attributes.h"
      11             : #include "mozilla/Move.h"
      12             : #include "nsCycleCollectionParticipant.h"
      13             : #include "nsPIDOMWindow.h"
      14             : #include "nsIScriptContext.h"
      15             : #include "nsStubAnimationObserver.h"
      16             : #include "nsCOMArray.h"
      17             : #include "nsTArray.h"
      18             : #include "nsIVariant.h"
      19             : #include "nsContentList.h"
      20             : #include "mozilla/dom/Element.h"
      21             : #include "nsClassHashtable.h"
      22             : #include "nsNodeUtils.h"
      23             : #include "nsIDOMMutationEvent.h"
      24             : #include "nsWrapperCache.h"
      25             : #include "mozilla/dom/MutationObserverBinding.h"
      26             : #include "nsIDocument.h"
      27             : #include "mozilla/dom/Animation.h"
      28             : #include "nsIAnimationObserver.h"
      29             : 
      30             : class nsDOMMutationObserver;
      31             : using mozilla::dom::MutationObservingInfo;
      32             : 
      33             : class nsDOMMutationRecord final : public nsISupports,
      34             :                                   public nsWrapperCache
      35             : {
      36           0 :   virtual ~nsDOMMutationRecord() {}
      37             : 
      38             : public:
      39             :   typedef nsTArray<RefPtr<mozilla::dom::Animation>> AnimationArray;
      40             : 
      41           0 :   nsDOMMutationRecord(nsIAtom* aType, nsISupports* aOwner)
      42           0 :   : mType(aType), mAttrNamespace(NullString()), mPrevValue(NullString()), mOwner(aOwner)
      43             :   {
      44           0 :   }
      45             : 
      46           0 :   nsISupports* GetParentObject() const
      47             :   {
      48           0 :     return mOwner;
      49             :   }
      50             : 
      51           0 :   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
      52             :   {
      53           0 :     return mozilla::dom::MutationRecordBinding::Wrap(aCx, this, aGivenProto);
      54             :   }
      55             : 
      56             :   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
      57           1 :   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMMutationRecord)
      58             : 
      59           0 :   void GetType(mozilla::dom::DOMString& aRetVal) const
      60             :   {
      61           0 :     aRetVal.SetOwnedAtom(mType, mozilla::dom::DOMString::eNullNotExpected);
      62           0 :   }
      63             : 
      64           0 :   nsINode* GetTarget() const
      65             :   {
      66           0 :     return mTarget;
      67             :   }
      68             : 
      69             :   nsINodeList* AddedNodes();
      70             : 
      71             :   nsINodeList* RemovedNodes();
      72             : 
      73           0 :   nsINode* GetPreviousSibling() const
      74             :   {
      75           0 :     return mPreviousSibling;
      76             :   }
      77             : 
      78           0 :   nsINode* GetNextSibling() const
      79             :   {
      80           0 :     return mNextSibling;
      81             :   }
      82             : 
      83           0 :   void GetAttributeName(mozilla::dom::DOMString& aRetVal) const
      84             :   {
      85           0 :     aRetVal.SetOwnedAtom(mAttrName, mozilla::dom::DOMString::eTreatNullAsNull);
      86           0 :   }
      87             : 
      88           0 :   void GetAttributeNamespace(mozilla::dom::DOMString& aRetVal) const
      89             :   {
      90           0 :     aRetVal.SetOwnedString(mAttrNamespace);
      91           0 :   }
      92             : 
      93           0 :   void GetOldValue(mozilla::dom::DOMString& aRetVal) const
      94             :   {
      95           0 :     aRetVal.SetOwnedString(mPrevValue);
      96           0 :   }
      97             : 
      98           0 :   void GetAddedAnimations(AnimationArray& aRetVal) const
      99             :   {
     100           0 :     aRetVal = mAddedAnimations;
     101           0 :   }
     102             : 
     103           0 :   void GetRemovedAnimations(AnimationArray& aRetVal) const
     104             :   {
     105           0 :     aRetVal = mRemovedAnimations;
     106           0 :   }
     107             : 
     108           0 :   void GetChangedAnimations(AnimationArray& aRetVal) const
     109             :   {
     110           0 :     aRetVal = mChangedAnimations;
     111           0 :   }
     112             : 
     113             :   nsCOMPtr<nsINode>             mTarget;
     114             :   nsCOMPtr<nsIAtom>             mType;
     115             :   nsCOMPtr<nsIAtom>             mAttrName;
     116             :   nsString                      mAttrNamespace;
     117             :   nsString                      mPrevValue;
     118             :   RefPtr<nsSimpleContentList> mAddedNodes;
     119             :   RefPtr<nsSimpleContentList> mRemovedNodes;
     120             :   nsCOMPtr<nsINode>             mPreviousSibling;
     121             :   nsCOMPtr<nsINode>             mNextSibling;
     122             :   AnimationArray                mAddedAnimations;
     123             :   AnimationArray                mRemovedAnimations;
     124             :   AnimationArray                mChangedAnimations;
     125             : 
     126             :   RefPtr<nsDOMMutationRecord> mNext;
     127             :   nsCOMPtr<nsISupports>         mOwner;
     128             : };
     129             : 
     130             : // Base class just prevents direct access to
     131             : // members to make sure we go through getters/setters.
     132             : class nsMutationReceiverBase : public nsStubAnimationObserver
     133             : {
     134             : public:
     135           0 :   virtual ~nsMutationReceiverBase() { }
     136             : 
     137             :   nsDOMMutationObserver* Observer();
     138           1 :   nsINode* Target() { return mParent ? mParent->Target() : mTarget; }
     139           0 :   nsINode* RegisterTarget() { return mRegisterTarget; }
     140             : 
     141           0 :   bool Subtree() { return mParent ? mParent->Subtree() : mSubtree; }
     142           1 :   void SetSubtree(bool aSubtree)
     143             :   {
     144           1 :     NS_ASSERTION(!mParent, "Shouldn't have parent");
     145           1 :     mSubtree = aSubtree;
     146           1 :   }
     147             : 
     148           0 :   bool ChildList() { return mParent ? mParent->ChildList() : mChildList; }
     149           1 :   void SetChildList(bool aChildList)
     150             :   {
     151           1 :     NS_ASSERTION(!mParent, "Shouldn't have parent");
     152           1 :     mChildList = aChildList;
     153           1 :   }
     154             : 
     155           0 :   bool CharacterData()
     156             :   {
     157           0 :     return mParent ? mParent->CharacterData() : mCharacterData;
     158             :   }
     159           1 :   void SetCharacterData(bool aCharacterData)
     160             :   {
     161           1 :     NS_ASSERTION(!mParent, "Shouldn't have parent");
     162           1 :     mCharacterData = aCharacterData;
     163           1 :   }
     164             : 
     165           0 :   bool CharacterDataOldValue()
     166             :   {
     167           0 :     return mParent ? mParent->CharacterDataOldValue() : mCharacterDataOldValue;
     168             :   }
     169           1 :   void SetCharacterDataOldValue(bool aOldValue)
     170             :   {
     171           1 :     NS_ASSERTION(!mParent, "Shouldn't have parent");
     172           1 :     mCharacterDataOldValue = aOldValue;
     173           1 :   }
     174             : 
     175           0 :   bool NativeAnonymousChildList()
     176             :   {
     177           0 :     return mParent ? mParent->NativeAnonymousChildList() : mNativeAnonymousChildList;
     178             :   }
     179           1 :   void SetNativeAnonymousChildList(bool aOldValue)
     180             :   {
     181           1 :     NS_ASSERTION(!mParent, "Shouldn't have parent");
     182           1 :     mNativeAnonymousChildList = aOldValue;
     183           1 :   }
     184             : 
     185           0 :   bool Attributes() { return mParent ? mParent->Attributes() : mAttributes; }
     186           1 :   void SetAttributes(bool aAttributes)
     187             :   {
     188           1 :     NS_ASSERTION(!mParent, "Shouldn't have parent");
     189           1 :     mAttributes = aAttributes;
     190           1 :   }
     191             : 
     192           0 :   bool AllAttributes()
     193             :   {
     194           0 :     return mParent ? mParent->AllAttributes()
     195           0 :                    : mAllAttributes;
     196             :   }
     197           1 :   void SetAllAttributes(bool aAll)
     198             :   {
     199           1 :     NS_ASSERTION(!mParent, "Shouldn't have parent");
     200           1 :     mAllAttributes = aAll;
     201           1 :   }
     202             : 
     203           0 :   bool Animations() { return mParent ? mParent->Animations() : mAnimations; }
     204           1 :   void SetAnimations(bool aAnimations)
     205             :   {
     206           1 :     NS_ASSERTION(!mParent, "Shouldn't have parent");
     207           1 :     mAnimations = aAnimations;
     208           1 :   }
     209             : 
     210           0 :   bool AttributeOldValue() {
     211           0 :     return mParent ? mParent->AttributeOldValue()
     212           0 :                    : mAttributeOldValue;
     213             :   }
     214           1 :   void SetAttributeOldValue(bool aOldValue)
     215             :   {
     216           1 :     NS_ASSERTION(!mParent, "Shouldn't have parent");
     217           1 :     mAttributeOldValue = aOldValue;
     218           1 :   }
     219             : 
     220           0 :   nsCOMArray<nsIAtom>& AttributeFilter() { return mAttributeFilter; }
     221           1 :   void SetAttributeFilter(nsCOMArray<nsIAtom>&& aFilter)
     222             :   {
     223           1 :     NS_ASSERTION(!mParent, "Shouldn't have parent");
     224           1 :     mAttributeFilter.Clear();
     225           1 :     mAttributeFilter = mozilla::Move(aFilter);
     226           1 :   }
     227             : 
     228           0 :   void AddClone(nsMutationReceiverBase* aClone)
     229             :   {
     230           0 :     mTransientReceivers.AppendObject(aClone);
     231           0 :   }
     232             : 
     233             :   void RemoveClone(nsMutationReceiverBase* aClone)
     234             :   {
     235             :     mTransientReceivers.RemoveObject(aClone);
     236             :   }
     237             : 
     238             : protected:
     239           1 :   nsMutationReceiverBase(nsINode* aTarget, nsDOMMutationObserver* aObserver)
     240           1 :     : mTarget(aTarget)
     241             :     , mObserver(aObserver)
     242             :     , mRegisterTarget(aTarget)
     243             :     , mSubtree(false)
     244             :     , mChildList(false)
     245             :     , mCharacterData(false)
     246             :     , mCharacterDataOldValue(false)
     247             :     , mNativeAnonymousChildList(false)
     248             :     , mAttributes(false)
     249             :     , mAllAttributes(false)
     250             :     , mAttributeOldValue(false)
     251           1 :     , mAnimations(false)
     252             :   {
     253           1 :   }
     254             : 
     255           0 :   nsMutationReceiverBase(nsINode* aRegisterTarget,
     256             :                          nsMutationReceiverBase* aParent)
     257           0 :     : mTarget(nullptr)
     258             :     , mObserver(nullptr)
     259             :     , mParent(aParent)
     260             :     , mRegisterTarget(aRegisterTarget)
     261             :     , mKungFuDeathGrip(aParent->Target())
     262             :     , mSubtree(false)
     263             :     , mChildList(false)
     264             :     , mCharacterData(false)
     265             :     , mCharacterDataOldValue(false)
     266             :     , mNativeAnonymousChildList(false)
     267             :     , mAttributes(false)
     268             :     , mAllAttributes(false)
     269             :     , mAttributeOldValue(false)
     270           0 :     , mAnimations(false)
     271             :   {
     272           0 :     NS_ASSERTION(mParent->Subtree(), "Should clone a non-subtree observer!");
     273           0 :   }
     274             : 
     275             :   virtual void AddMutationObserver() = 0;
     276             : 
     277           1 :   void AddObserver()
     278             :   {
     279           1 :     AddMutationObserver();
     280           1 :     mRegisterTarget->SetMayHaveDOMMutationObserver();
     281           1 :     mRegisterTarget->OwnerDoc()->SetMayHaveDOMMutationObservers();
     282           1 :   }
     283             : 
     284             :   bool IsObservable(nsIContent* aContent);
     285             : 
     286           0 :   bool ObservesAttr(nsINode* aRegisterTarget,
     287             :                     mozilla::dom::Element* aElement,
     288             :                     int32_t aNameSpaceID,
     289             :                     nsIAtom* aAttr)
     290             :   {
     291           0 :     if (mParent) {
     292           0 :       return mParent->ObservesAttr(aRegisterTarget, aElement, aNameSpaceID, aAttr);
     293             :     }
     294           0 :     if (!Attributes() ||
     295           0 :         (!Subtree() && aElement != Target()) ||
     296           0 :         (Subtree() && aRegisterTarget->SubtreeRoot() != aElement->SubtreeRoot()) ||
     297           0 :         !IsObservable(aElement)) {
     298           0 :       return false;
     299             :     }
     300           0 :     if (AllAttributes()) {
     301           0 :       return true;
     302             :     }
     303             : 
     304           0 :     if (aNameSpaceID != kNameSpaceID_None) {
     305           0 :       return false;
     306             :     }
     307             : 
     308           0 :     nsCOMArray<nsIAtom>& filters = AttributeFilter();
     309           0 :     for (int32_t i = 0; i < filters.Count(); ++i) {
     310           0 :       if (filters[i] == aAttr) {
     311           0 :         return true;
     312             :       }
     313             :     }
     314           0 :     return false;
     315             :   }
     316             : 
     317             :   // The target for the MutationObserver.observe() method.
     318             :   nsINode*                           mTarget;
     319             :   nsDOMMutationObserver*             mObserver;
     320             :   RefPtr<nsMutationReceiverBase>   mParent; // Cleared after microtask.
     321             :   // The node to which Gecko-internal nsIMutationObserver was registered to.
     322             :   // This is different than mTarget when dealing with transient observers.
     323             :   nsINode*                           mRegisterTarget;
     324             :   nsCOMArray<nsMutationReceiverBase> mTransientReceivers;
     325             :   // While we have transient receivers, keep the original mutation receiver
     326             :   // alive so it doesn't go away and disconnect all its transient receivers.
     327             :   nsCOMPtr<nsINode>                  mKungFuDeathGrip;
     328             : 
     329             : private:
     330             :   bool                               mSubtree;
     331             :   bool                               mChildList;
     332             :   bool                               mCharacterData;
     333             :   bool                               mCharacterDataOldValue;
     334             :   bool                               mNativeAnonymousChildList;
     335             :   bool                               mAttributes;
     336             :   bool                               mAllAttributes;
     337             :   bool                               mAttributeOldValue;
     338             :   bool                               mAnimations;
     339             :   nsCOMArray<nsIAtom>                mAttributeFilter;
     340             : };
     341             : 
     342             : 
     343             : class nsMutationReceiver : public nsMutationReceiverBase
     344             : {
     345             : protected:
     346           0 :   virtual ~nsMutationReceiver() { Disconnect(false); }
     347             : 
     348             : public:
     349           1 :   static nsMutationReceiver* Create(nsINode* aTarget,
     350             :                                     nsDOMMutationObserver* aObserver)
     351             :   {
     352           1 :     nsMutationReceiver* r = new nsMutationReceiver(aTarget, aObserver);
     353           1 :     r->AddObserver();
     354           1 :     return r;
     355             :   }
     356             : 
     357           0 :   static nsMutationReceiver* Create(nsINode* aRegisterTarget,
     358             :                                     nsMutationReceiverBase* aParent)
     359             :   {
     360           0 :     nsMutationReceiver* r = new nsMutationReceiver(aRegisterTarget, aParent);
     361           0 :     aParent->AddClone(r);
     362           0 :     r->AddObserver();
     363           0 :     return r;
     364             :   }
     365             : 
     366           0 :   nsMutationReceiver* GetParent()
     367             :   {
     368           0 :     return static_cast<nsMutationReceiver*>(mParent.get());
     369             :   }
     370             : 
     371           1 :   void RemoveClones()
     372             :   {
     373           1 :     for (int32_t i = 0; i < mTransientReceivers.Count(); ++i) {
     374             :       nsMutationReceiver* r =
     375           0 :         static_cast<nsMutationReceiver*>(mTransientReceivers[i]);
     376           0 :       r->DisconnectTransientReceiver();
     377             :     }
     378           1 :     mTransientReceivers.Clear();
     379           1 :   }
     380             : 
     381           0 :   void DisconnectTransientReceiver()
     382             :   {
     383           0 :     if (mRegisterTarget) {
     384           0 :       mRegisterTarget->RemoveMutationObserver(this);
     385           0 :       mRegisterTarget = nullptr;
     386             :     }
     387             : 
     388           0 :     mParent = nullptr;
     389           0 :     NS_ASSERTION(!mTarget, "Should not have mTarget");
     390           0 :     NS_ASSERTION(!mObserver, "Should not have mObserver");
     391           0 :   }
     392             : 
     393             :   void Disconnect(bool aRemoveFromObserver);
     394             : 
     395             :   NS_DECL_ISUPPORTS
     396             : 
     397             :   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE
     398             :   NS_DECL_NSIMUTATIONOBSERVER_NATIVEANONYMOUSCHILDLISTCHANGE
     399             :   NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATAWILLCHANGE
     400             :   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
     401             :   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
     402             :   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
     403             :   NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
     404             : 
     405           0 :   virtual void AttributeSetToCurrentValue(nsIDocument* aDocument,
     406             :                                           mozilla::dom::Element* aElement,
     407             :                                           int32_t aNameSpaceID,
     408             :                                           nsIAtom* aAttribute) override
     409             :   {
     410             :     // We can reuse AttributeWillChange implementation.
     411             :     AttributeWillChange(aDocument, aElement, aNameSpaceID, aAttribute,
     412           0 :                         nsIDOMMutationEvent::MODIFICATION, nullptr);
     413           0 :   }
     414             : 
     415             : protected:
     416             :   nsMutationReceiver(nsINode* aTarget, nsDOMMutationObserver* aObserver);
     417             : 
     418           0 :   nsMutationReceiver(nsINode* aRegisterTarget, nsMutationReceiverBase* aParent)
     419           0 :   : nsMutationReceiverBase(aRegisterTarget, aParent)
     420             :   {
     421           0 :     NS_ASSERTION(!static_cast<nsMutationReceiver*>(aParent)->GetParent(),
     422             :                  "Shouldn't create deep observer hierarchies!");
     423           0 :   }
     424             : 
     425           1 :   virtual void AddMutationObserver() override
     426             :   {
     427           1 :     mRegisterTarget->AddMutationObserver(this);
     428           1 :   }
     429             : };
     430             : 
     431             : class nsAnimationReceiver : public nsMutationReceiver
     432             : {
     433             : public:
     434           0 :   static nsAnimationReceiver* Create(nsINode* aTarget,
     435             :                                      nsDOMMutationObserver* aObserver)
     436             :   {
     437           0 :     nsAnimationReceiver* r = new nsAnimationReceiver(aTarget, aObserver);
     438           0 :     r->AddObserver();
     439           0 :     return r;
     440             :   }
     441             : 
     442           0 :   static nsAnimationReceiver* Create(nsINode* aRegisterTarget,
     443             :                                      nsMutationReceiverBase* aParent)
     444             :   {
     445           0 :     nsAnimationReceiver* r = new nsAnimationReceiver(aRegisterTarget, aParent);
     446           0 :     aParent->AddClone(r);
     447           0 :     r->AddObserver();
     448           0 :     return r;
     449             :   }
     450             : 
     451             :   NS_DECL_ISUPPORTS_INHERITED
     452             : 
     453             :   NS_DECL_NSIANIMATIONOBSERVER_ANIMATIONADDED
     454             :   NS_DECL_NSIANIMATIONOBSERVER_ANIMATIONCHANGED
     455             :   NS_DECL_NSIANIMATIONOBSERVER_ANIMATIONREMOVED
     456             : 
     457             : protected:
     458           0 :   virtual ~nsAnimationReceiver() {}
     459             : 
     460           0 :   nsAnimationReceiver(nsINode* aTarget, nsDOMMutationObserver* aObserver)
     461           0 :     : nsMutationReceiver(aTarget, aObserver) {}
     462             : 
     463           0 :   nsAnimationReceiver(nsINode* aRegisterTarget, nsMutationReceiverBase* aParent)
     464           0 :     : nsMutationReceiver(aRegisterTarget, aParent) {}
     465             : 
     466           0 :   virtual void AddMutationObserver() override
     467             :   {
     468           0 :     mRegisterTarget->AddAnimationObserver(this);
     469           0 :   }
     470             : 
     471             : private:
     472             :   enum AnimationMutation {
     473             :     eAnimationMutation_Added,
     474             :     eAnimationMutation_Changed,
     475             :     eAnimationMutation_Removed
     476             :   };
     477             : 
     478             :   void RecordAnimationMutation(mozilla::dom::Animation* aAnimation,
     479             :                                AnimationMutation aMutationType);
     480             : };
     481             : 
     482             : #define NS_DOM_MUTATION_OBSERVER_IID \
     483             : { 0x0c3b91f8, 0xcc3b, 0x4b08, \
     484             :   { 0x9e, 0xab, 0x07, 0x47, 0xa9, 0xe4, 0x65, 0xb4 } }
     485             : 
     486             : class nsDOMMutationObserver final : public nsISupports,
     487             :                                     public nsWrapperCache
     488             : {
     489             : public:
     490           1 :   nsDOMMutationObserver(already_AddRefed<nsPIDOMWindowInner>&& aOwner,
     491             :                         mozilla::dom::MutationCallback& aCb,
     492             :                         bool aChrome)
     493           1 :   : mOwner(aOwner), mLastPendingMutation(nullptr), mPendingMutationCount(0),
     494             :     mCallback(&aCb), mWaitingForRun(false), mIsChrome(aChrome),
     495           1 :     mMergeAttributeRecords(false), mId(++sCount)
     496             :   {
     497           1 :   }
     498             :   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     499          20 :   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMMutationObserver)
     500             :   NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOM_MUTATION_OBSERVER_IID)
     501             : 
     502             :   static already_AddRefed<nsDOMMutationObserver>
     503             :   Constructor(const mozilla::dom::GlobalObject& aGlobal,
     504             :               mozilla::dom::MutationCallback& aCb,
     505             :               mozilla::ErrorResult& aRv);
     506             : 
     507           1 :   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
     508             :   {
     509           1 :     return mozilla::dom::MutationObserverBinding::Wrap(aCx, this, aGivenProto);
     510             :   }
     511             : 
     512           1 :   nsISupports* GetParentObject() const
     513             :   {
     514           1 :     return mOwner;
     515             :   }
     516             : 
     517           0 :   bool IsChrome()
     518             :   {
     519           0 :     return mIsChrome;
     520             :   }
     521             : 
     522             :   void Observe(nsINode& aTarget,
     523             :                const mozilla::dom::MutationObserverInit& aOptions,
     524             :                mozilla::ErrorResult& aRv);
     525             : 
     526             :   void Disconnect();
     527             : 
     528             :   void TakeRecords(nsTArray<RefPtr<nsDOMMutationRecord> >& aRetVal);
     529             : 
     530             :   void HandleMutation();
     531             : 
     532             :   void GetObservingInfo(nsTArray<Nullable<MutationObservingInfo>>& aResult,
     533             :                         mozilla::ErrorResult& aRv);
     534             : 
     535           0 :   mozilla::dom::MutationCallback* MutationCallback() { return mCallback; }
     536             : 
     537           0 :   bool MergeAttributeRecords()
     538             :   {
     539           0 :     return mMergeAttributeRecords;
     540             :   }
     541             : 
     542           0 :   void SetMergeAttributeRecords(bool aVal)
     543             :   {
     544           0 :     mMergeAttributeRecords = aVal;
     545           0 :   }
     546             : 
     547             :   // If both records are for 'attributes' type and for the same target and
     548             :   // attribute name and namespace are the same, we can skip the newer record.
     549             :   // aOldRecord->mPrevValue holds the original value, if observed.
     550             :   bool MergeableAttributeRecord(nsDOMMutationRecord* aOldRecord,
     551             :                                 nsDOMMutationRecord* aRecord);
     552             : 
     553           0 :   void AppendMutationRecord(already_AddRefed<nsDOMMutationRecord> aRecord)
     554             :   {
     555           0 :     RefPtr<nsDOMMutationRecord> record = aRecord;
     556           0 :     MOZ_ASSERT(record);
     557           0 :     if (!mLastPendingMutation) {
     558           0 :       MOZ_ASSERT(!mFirstPendingMutation);
     559           0 :       mFirstPendingMutation = record.forget();
     560           0 :       mLastPendingMutation = mFirstPendingMutation;
     561             :     } else {
     562           0 :       MOZ_ASSERT(mFirstPendingMutation);
     563           0 :       mLastPendingMutation->mNext = record.forget();
     564           0 :       mLastPendingMutation = mLastPendingMutation->mNext;
     565             :     }
     566           0 :     ++mPendingMutationCount;
     567           0 :   }
     568             : 
     569           0 :   void ClearPendingRecords()
     570             :   {
     571           0 :     mFirstPendingMutation = nullptr;
     572           0 :     mLastPendingMutation = nullptr;
     573           0 :     mPendingMutationCount = 0;
     574           0 :   }
     575             : 
     576             :   // static methods
     577        1733 :   static void HandleMutations()
     578             :   {
     579        1733 :     if (sScheduledMutationObservers) {
     580           0 :       HandleMutationsInternal();
     581             :     }
     582        1733 :   }
     583             : 
     584             :   static void EnterMutationHandling();
     585             :   static void LeaveMutationHandling();
     586             : 
     587             :   static void Shutdown();
     588             : protected:
     589             :   virtual ~nsDOMMutationObserver();
     590             : 
     591             :   friend class nsMutationReceiver;
     592             :   friend class nsAnimationReceiver;
     593             :   friend class nsAutoMutationBatch;
     594             :   friend class nsAutoAnimationMutationBatch;
     595             :   nsMutationReceiver* GetReceiverFor(nsINode* aNode,
     596             :                                      bool aMayCreate,
     597             :                                      bool aWantsAnimations);
     598             :   void RemoveReceiver(nsMutationReceiver* aReceiver);
     599             : 
     600             :   already_AddRefed<nsIVariant> TakeRecords();
     601             : 
     602             :   void GetAllSubtreeObserversFor(nsINode* aNode,
     603             :                                  nsTArray<nsMutationReceiver*>& aObservers);
     604             :   void ScheduleForRun();
     605             :   void RescheduleForRun();
     606             : 
     607             :   nsDOMMutationRecord* CurrentRecord(nsIAtom* aType);
     608             :   bool HasCurrentRecord(const nsAString& aType);
     609             : 
     610           0 :   bool Suppressed()
     611             :   {
     612           0 :     if (mOwner) {
     613           0 :       nsCOMPtr<nsIDocument> d = mOwner->GetExtantDoc();
     614           0 :       return d && d->IsInSyncOperation();
     615             :     }
     616           0 :     return false;
     617             :   }
     618             : 
     619             :   static void HandleMutationsInternal();
     620             : 
     621             :   static void AddCurrentlyHandlingObserver(nsDOMMutationObserver* aObserver,
     622             :                                            uint32_t aMutationLevel);
     623             : 
     624             :   nsCOMPtr<nsPIDOMWindowInner>                       mOwner;
     625             : 
     626             :   nsCOMArray<nsMutationReceiver>                     mReceivers;
     627             :   nsClassHashtable<nsISupportsHashKey,
     628             :                    nsCOMArray<nsMutationReceiver> >  mTransientReceivers;
     629             :   // MutationRecords which are being constructed.
     630             :   AutoTArray<nsDOMMutationRecord*, 4>              mCurrentMutations;
     631             :   // MutationRecords which will be handed to the callback at the end of
     632             :   // the microtask.
     633             :   RefPtr<nsDOMMutationRecord>                      mFirstPendingMutation;
     634             :   nsDOMMutationRecord*                               mLastPendingMutation;
     635             :   uint32_t                                           mPendingMutationCount;
     636             : 
     637             :   RefPtr<mozilla::dom::MutationCallback>           mCallback;
     638             : 
     639             :   bool                                               mWaitingForRun;
     640             :   bool                                               mIsChrome;
     641             :   bool                                               mMergeAttributeRecords;
     642             : 
     643             :   uint64_t                                           mId;
     644             : 
     645             :   static uint64_t                                    sCount;
     646             :   static AutoTArray<RefPtr<nsDOMMutationObserver>, 4>* sScheduledMutationObservers;
     647             :   static nsDOMMutationObserver*                      sCurrentObserver;
     648             : 
     649             :   static uint32_t                                    sMutationLevel;
     650             :   static AutoTArray<AutoTArray<RefPtr<nsDOMMutationObserver>, 4>, 4>*
     651             :                                                      sCurrentlyHandlingObservers;
     652             : };
     653             : 
     654             : NS_DEFINE_STATIC_IID_ACCESSOR(nsDOMMutationObserver, NS_DOM_MUTATION_OBSERVER_IID)
     655             : 
     656             : class nsAutoMutationBatch
     657             : {
     658             : public:
     659          96 :   nsAutoMutationBatch()
     660          96 :   : mPreviousBatch(nullptr), mBatchTarget(nullptr), mRemovalDone(false),
     661          96 :     mFromFirstToLast(false), mAllowNestedBatches(false)
     662             :   {
     663          96 :   }
     664             : 
     665           7 :   nsAutoMutationBatch(nsINode* aTarget, bool aFromFirstToLast,
     666             :                       bool aAllowNestedBatches)
     667           7 :   : mPreviousBatch(nullptr), mBatchTarget(nullptr), mRemovalDone(false),
     668           7 :     mFromFirstToLast(false), mAllowNestedBatches(false)
     669             :   {
     670           7 :     Init(aTarget, aFromFirstToLast, aAllowNestedBatches);
     671           7 :   }
     672             : 
     673          13 :   void Init(nsINode* aTarget, bool aFromFirstToLast, bool aAllowNestedBatches)
     674             :   {
     675          13 :     if (aTarget && aTarget->OwnerDoc()->MayHaveDOMMutationObservers()) {
     676          10 :       if (sCurrentBatch && !sCurrentBatch->mAllowNestedBatches) {
     677           0 :         return;
     678             :       }
     679          10 :       mBatchTarget = aTarget;
     680          10 :       mFromFirstToLast = aFromFirstToLast;
     681          10 :       mAllowNestedBatches = aAllowNestedBatches;
     682          10 :       mPreviousBatch = sCurrentBatch;
     683          10 :       sCurrentBatch = this;
     684          10 :       nsDOMMutationObserver::EnterMutationHandling();
     685             :     }
     686             :   }
     687             : 
     688           8 :   void RemovalDone() { mRemovalDone = true; }
     689           0 :   static bool IsRemovalDone() { return sCurrentBatch->mRemovalDone; }
     690             : 
     691           6 :   void SetPrevSibling(nsINode* aNode) { mPrevSibling = aNode; }
     692           6 :   void SetNextSibling(nsINode* aNode) { mNextSibling = aNode; }
     693             : 
     694             :   void Done();
     695             : 
     696         103 :   ~nsAutoMutationBatch() { NodesAdded(); }
     697             : 
     698           0 :   static bool IsBatching()
     699             :   {
     700           0 :     return !!sCurrentBatch;
     701             :   }
     702             : 
     703          97 :   static nsAutoMutationBatch* GetCurrentBatch()
     704             :   {
     705          97 :     return sCurrentBatch;
     706             :   }
     707             : 
     708           0 :   static void UpdateObserver(nsDOMMutationObserver* aObserver,
     709             :                              bool aWantsChildList)
     710             :   {
     711           0 :     uint32_t l = sCurrentBatch->mObservers.Length();
     712           0 :     for (uint32_t i = 0; i < l; ++i) {
     713           0 :       if (sCurrentBatch->mObservers[i].mObserver == aObserver) {
     714           0 :         if (aWantsChildList) {
     715           0 :           sCurrentBatch->mObservers[i].mWantsChildList = aWantsChildList;
     716             :         }
     717           0 :         return;
     718             :       }
     719             :     }
     720           0 :     BatchObserver* bo = sCurrentBatch->mObservers.AppendElement();
     721           0 :     bo->mObserver = aObserver;
     722           0 :     bo->mWantsChildList = aWantsChildList;
     723             :   }
     724             : 
     725             : 
     726           0 :   static nsINode* GetBatchTarget() { return sCurrentBatch->mBatchTarget; }
     727             : 
     728             :   // Mutation receivers notify the batch about removed child nodes.
     729           0 :   static void NodeRemoved(nsIContent* aChild)
     730             :   {
     731           0 :     if (IsBatching() && !sCurrentBatch->mRemovalDone) {
     732           0 :       uint32_t len = sCurrentBatch->mRemovedNodes.Length();
     733           0 :       if (!len ||
     734           0 :           sCurrentBatch->mRemovedNodes[len - 1] != aChild) {
     735           0 :         sCurrentBatch->mRemovedNodes.AppendElement(aChild);
     736             :       }
     737             :     }
     738           0 :   }
     739             : 
     740             :   // Called after new child nodes have been added to the batch target.
     741         109 :   void NodesAdded()
     742             :   {
     743         109 :     if (sCurrentBatch != this) {
     744          99 :       return;
     745             :     }
     746             : 
     747             :     nsIContent* c =
     748          16 :       mPrevSibling ? mPrevSibling->GetNextSibling() :
     749          26 :                      mBatchTarget->GetFirstChild();
     750          82 :     for (; c != mNextSibling; c = c->GetNextSibling()) {
     751          36 :       mAddedNodes.AppendElement(c);
     752             :     }
     753          10 :     Done();
     754             :   }
     755             : 
     756             : private:
     757             :   struct BatchObserver
     758             :   {
     759             :     nsDOMMutationObserver* mObserver;
     760             :     bool                   mWantsChildList;
     761             :   };
     762             : 
     763             :   static nsAutoMutationBatch* sCurrentBatch;
     764             :   nsAutoMutationBatch* mPreviousBatch;
     765             :   AutoTArray<BatchObserver, 2> mObservers;
     766             :   nsTArray<nsCOMPtr<nsIContent> > mRemovedNodes;
     767             :   nsTArray<nsCOMPtr<nsIContent> > mAddedNodes;
     768             :   nsINode* mBatchTarget;
     769             :   bool mRemovalDone;
     770             :   bool mFromFirstToLast;
     771             :   bool mAllowNestedBatches;
     772             :   nsCOMPtr<nsINode> mPrevSibling;
     773             :   nsCOMPtr<nsINode> mNextSibling;
     774             : };
     775             : 
     776             : class nsAutoAnimationMutationBatch
     777             : {
     778             :   struct Entry;
     779             : 
     780             : public:
     781          86 :   explicit nsAutoAnimationMutationBatch(nsIDocument* aDocument)
     782          86 :   {
     783          86 :     Init(aDocument);
     784          86 :   }
     785             : 
     786          86 :   void Init(nsIDocument* aDocument)
     787             :   {
     788         172 :     if (!aDocument ||
     789         159 :         !aDocument->MayHaveDOMMutationObservers() ||
     790          73 :         sCurrentBatch) {
     791          13 :       return;
     792             :     }
     793             : 
     794          73 :     sCurrentBatch = this;
     795          73 :     nsDOMMutationObserver::EnterMutationHandling();
     796             :   }
     797             : 
     798          86 :   ~nsAutoAnimationMutationBatch()
     799          86 :   {
     800          86 :     Done();
     801          86 :   }
     802             : 
     803             :   void Done();
     804             : 
     805           0 :   static bool IsBatching()
     806             :   {
     807           0 :     return !!sCurrentBatch;
     808             :   }
     809             : 
     810             :   static nsAutoAnimationMutationBatch* GetCurrentBatch()
     811             :   {
     812             :     return sCurrentBatch;
     813             :   }
     814             : 
     815           0 :   static void AddObserver(nsDOMMutationObserver* aObserver)
     816             :   {
     817           0 :     if (sCurrentBatch->mObservers.Contains(aObserver)) {
     818           0 :       return;
     819             :     }
     820           0 :     sCurrentBatch->mObservers.AppendElement(aObserver);
     821             :   }
     822             : 
     823           0 :   static void AnimationAdded(mozilla::dom::Animation* aAnimation,
     824             :                              nsINode* aTarget)
     825             :   {
     826           0 :     if (!IsBatching()) {
     827           0 :       return;
     828             :     }
     829             : 
     830           0 :     Entry* entry = sCurrentBatch->FindEntry(aAnimation, aTarget);
     831           0 :     if (entry) {
     832           0 :       switch (entry->mState) {
     833             :         case eState_RemainedAbsent:
     834           0 :           entry->mState = eState_Added;
     835           0 :           break;
     836             :         case eState_Removed:
     837           0 :           entry->mState = eState_RemainedPresent;
     838           0 :           break;
     839             :         default:
     840           0 :           NS_NOTREACHED("shouldn't have observed an animation being added "
     841             :                         "twice");
     842             :       }
     843             :     } else {
     844           0 :       entry = sCurrentBatch->AddEntry(aAnimation, aTarget);
     845           0 :       entry->mState = eState_Added;
     846           0 :       entry->mChanged = false;
     847             :     }
     848             :   }
     849             : 
     850           0 :   static void AnimationChanged(mozilla::dom::Animation* aAnimation,
     851             :                                nsINode* aTarget)
     852             :   {
     853           0 :     Entry* entry = sCurrentBatch->FindEntry(aAnimation, aTarget);
     854           0 :     if (entry) {
     855           0 :       NS_ASSERTION(entry->mState == eState_RemainedPresent ||
     856             :                    entry->mState == eState_Added,
     857             :                    "shouldn't have observed an animation being changed after "
     858             :                    "being removed");
     859           0 :       entry->mChanged = true;
     860             :     } else {
     861           0 :       entry = sCurrentBatch->AddEntry(aAnimation, aTarget);
     862           0 :       entry->mState = eState_RemainedPresent;
     863           0 :       entry->mChanged = true;
     864             :     }
     865           0 :   }
     866             : 
     867           0 :   static void AnimationRemoved(mozilla::dom::Animation* aAnimation,
     868             :                                nsINode* aTarget)
     869             :   {
     870           0 :     Entry* entry = sCurrentBatch->FindEntry(aAnimation, aTarget);
     871           0 :     if (entry) {
     872           0 :       switch (entry->mState) {
     873             :         case eState_RemainedPresent:
     874           0 :           entry->mState = eState_Removed;
     875           0 :           break;
     876             :         case eState_Added:
     877           0 :           entry->mState = eState_RemainedAbsent;
     878           0 :           break;
     879             :         default:
     880           0 :           NS_NOTREACHED("shouldn't have observed an animation being removed "
     881             :                         "twice");
     882             :       }
     883             :     } else {
     884           0 :       entry = sCurrentBatch->AddEntry(aAnimation, aTarget);
     885           0 :       entry->mState = eState_Removed;
     886           0 :       entry->mChanged = false;
     887             :     }
     888           0 :   }
     889             : 
     890             : private:
     891           0 :   Entry* FindEntry(mozilla::dom::Animation* aAnimation, nsINode* aTarget)
     892             :   {
     893           0 :     EntryArray* entries = mEntryTable.Get(aTarget);
     894           0 :     if (!entries) {
     895           0 :       return nullptr;
     896             :     }
     897             : 
     898           0 :     for (Entry& e : *entries) {
     899           0 :       if (e.mAnimation == aAnimation) {
     900           0 :         return &e;
     901             :       }
     902             :     }
     903           0 :     return nullptr;
     904             :   }
     905             : 
     906           0 :   Entry* AddEntry(mozilla::dom::Animation* aAnimation, nsINode* aTarget)
     907             :   {
     908           0 :     EntryArray* entries = sCurrentBatch->mEntryTable.LookupOrAdd(aTarget);
     909           0 :     if (entries->IsEmpty()) {
     910           0 :       sCurrentBatch->mBatchTargets.AppendElement(aTarget);
     911             :     }
     912           0 :     Entry* entry = entries->AppendElement();
     913           0 :     entry->mAnimation = aAnimation;
     914           0 :     return entry;
     915             :   }
     916             : 
     917             :   enum State {
     918             :     eState_RemainedPresent,
     919             :     eState_RemainedAbsent,
     920             :     eState_Added,
     921             :     eState_Removed
     922             :   };
     923             : 
     924           0 :   struct Entry
     925             :   {
     926             :     RefPtr<mozilla::dom::Animation> mAnimation;
     927             :     State mState;
     928             :     bool mChanged;
     929             :   };
     930             : 
     931             :   static nsAutoAnimationMutationBatch* sCurrentBatch;
     932             :   AutoTArray<nsDOMMutationObserver*, 2> mObservers;
     933             :   typedef nsTArray<Entry> EntryArray;
     934             :   nsClassHashtable<nsPtrHashKey<nsINode>, EntryArray> mEntryTable;
     935             :   // List of nodes referred to by mEntryTable so we can sort them
     936             :   // For a specific pseudo element, we use its parent element as the
     937             :   // batch target, so they will be put in the same EntryArray.
     938             :   nsTArray<nsINode*> mBatchTargets;
     939             : };
     940             : 
     941             : inline
     942             : nsDOMMutationObserver*
     943           0 : nsMutationReceiverBase::Observer()
     944             : {
     945           0 :   return mParent ?
     946           0 :     mParent->Observer() : static_cast<nsDOMMutationObserver*>(mObserver);
     947             : }
     948             : 
     949             : #endif

Generated by: LCOV version 1.13