Bumping gaia.json for 8 gaia revision(s) a=gaia-bump
[gecko.git] / dom / base / nsReferencedElement.h
blob4d7ea690171814e8aca53e7198e3f5d136b81e99
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=78: */
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
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef NSREFERENCEDELEMENT_H_
8 #define NSREFERENCEDELEMENT_H_
10 #include "mozilla/Attributes.h"
11 #include "mozilla/dom/Element.h"
12 #include "nsIAtom.h"
13 #include "nsIDocument.h"
14 #include "nsThreadUtils.h"
15 #include "nsAutoPtr.h"
17 class nsIURI;
18 class nsCycleCollectionCallback;
20 /**
21 * Class to track what element is referenced by a given ID.
23 * To use it, call Reset() to set it up to watch a given URI. Call get()
24 * anytime to determine the referenced element (which may be null if
25 * the element isn't found). When the element changes, ElementChanged
26 * will be called, so subclass this class if you want to receive that
27 * notification. ElementChanged runs at safe-for-script time, i.e. outside
28 * of the content update. Call Unlink() if you want to stop watching
29 * for changes (get() will then return null).
31 * By default this is a single-shot tracker --- i.e., when ElementChanged
32 * fires, we will automatically stop tracking. get() will continue to return
33 * the changed-to element.
34 * Override IsPersistent to return true if you want to keep tracking after
35 * the first change.
37 class nsReferencedElement {
38 public:
39 typedef mozilla::dom::Element Element;
41 nsReferencedElement() {}
42 ~nsReferencedElement() {
43 Unlink();
46 /**
47 * Find which element, if any, is referenced.
49 Element* get() { return mElement; }
51 /**
52 * Set up the reference. This can be called multiple times to
53 * change which reference is being tracked, but these changes
54 * do not trigger ElementChanged.
55 * @param aFrom the source element for context
56 * @param aURI the URI containing a hash-reference to the element
57 * @param aWatch if false, then we do not set up the notifications to track
58 * changes, so ElementChanged won't fire and get() will always return the same
59 * value, the current element for the ID.
60 * @param aReferenceImage whether the ID references image elements which are
61 * subject to the document's mozSetImageElement overriding mechanism.
63 void Reset(nsIContent* aFrom, nsIURI* aURI, bool aWatch = true,
64 bool aReferenceImage = false);
66 /**
67 * A variation on Reset() to set up a reference that consists of the ID of
68 * an element in the same document as aFrom.
69 * @param aFrom the source element for context
70 * @param aID the ID of the element
71 * @param aWatch if false, then we do not set up the notifications to track
72 * changes, so ElementChanged won't fire and get() will always return the same
73 * value, the current element for the ID.
75 void ResetWithID(nsIContent* aFrom, const nsString& aID,
76 bool aWatch = true);
78 /**
79 * Clears the reference. ElementChanged is not triggered. get() will return
80 * null.
82 void Unlink();
84 void Traverse(nsCycleCollectionTraversalCallback* aCB);
86 protected:
87 /**
88 * Override this to be notified of element changes. Don't forget
89 * to call this superclass method to change mElement. This is called
90 * at script-runnable time.
92 virtual void ElementChanged(Element* aFrom, Element* aTo) {
93 mElement = aTo;
96 /**
97 * Override this to convert from a single-shot notification to
98 * a persistent notification.
100 virtual bool IsPersistent() { return false; }
103 * Set ourselves up with our new document. Note that aDocument might be
104 * null. Either aWatch must be false or aRef must be empty.
106 void HaveNewDocument(nsIDocument* aDocument, bool aWatch,
107 const nsString& aRef);
109 private:
110 static bool Observe(Element* aOldElement,
111 Element* aNewElement, void* aData);
113 class Notification : public nsISupports {
114 public:
115 virtual void SetTo(Element* aTo) = 0;
116 virtual void Clear() { mTarget = nullptr; }
117 virtual ~Notification() {}
118 protected:
119 explicit Notification(nsReferencedElement* aTarget)
120 : mTarget(aTarget)
122 NS_PRECONDITION(aTarget, "Must have a target");
124 nsReferencedElement* mTarget;
127 class ChangeNotification : public nsRunnable,
128 public Notification
130 public:
131 ChangeNotification(nsReferencedElement* aTarget,
132 Element* aFrom, Element* aTo)
133 : Notification(aTarget), mFrom(aFrom), mTo(aTo)
136 NS_DECL_ISUPPORTS_INHERITED
137 NS_IMETHOD Run() MOZ_OVERRIDE {
138 if (mTarget) {
139 mTarget->mPendingNotification = nullptr;
140 mTarget->ElementChanged(mFrom, mTo);
142 return NS_OK;
144 virtual void SetTo(Element* aTo) MOZ_OVERRIDE { mTo = aTo; }
145 virtual void Clear() MOZ_OVERRIDE
147 Notification::Clear(); mFrom = nullptr; mTo = nullptr;
149 protected:
150 virtual ~ChangeNotification() {}
152 nsRefPtr<Element> mFrom;
153 nsRefPtr<Element> mTo;
155 friend class ChangeNotification;
157 class DocumentLoadNotification : public Notification,
158 public nsIObserver
160 public:
161 DocumentLoadNotification(nsReferencedElement* aTarget,
162 const nsString& aRef) :
163 Notification(aTarget)
165 if (!mTarget->IsPersistent()) {
166 mRef = aRef;
170 NS_DECL_ISUPPORTS
171 NS_DECL_NSIOBSERVER
172 private:
173 virtual ~DocumentLoadNotification() {}
175 virtual void SetTo(Element* aTo) MOZ_OVERRIDE { }
177 nsString mRef;
179 friend class DocumentLoadNotification;
181 nsCOMPtr<nsIAtom> mWatchID;
182 nsCOMPtr<nsIDocument> mWatchDocument;
183 nsRefPtr<Element> mElement;
184 nsRefPtr<Notification> mPendingNotification;
185 bool mReferencingImage;
188 inline void
189 ImplCycleCollectionUnlink(nsReferencedElement& aField)
191 aField.Unlink();
194 inline void
195 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
196 nsReferencedElement& aField,
197 const char* aName,
198 uint32_t aFlags = 0)
200 aField.Traverse(&aCallback);
203 #endif /*NSREFERENCEDELEMENT_H_*/