/src/mozilla-central/dom/svg/DOMSVGPointList.h
Line | Count | Source (jump to first uncovered line) |
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 |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #ifndef MOZILLA_DOMSVGPOINTLIST_H__ |
8 | | #define MOZILLA_DOMSVGPOINTLIST_H__ |
9 | | |
10 | | #include "nsCOMPtr.h" |
11 | | #include "nsCycleCollectionParticipant.h" |
12 | | #include "nsDebug.h" |
13 | | #include "nsSVGElement.h" |
14 | | #include "nsTArray.h" |
15 | | #include "SVGPointList.h" // IWYU pragma: keep |
16 | | #include "mozilla/Attributes.h" |
17 | | #include "mozilla/ErrorResult.h" |
18 | | |
19 | | namespace mozilla { |
20 | | |
21 | | class DOMSVGPoint; |
22 | | class nsISVGPoint; |
23 | | class SVGAnimatedPointList; |
24 | | |
25 | | /** |
26 | | * Class DOMSVGPointList |
27 | | * |
28 | | * This class is used to create the DOM tearoff objects that wrap internal |
29 | | * SVGPointList objects. |
30 | | * |
31 | | * See the architecture comment in DOMSVGAnimatedLengthList.h first (that's |
32 | | * LENGTH list), then continue reading the remainder of this comment. |
33 | | * |
34 | | * The architecture of this class is very similar to that of DOMSVGLengthList |
35 | | * except that, since there is no nsIDOMSVGAnimatedPointList interface |
36 | | * in SVG, we have no parent DOMSVGAnimatedPointList (unlike DOMSVGLengthList |
37 | | * which has a parent DOMSVGAnimatedLengthList class). (There is an |
38 | | * SVGAnimatedPoints interface, but that is quite different to |
39 | | * DOMSVGAnimatedLengthList, since it is inherited by elements rather than |
40 | | * elements having members of that type.) As a consequence, much of the logic |
41 | | * that would otherwise be in DOMSVGAnimatedPointList (and is in |
42 | | * DOMSVGAnimatedLengthList) is contained in this class. |
43 | | * |
44 | | * This class is strongly intertwined with DOMSVGPoint. Our DOMSVGPoint |
45 | | * items are friends of us and responsible for nulling out our pointers to |
46 | | * them when they die. |
47 | | * |
48 | | * Our DOM items are created lazily on demand as and when script requests them. |
49 | | */ |
50 | | class DOMSVGPointList final : public nsISupports, |
51 | | public nsWrapperCache |
52 | | { |
53 | | friend class AutoChangePointListNotifier; |
54 | | friend class nsISVGPoint; |
55 | | friend class mozilla::DOMSVGPoint; |
56 | | |
57 | | public: |
58 | | NS_DECL_CYCLE_COLLECTING_ISUPPORTS |
59 | | NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMSVGPointList) |
60 | | |
61 | | virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override; |
62 | | |
63 | | nsISupports* GetParentObject() |
64 | 0 | { |
65 | 0 | return static_cast<nsIContent*>(mElement); |
66 | 0 | } |
67 | | |
68 | | /** |
69 | | * Factory method to create and return a DOMSVGPointList wrapper |
70 | | * for a given internal SVGPointList object. The factory takes care |
71 | | * of caching the object that it returns so that the same object can be |
72 | | * returned for the given SVGPointList each time it is requested. |
73 | | * The cached object is only removed from the cache when it is destroyed due |
74 | | * to there being no more references to it or to any of its descendant |
75 | | * objects. If that happens, any subsequent call requesting the DOM wrapper |
76 | | * for the SVGPointList will naturally result in a new |
77 | | * DOMSVGPointList being returned. |
78 | | * |
79 | | * It's unfortunate that aList is a void* instead of a typed argument. This |
80 | | * is because the mBaseVal and mAnimVal members of SVGAnimatedPointList are |
81 | | * of different types - a plain SVGPointList, and a SVGPointList*. We |
82 | | * use the addresses of these members as the key for the hash table, and |
83 | | * clearly SVGPointList* and a SVGPointList** are not the same type. |
84 | | */ |
85 | | static already_AddRefed<DOMSVGPointList> |
86 | | GetDOMWrapper(void *aList, |
87 | | nsSVGElement *aElement, |
88 | | bool aIsAnimValList); |
89 | | |
90 | | /** |
91 | | * This method returns the DOMSVGPointList wrapper for an internal |
92 | | * SVGPointList object if it currently has a wrapper. If it does |
93 | | * not, then nullptr is returned. |
94 | | */ |
95 | | static DOMSVGPointList* |
96 | | GetDOMWrapperIfExists(void *aList); |
97 | | |
98 | | /** |
99 | | * This will normally be the same as InternalList().Length(), except if |
100 | | * we've hit OOM, in which case our length will be zero. |
101 | | */ |
102 | 0 | uint32_t LengthNoFlush() const { |
103 | 0 | MOZ_ASSERT(mItems.Length() == 0 || |
104 | 0 | mItems.Length() == InternalList().Length(), |
105 | 0 | "DOM wrapper's list length is out of sync"); |
106 | 0 | return mItems.Length(); |
107 | 0 | } |
108 | | |
109 | | /** |
110 | | * WATCH OUT! If you add code to call this on a baseVal wrapper, then you |
111 | | * must also call it on the animVal wrapper too if necessary!! See other |
112 | | * callers! |
113 | | * |
114 | | * Called by internal code to notify us when we need to sync the length of |
115 | | * this DOM list with its internal list. This is called immediately prior to |
116 | | * the length of the internal list being changed so that any DOM list items |
117 | | * that need to be removed from the DOM list can first copy their values from |
118 | | * their internal counterpart. |
119 | | * |
120 | | * The only time this method could fail is on OOM when trying to increase the |
121 | | * length of the DOM list. If that happens then this method simply clears the |
122 | | * list and returns. Callers just proceed as normal, and we simply accept |
123 | | * that the DOM list will be empty (until successfully set to a new value). |
124 | | */ |
125 | | void InternalListWillChangeTo(const SVGPointList& aNewValue); |
126 | | |
127 | | /** |
128 | | * Returns true if our attribute is animating (in which case our animVal is |
129 | | * not simply a mirror of our baseVal). |
130 | | */ |
131 | | bool AttrIsAnimating() const; |
132 | | /** |
133 | | * Returns true if there is an animated list mirroring the base list. |
134 | | */ |
135 | | bool AnimListMirrorsBaseList() const; |
136 | | |
137 | | uint32_t NumberOfItems() const |
138 | 0 | { |
139 | 0 | if (IsAnimValList()) { |
140 | 0 | Element()->FlushAnimations(); |
141 | 0 | } |
142 | 0 | return LengthNoFlush(); |
143 | 0 | } |
144 | | void Clear(ErrorResult& aError); |
145 | | already_AddRefed<nsISVGPoint> Initialize(nsISVGPoint& aNewItem, |
146 | | ErrorResult& aError); |
147 | | already_AddRefed<nsISVGPoint> GetItem(uint32_t index, |
148 | | ErrorResult& error); |
149 | | already_AddRefed<nsISVGPoint> IndexedGetter(uint32_t index, bool& found, |
150 | | ErrorResult& error); |
151 | | already_AddRefed<nsISVGPoint> InsertItemBefore(nsISVGPoint& aNewItem, |
152 | | uint32_t aIndex, |
153 | | ErrorResult& aError); |
154 | | already_AddRefed<nsISVGPoint> ReplaceItem(nsISVGPoint& aNewItem, |
155 | | uint32_t aIndex, |
156 | | ErrorResult& aError); |
157 | | already_AddRefed<nsISVGPoint> RemoveItem(uint32_t aIndex, |
158 | | ErrorResult& aError); |
159 | | already_AddRefed<nsISVGPoint> AppendItem(nsISVGPoint& aNewItem, |
160 | | ErrorResult& aError) |
161 | 0 | { |
162 | 0 | return InsertItemBefore(aNewItem, LengthNoFlush(), aError); |
163 | 0 | } |
164 | | uint32_t Length() const |
165 | 0 | { |
166 | 0 | return NumberOfItems(); |
167 | 0 | } |
168 | | |
169 | | private: |
170 | | |
171 | | /** |
172 | | * Only our static GetDOMWrapper() factory method may create objects of our |
173 | | * type. |
174 | | */ |
175 | | DOMSVGPointList(nsSVGElement *aElement, bool aIsAnimValList) |
176 | | : mElement(aElement) |
177 | | , mIsAnimValList(aIsAnimValList) |
178 | 0 | { |
179 | 0 | InternalListWillChangeTo(InternalList()); // Sync mItems |
180 | 0 | } |
181 | | |
182 | | ~DOMSVGPointList(); |
183 | | |
184 | 0 | nsSVGElement* Element() const { |
185 | 0 | return mElement.get(); |
186 | 0 | } |
187 | | |
188 | | /// Used to determine if this list is the baseVal or animVal list. |
189 | 0 | bool IsAnimValList() const { |
190 | 0 | return mIsAnimValList; |
191 | 0 | } |
192 | | |
193 | | /** |
194 | | * Get a reference to this object's corresponding internal SVGPointList. |
195 | | * |
196 | | * To simplify the code we just have this one method for obtaining both |
197 | | * base val and anim val internal lists. This means that anim val lists don't |
198 | | * get const protection, but our setter methods guard against changing |
199 | | * anim val lists. |
200 | | */ |
201 | | SVGPointList& InternalList() const; |
202 | | |
203 | | SVGAnimatedPointList& InternalAList() const; |
204 | | |
205 | | /// Returns the nsISVGPoint at aIndex, creating it if necessary. |
206 | | already_AddRefed<nsISVGPoint> GetItemAt(uint32_t aIndex); |
207 | | |
208 | | void MaybeInsertNullInAnimValListAt(uint32_t aIndex); |
209 | | void MaybeRemoveItemFromAnimValListAt(uint32_t aIndex); |
210 | | |
211 | | // Weak refs to our nsISVGPoint items. The items are friends and take care |
212 | | // of clearing our pointer to them when they die. |
213 | | FallibleTArray<nsISVGPoint*> mItems; |
214 | | |
215 | | // Strong ref to our element to keep it alive. We hold this not only for |
216 | | // ourself, but also for our nsISVGPoint items too. |
217 | | RefPtr<nsSVGElement> mElement; |
218 | | |
219 | | bool mIsAnimValList; |
220 | | }; |
221 | | |
222 | | } // namespace mozilla |
223 | | |
224 | | #endif // MOZILLA_DOMSVGPOINTLIST_H__ |