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
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 0 : NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMSVGPointList)
60 :
61 : virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
62 :
63 0 : nsISupports* GetParentObject()
64 : {
65 0 : return static_cast<nsIContent*>(mElement);
66 : }
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 : mItems.Length() == InternalList().Length(),
105 : "DOM wrapper's list length is out of sync");
106 0 : return mItems.Length();
107 : }
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 0 : uint32_t NumberOfItems() const
138 : {
139 0 : if (IsAnimValList()) {
140 0 : Element()->FlushAnimations();
141 : }
142 0 : return LengthNoFlush();
143 : }
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 0 : already_AddRefed<nsISVGPoint> AppendItem(nsISVGPoint& aNewItem,
160 : ErrorResult& aError)
161 : {
162 0 : return InsertItemBefore(aNewItem, LengthNoFlush(), aError);
163 : }
164 0 : uint32_t Length() const
165 : {
166 0 : return NumberOfItems();
167 : }
168 :
169 : private:
170 :
171 : /**
172 : * Only our static GetDOMWrapper() factory method may create objects of our
173 : * type.
174 : */
175 0 : DOMSVGPointList(nsSVGElement *aElement, bool aIsAnimValList)
176 0 : : mElement(aElement)
177 0 : , mIsAnimValList(aIsAnimValList)
178 : {
179 0 : InternalListWillChangeTo(InternalList()); // Sync mItems
180 0 : }
181 :
182 : ~DOMSVGPointList();
183 :
184 0 : nsSVGElement* Element() const {
185 0 : return mElement.get();
186 : }
187 :
188 : /// Used to determine if this list is the baseVal or animVal list.
189 0 : bool IsAnimValList() const {
190 0 : return mIsAnimValList;
191 : }
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__
|