forked from mirrors/gecko-dev
		
	 71422dcaa9
			
		
	
	
		71422dcaa9
		
	
	
	
	
		
			
			s/NS_PRECONDITION/MOZ_ASSERT/ and reindent MozReview-Commit-ID: KuUsnVe2h8L --HG-- extra : source : c14655ab3df2c9b1465dd8102b9d25683359a37b
		
			
				
	
	
		
			215 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			215 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #ifndef mozilla_dom_IDTracker_h_
 | |
| #define mozilla_dom_IDTracker_h_
 | |
| 
 | |
| #include "mozilla/Attributes.h"
 | |
| #include "mozilla/dom/Element.h"
 | |
| #include "nsAtom.h"
 | |
| #include "nsIDocument.h"
 | |
| #include "nsThreadUtils.h"
 | |
| 
 | |
| class nsIURI;
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace dom {
 | |
| 
 | |
| /**
 | |
|  * Class to track what element is referenced by a given ID.
 | |
|  *
 | |
|  * To use it, call Reset() to set it up to watch a given URI. Call get()
 | |
|  * anytime to determine the referenced element (which may be null if
 | |
|  * the element isn't found). When the element changes, ElementChanged
 | |
|  * will be called, so subclass this class if you want to receive that
 | |
|  * notification. ElementChanged runs at safe-for-script time, i.e. outside
 | |
|  * of the content update. Call Unlink() if you want to stop watching
 | |
|  * for changes (get() will then return null).
 | |
|  *
 | |
|  * By default this is a single-shot tracker --- i.e., when ElementChanged
 | |
|  * fires, we will automatically stop tracking. get() will continue to return
 | |
|  * the changed-to element.
 | |
|  * Override IsPersistent to return true if you want to keep tracking after
 | |
|  * the first change.
 | |
|  */
 | |
| class IDTracker {
 | |
| public:
 | |
|   typedef mozilla::dom::Element Element;
 | |
| 
 | |
|   IDTracker()
 | |
|     : mReferencingImage(false)
 | |
|   {}
 | |
|   ~IDTracker() {
 | |
|     Unlink();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Find which element, if any, is referenced.
 | |
|    */
 | |
|   Element* get() { return mElement; }
 | |
| 
 | |
|   /**
 | |
|    * Set up the reference. This can be called multiple times to
 | |
|    * change which reference is being tracked, but these changes
 | |
|    * do not trigger ElementChanged.
 | |
|    * @param aFrom the source element for context
 | |
|    * @param aURI the URI containing a hash-reference to the element
 | |
|    * @param aWatch if false, then we do not set up the notifications to track
 | |
|    * changes, so ElementChanged won't fire and get() will always return the same
 | |
|    * value, the current element for the ID.
 | |
|    * @param aReferenceImage whether the ID references image elements which are
 | |
|    * subject to the document's mozSetImageElement overriding mechanism.
 | |
|    */
 | |
|   void Reset(nsIContent* aFrom, nsIURI* aURI, bool aWatch = true,
 | |
|              bool aReferenceImage = false);
 | |
| 
 | |
|   /**
 | |
|    * A variation on Reset() to set up a reference that consists of the ID of
 | |
|    * an element in the same document as aFrom.
 | |
|    * @param aFrom the source element for context
 | |
|    * @param aID the ID of the element
 | |
|    * @param aWatch if false, then we do not set up the notifications to track
 | |
|    * changes, so ElementChanged won't fire and get() will always return the same
 | |
|    * value, the current element for the ID.
 | |
|    */
 | |
|   void ResetWithID(nsIContent* aFrom, const nsString& aID,
 | |
|                    bool aWatch = true);
 | |
| 
 | |
|   /**
 | |
|    * Clears the reference. ElementChanged is not triggered. get() will return
 | |
|    * null.
 | |
|    */
 | |
|   void Unlink();
 | |
| 
 | |
|   void Traverse(nsCycleCollectionTraversalCallback* aCB);
 | |
| 
 | |
| protected:
 | |
|   /**
 | |
|    * Override this to be notified of element changes. Don't forget
 | |
|    * to call this superclass method to change mElement. This is called
 | |
|    * at script-runnable time.
 | |
|    */
 | |
|   virtual void ElementChanged(Element* aFrom, Element* aTo) {
 | |
|     mElement = aTo;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Override this to convert from a single-shot notification to
 | |
|    * a persistent notification.
 | |
|    */
 | |
|   virtual bool IsPersistent() { return false; }
 | |
| 
 | |
|   /**
 | |
|    * Set ourselves up with our new document.  Note that aDocument might be
 | |
|    * null.  Either aWatch must be false or aRef must be empty.
 | |
|    */
 | |
|   void HaveNewDocument(nsIDocument* aDocument, bool aWatch,
 | |
|                        const nsString& aRef);
 | |
| 
 | |
| private:
 | |
|   static bool Observe(Element* aOldElement,
 | |
|                         Element* aNewElement, void* aData);
 | |
| 
 | |
|   class Notification : public nsISupports {
 | |
|   public:
 | |
|     virtual void SetTo(Element* aTo) = 0;
 | |
|     virtual void Clear() { mTarget = nullptr; }
 | |
|     virtual ~Notification() {}
 | |
|   protected:
 | |
|     explicit Notification(IDTracker* aTarget)
 | |
|       : mTarget(aTarget)
 | |
|     {
 | |
|       MOZ_ASSERT(aTarget, "Must have a target");
 | |
|     }
 | |
|     IDTracker* mTarget;
 | |
|   };
 | |
| 
 | |
|   class ChangeNotification : public mozilla::Runnable,
 | |
|                              public Notification
 | |
|   {
 | |
|   public:
 | |
|     ChangeNotification(IDTracker* aTarget,
 | |
|                        Element* aFrom,
 | |
|                        Element* aTo)
 | |
|       : mozilla::Runnable("IDTracker::ChangeNotification")
 | |
|       , Notification(aTarget)
 | |
|       , mFrom(aFrom)
 | |
|       , mTo(aTo)
 | |
|     {}
 | |
| 
 | |
|     // We need to actually declare all of nsISupports, because
 | |
|     // Notification inherits from it but doesn't declare it.
 | |
|     NS_DECL_ISUPPORTS_INHERITED
 | |
|     NS_IMETHOD Run() override {
 | |
|       if (mTarget) {
 | |
|         mTarget->mPendingNotification = nullptr;
 | |
|         mTarget->ElementChanged(mFrom, mTo);
 | |
|       }
 | |
|       return NS_OK;
 | |
|     }
 | |
|     virtual void SetTo(Element* aTo) override { mTo = aTo; }
 | |
|     virtual void Clear() override
 | |
|     {
 | |
|       Notification::Clear(); mFrom = nullptr; mTo = nullptr;
 | |
|     }
 | |
|   protected:
 | |
|     virtual ~ChangeNotification() {}
 | |
| 
 | |
|     RefPtr<Element> mFrom;
 | |
|     RefPtr<Element> mTo;
 | |
|   };
 | |
|   friend class ChangeNotification;
 | |
| 
 | |
|   class DocumentLoadNotification : public Notification,
 | |
|                                    public nsIObserver
 | |
|   {
 | |
|   public:
 | |
|     DocumentLoadNotification(IDTracker* aTarget,
 | |
|                              const nsString& aRef) :
 | |
|       Notification(aTarget)
 | |
|     {
 | |
|       if (!mTarget->IsPersistent()) {
 | |
|         mRef = aRef;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     NS_DECL_ISUPPORTS
 | |
|     NS_DECL_NSIOBSERVER
 | |
|   private:
 | |
|     virtual ~DocumentLoadNotification() {}
 | |
| 
 | |
|     virtual void SetTo(Element* aTo) override { }
 | |
| 
 | |
|     nsString mRef;
 | |
|   };
 | |
|   friend class DocumentLoadNotification;
 | |
| 
 | |
|   RefPtr<nsAtom>      mWatchID;
 | |
|   nsCOMPtr<nsIDocument>  mWatchDocument;
 | |
|   RefPtr<Element> mElement;
 | |
|   RefPtr<Notification> mPendingNotification;
 | |
|   bool                   mReferencingImage;
 | |
| };
 | |
| 
 | |
| inline void
 | |
| ImplCycleCollectionUnlink(IDTracker& aField)
 | |
| {
 | |
|   aField.Unlink();
 | |
| }
 | |
| 
 | |
| inline void
 | |
| ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
 | |
|                             IDTracker& aField,
 | |
|                             const char* aName,
 | |
|                             uint32_t aFlags = 0)
 | |
| {
 | |
|   aField.Traverse(&aCallback);
 | |
| }
 | |
| 
 | |
| } // namespace dom
 | |
| } // namespace mozilla
 | |
| 
 | |
| #endif /* mozilla_dom_IDTracker_h_ */
 |