1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla SVG Project code.
16 : *
17 : * The Initial Developer of the Original Code is the Mozilla Foundation.
18 : * Portions created by the Initial Developer are Copyright (C) 2010
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : *
23 : * Alternatively, the contents of this file may be used under the terms of
24 : * either the GNU General Public License Version 2 or later (the "GPL"), or
25 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 : * in which case the provisions of the GPL or the LGPL are applicable instead
27 : * of those above. If you wish to allow use of your version of this file only
28 : * under the terms of either the GPL or the LGPL, and not to allow others to
29 : * use your version of this file under the terms of the MPL, indicate your
30 : * decision by deleting the provisions above and replace them with the notice
31 : * and other provisions required by the GPL or the LGPL. If you do not delete
32 : * the provisions above, a recipient may use your version of this file under
33 : * the terms of any one of the MPL, the GPL or the LGPL.
34 : *
35 : * ***** END LICENSE BLOCK ***** */
36 :
37 : #ifndef MOZILLA_DOMSVGPATHSEGLIST_H__
38 : #define MOZILLA_DOMSVGPATHSEGLIST_H__
39 :
40 : #include "nsAutoPtr.h"
41 : #include "nsCOMPtr.h"
42 : #include "nsCycleCollectionParticipant.h"
43 : #include "nsDebug.h"
44 : #include "nsIDOMSVGPathSegList.h"
45 : #include "nsSVGElement.h"
46 : #include "nsTArray.h"
47 : #include "SVGPathData.h" // IWYU pragma: keep
48 :
49 : class nsIDOMSVGPathSeg;
50 :
51 : namespace mozilla {
52 :
53 : class DOMSVGPathSeg;
54 : class SVGAnimatedPathSegList;
55 :
56 : /**
57 : * Class DOMSVGPathSegList
58 : *
59 : * This class is used to create the DOM tearoff objects that wrap internal
60 : * SVGPathData objects.
61 : *
62 : * See the architecture comment in DOMSVGAnimatedLengthList.h first (that's
63 : * LENGTH list), then continue reading the remainder of this comment.
64 : *
65 : * The architecture of this class is very similar to that of DOMSVGLengthList
66 : * except that, since there is no nsIDOMSVGAnimatedPathSegList interface
67 : * in SVG, we have no parent DOMSVGAnimatedPathSegList (unlike DOMSVGLengthList
68 : * which has a parent DOMSVGAnimatedLengthList class). (There is an
69 : * SVGAnimatedPathData interface, but that is quite different to
70 : * DOMSVGAnimatedLengthList, since it is inherited by elements rather than
71 : * elements having members of that type.) As a consequence, much of the logic
72 : * that would otherwise be in DOMSVGAnimatedPathSegList (and is in
73 : * DOMSVGAnimatedLengthList) is contained in this class.
74 : *
75 : * This class is strongly intertwined with DOMSVGPathSeg. Our DOMSVGPathSeg
76 : * items are friends of us and responsible for nulling out our pointers to
77 : * them when they die.
78 : *
79 : * Our DOM items are created lazily on demand as and when script requests them.
80 : */
81 : class DOMSVGPathSegList : public nsIDOMSVGPathSegList,
82 : public nsWrapperCache
83 : {
84 : friend class DOMSVGPathSeg;
85 :
86 : public:
87 0 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
88 1464 : NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMSVGPathSegList)
89 : NS_DECL_NSIDOMSVGPATHSEGLIST
90 :
91 : virtual JSObject* WrapObject(JSContext *cx, XPCWrappedNativeScope *scope,
92 : bool *triedToWrap);
93 :
94 0 : nsISupports* GetParentObject()
95 : {
96 0 : return static_cast<nsIContent*>(mElement);
97 : }
98 :
99 : /**
100 : * Factory method to create and return a DOMSVGPathSegList wrapper
101 : * for a given internal SVGPathData object. The factory takes care
102 : * of caching the object that it returns so that the same object can be
103 : * returned for the given SVGPathData each time it is requested.
104 : * The cached object is only removed from the cache when it is destroyed due
105 : * to there being no more references to it or to any of its descendant
106 : * objects. If that happens, any subsequent call requesting the DOM wrapper
107 : * for the SVGPathData will naturally result in a new
108 : * DOMSVGPathSegList being returned.
109 : *
110 : * It's unfortunate that aList is a void* instead of a typed argument. This
111 : * is because the mBaseVal and mAnimVal members of SVGAnimatedPathSegList are
112 : * of different types - a plain SVGPathData, and a SVGPathData*. We
113 : * use the addresses of these members as the key for the hash table, and
114 : * clearly SVGPathData* and a SVGPathData** are not the same type.
115 : */
116 : static already_AddRefed<DOMSVGPathSegList>
117 : GetDOMWrapper(void *aList,
118 : nsSVGElement *aElement,
119 : bool aIsAnimValList);
120 :
121 : /**
122 : * This method returns the DOMSVGPathSegList wrapper for an internal
123 : * SVGPathData object if it currently has a wrapper. If it does
124 : * not, then nsnull is returned.
125 : */
126 : static DOMSVGPathSegList*
127 : GetDOMWrapperIfExists(void *aList);
128 :
129 : /**
130 : * This will normally be the same as InternalList().CountItems(), except if
131 : * we've hit OOM, in which case our length will be zero.
132 : */
133 0 : PRUint32 Length() const {
134 0 : NS_ABORT_IF_FALSE(mItems.Length() == 0 ||
135 : mItems.Length() == InternalList().CountItems(),
136 : "DOM wrapper's list length is out of sync");
137 0 : return mItems.Length();
138 : }
139 :
140 : /**
141 : * WATCH OUT! If you add code to call this on a baseVal wrapper, then you
142 : * must also call it on the animVal wrapper too if necessary!! See other
143 : * callers!
144 : *
145 : * Called by internal code to notify us when we need to sync the length of
146 : * this DOM list with its internal list. This is called immediately prior to
147 : * the length of the internal list being changed so that any DOM list items
148 : * that need to be removed from the DOM list can first copy their values from
149 : * their internal counterpart.
150 : *
151 : * The only time this method could fail is on OOM when trying to increase the
152 : * length of the DOM list. If that happens then this method simply clears the
153 : * list and returns. Callers just proceed as normal, and we simply accept
154 : * that the DOM list will be empty (until successfully set to a new value).
155 : */
156 : void InternalListWillChangeTo(const SVGPathData& aNewValue);
157 :
158 : /**
159 : * Returns true if our attribute is animating (in which case our animVal is
160 : * not simply a mirror of our baseVal).
161 : */
162 : bool AttrIsAnimating() const;
163 :
164 : private:
165 :
166 : /**
167 : * Only our static GetDOMWrapper() factory method may create objects of our
168 : * type.
169 : */
170 0 : DOMSVGPathSegList(nsSVGElement *aElement, bool aIsAnimValList)
171 : : mElement(aElement)
172 0 : , mIsAnimValList(aIsAnimValList)
173 : {
174 0 : SetIsProxy();
175 :
176 0 : InternalListWillChangeTo(InternalList()); // Sync mItems
177 0 : }
178 :
179 : ~DOMSVGPathSegList();
180 :
181 0 : nsSVGElement* Element() {
182 0 : return mElement.get();
183 : }
184 :
185 : /// Used to determine if this list is the baseVal or animVal list.
186 0 : bool IsAnimValList() const {
187 0 : return mIsAnimValList;
188 : }
189 :
190 : /**
191 : * Get a reference to this object's corresponding internal SVGPathData.
192 : *
193 : * To simplify the code we just have this one method for obtaining both
194 : * base val and anim val internal lists. This means that anim val lists don't
195 : * get const protection, but our setter methods guard against changing
196 : * anim val lists.
197 : */
198 : SVGPathData& InternalList() const;
199 :
200 : SVGAnimatedPathSegList& InternalAList() const;
201 :
202 : /// Creates an instance of the appropriate DOMSVGPathSeg sub-class for
203 : // aIndex, if it doesn't already exist.
204 : void EnsureItemAt(PRUint32 aIndex);
205 :
206 : void MaybeInsertNullInAnimValListAt(PRUint32 aIndex,
207 : PRUint32 aInternalIndex,
208 : PRUint32 aArgCountForItem);
209 : void MaybeRemoveItemFromAnimValListAt(PRUint32 aIndex,
210 : PRUint32 aArgCountForItem);
211 :
212 : // Calls UpdateListIndex on all elements in |mItems| that satisfy ItemAt(),
213 : // from |aStartingIndex| to the end of |mItems|. Also adjusts
214 : // |mItems.mInternalDataIndex| by the requested amount.
215 : void UpdateListIndicesFromIndex(PRUint32 aStartingIndex,
216 : PRInt32 aInternalDataIndexDelta);
217 :
218 0 : DOMSVGPathSeg*& ItemAt(PRUint32 aIndex) {
219 0 : return mItems[aIndex].mItem;
220 : }
221 :
222 : /**
223 : * This struct is used in our array of mItems to provide us with somewhere to
224 : * store the indexes into the internal SVGPathData of the internal seg data
225 : * that our DOMSVGPathSeg items wrap (the internal segment data is or varying
226 : * length, so we can't just use the index of our DOMSVGPathSeg items
227 : * themselves). The reason that we have this separate struct rather than
228 : * just storing the internal indexes in the DOMSVGPathSeg items is because we
229 : * want to create the DOMSVGPathSeg items lazily on demand.
230 : */
231 0 : struct ItemProxy {
232 0 : ItemProxy(){}
233 0 : ItemProxy(DOMSVGPathSeg *aItem, PRUint32 aInternalDataIndex)
234 : : mItem(aItem)
235 0 : , mInternalDataIndex(aInternalDataIndex)
236 0 : {}
237 :
238 : DOMSVGPathSeg *mItem;
239 : PRUint32 mInternalDataIndex;
240 : };
241 :
242 : // Weak refs to our DOMSVGPathSeg items. The items are friends and take care
243 : // of clearing our pointer to them when they die.
244 : nsTArray<ItemProxy> mItems;
245 :
246 : // Strong ref to our element to keep it alive. We hold this not only for
247 : // ourself, but also for our DOMSVGPathSeg items too.
248 : nsRefPtr<nsSVGElement> mElement;
249 :
250 : bool mIsAnimValList;
251 : };
252 :
253 : } // namespace mozilla
254 :
255 : #endif // MOZILLA_DOMSVGPATHSEGLIST_H__
|