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 : #include "DOMSVGPathSeg.h"
8 : #include "DOMSVGPathSegList.h"
9 : #include "SVGAnimatedPathSegList.h"
10 : #include "nsSVGElement.h"
11 : #include "nsError.h"
12 :
13 : // See the architecture comment in DOMSVGPathSegList.h.
14 :
15 : namespace mozilla {
16 :
17 : // We could use NS_IMPL_CYCLE_COLLECTION(, except that in Unlink() we need to
18 : // clear our list's weak ref to us to be safe. (The other option would be to
19 : // not unlink and rely on the breaking of the other edges in the cycle, as
20 : // NS_SVG_VAL_IMPL_CYCLE_COLLECTION does.)
21 : NS_IMPL_CYCLE_COLLECTION_CLASS(DOMSVGPathSeg)
22 :
23 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGPathSeg)
24 : // We may not belong to a list, so we must null check tmp->mList.
25 0 : if (tmp->mList) {
26 0 : tmp->mList->ItemAt(tmp->mListIndex) = nullptr;
27 : }
28 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mList)
29 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
30 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
31 :
32 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGPathSeg)
33 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mList)
34 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
35 :
36 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGPathSeg)
37 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
38 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
39 :
40 0 : NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMSVGPathSeg, AddRef)
41 0 : NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMSVGPathSeg, Release)
42 :
43 : //----------------------------------------------------------------------
44 : // Helper class: AutoChangePathSegNotifier
45 : // Stack-based helper class to pair calls to WillChangePathSegList
46 : // and DidChangePathSegList.
47 : class MOZ_RAII AutoChangePathSegNotifier
48 : {
49 : public:
50 0 : explicit AutoChangePathSegNotifier(DOMSVGPathSeg* aPathSeg MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
51 0 : : mPathSeg(aPathSeg)
52 : {
53 0 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
54 0 : MOZ_ASSERT(mPathSeg, "Expecting non-null pathSeg");
55 0 : MOZ_ASSERT(mPathSeg->HasOwner(),
56 : "Expecting list to have an owner for notification");
57 : mEmptyOrOldValue =
58 0 : mPathSeg->Element()->WillChangePathSegList();
59 0 : }
60 :
61 0 : ~AutoChangePathSegNotifier()
62 0 : {
63 0 : mPathSeg->Element()->DidChangePathSegList(mEmptyOrOldValue);
64 0 : if (mPathSeg->mList->AttrIsAnimating()) {
65 0 : mPathSeg->Element()->AnimationNeedsResample();
66 : }
67 0 : }
68 :
69 : private:
70 : DOMSVGPathSeg* const mPathSeg;
71 : nsAttrValue mEmptyOrOldValue;
72 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
73 : };
74 :
75 0 : DOMSVGPathSeg::DOMSVGPathSeg(DOMSVGPathSegList *aList,
76 : uint32_t aListIndex,
77 0 : bool aIsAnimValItem)
78 : : mList(aList)
79 : , mListIndex(aListIndex)
80 0 : , mIsAnimValItem(aIsAnimValItem)
81 : {
82 : // These shifts are in sync with the members in the header.
83 0 : MOZ_ASSERT(aList && aListIndex <= MaxListIndex(), "bad arg");
84 :
85 0 : MOZ_ASSERT(IndexIsValid(), "Bad index for DOMSVGPathSeg!");
86 0 : }
87 :
88 0 : DOMSVGPathSeg::DOMSVGPathSeg()
89 : : mList(nullptr)
90 : , mListIndex(0)
91 0 : , mIsAnimValItem(false)
92 : {
93 0 : }
94 :
95 : void
96 0 : DOMSVGPathSeg::InsertingIntoList(DOMSVGPathSegList *aList,
97 : uint32_t aListIndex,
98 : bool aIsAnimValItem)
99 : {
100 0 : MOZ_ASSERT(!HasOwner(), "Inserting item that is already in a list");
101 :
102 0 : mList = aList;
103 0 : mListIndex = aListIndex;
104 0 : mIsAnimValItem = aIsAnimValItem;
105 :
106 0 : MOZ_ASSERT(IndexIsValid(), "Bad index for DOMSVGPathSeg!");
107 0 : }
108 :
109 : void
110 0 : DOMSVGPathSeg::RemovingFromList()
111 : {
112 0 : uint32_t argCount = SVGPathSegUtils::ArgCountForType(Type());
113 : // InternalItem() + 1, because the args come after the encoded seg type
114 0 : memcpy(PtrToMemberArgs(), InternalItem() + 1, argCount * sizeof(float));
115 0 : mList = nullptr;
116 0 : mIsAnimValItem = false;
117 0 : }
118 :
119 : void
120 0 : DOMSVGPathSeg::ToSVGPathSegEncodedData(float* aRaw)
121 : {
122 0 : MOZ_ASSERT(aRaw, "null pointer");
123 0 : uint32_t argCount = SVGPathSegUtils::ArgCountForType(Type());
124 0 : if (IsInList()) {
125 : // 1 + argCount, because we're copying the encoded seg type and args
126 0 : memcpy(aRaw, InternalItem(), (1 + argCount) * sizeof(float));
127 : } else {
128 0 : aRaw[0] = SVGPathSegUtils::EncodeType(Type());
129 : // aRaw + 1, because the args go after the encoded seg type
130 0 : memcpy(aRaw + 1, PtrToMemberArgs(), argCount * sizeof(float));
131 : }
132 0 : }
133 :
134 : float*
135 0 : DOMSVGPathSeg::InternalItem()
136 : {
137 0 : uint32_t dataIndex = mList->mItems[mListIndex].mInternalDataIndex;
138 0 : return &(mList->InternalList().mData[dataIndex]);
139 : }
140 :
141 : #ifdef DEBUG
142 : bool
143 0 : DOMSVGPathSeg::IndexIsValid()
144 : {
145 0 : SVGAnimatedPathSegList *alist = Element()->GetAnimPathSegList();
146 0 : return (mIsAnimValItem &&
147 0 : mListIndex < alist->GetAnimValue().CountItems()) ||
148 0 : (!mIsAnimValItem &&
149 0 : mListIndex < alist->GetBaseValue().CountItems());
150 : }
151 : #endif
152 :
153 :
154 : ////////////////////////////////////////////////////////////////////////
155 : // Implementation of DOMSVGPathSeg sub-classes below this point
156 :
157 : #define IMPL_PROP_WITH_TYPE(segName, propName, index, type) \
158 : type \
159 : DOMSVGPathSeg##segName::propName() \
160 : { \
161 : if (mIsAnimValItem && HasOwner()) { \
162 : Element()->FlushAnimations(); /* May make HasOwner() == false */ \
163 : } \
164 : return type(HasOwner() ? InternalItem()[1+index] : mArgs[index]); \
165 : } \
166 : void \
167 : DOMSVGPathSeg##segName::Set##propName(type a##propName, ErrorResult& rv) \
168 : { \
169 : if (mIsAnimValItem) { \
170 : rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); \
171 : return; \
172 : } \
173 : if (HasOwner()) { \
174 : if (InternalItem()[1+index] == float(a##propName)) { \
175 : return; \
176 : } \
177 : AutoChangePathSegNotifier notifier(this); \
178 : InternalItem()[1+index] = float(a##propName); \
179 : } else { \
180 : mArgs[index] = float(a##propName); \
181 : } \
182 : }
183 :
184 : // For float, the normal type of arguments
185 : #define IMPL_FLOAT_PROP(segName, propName, index) \
186 : IMPL_PROP_WITH_TYPE(segName, propName, index, float)
187 :
188 : // For the boolean flags in arc commands
189 : #define IMPL_BOOL_PROP(segName, propName, index) \
190 : IMPL_PROP_WITH_TYPE(segName, propName, index, bool)
191 :
192 :
193 : ///////////////////////////////////////////////////////////////////////
194 :
195 0 : IMPL_FLOAT_PROP(MovetoAbs, X, 0)
196 0 : IMPL_FLOAT_PROP(MovetoAbs, Y, 1)
197 :
198 :
199 : ////////////////////////////////////////////////////////////////////////
200 :
201 0 : IMPL_FLOAT_PROP(MovetoRel, X, 0)
202 0 : IMPL_FLOAT_PROP(MovetoRel, Y, 1)
203 :
204 :
205 :
206 : ////////////////////////////////////////////////////////////////////////
207 :
208 0 : IMPL_FLOAT_PROP(LinetoAbs, X, 0)
209 0 : IMPL_FLOAT_PROP(LinetoAbs, Y, 1)
210 :
211 :
212 : ////////////////////////////////////////////////////////////////////////
213 :
214 0 : IMPL_FLOAT_PROP(LinetoRel, X, 0)
215 0 : IMPL_FLOAT_PROP(LinetoRel, Y, 1)
216 :
217 :
218 : ////////////////////////////////////////////////////////////////////////
219 :
220 0 : IMPL_FLOAT_PROP(CurvetoCubicAbs, X1, 0)
221 0 : IMPL_FLOAT_PROP(CurvetoCubicAbs, Y1, 1)
222 0 : IMPL_FLOAT_PROP(CurvetoCubicAbs, X2, 2)
223 0 : IMPL_FLOAT_PROP(CurvetoCubicAbs, Y2, 3)
224 0 : IMPL_FLOAT_PROP(CurvetoCubicAbs, X, 4)
225 0 : IMPL_FLOAT_PROP(CurvetoCubicAbs, Y, 5)
226 :
227 :
228 : ////////////////////////////////////////////////////////////////////////
229 :
230 0 : IMPL_FLOAT_PROP(CurvetoCubicRel, X1, 0)
231 0 : IMPL_FLOAT_PROP(CurvetoCubicRel, Y1, 1)
232 0 : IMPL_FLOAT_PROP(CurvetoCubicRel, X2, 2)
233 0 : IMPL_FLOAT_PROP(CurvetoCubicRel, Y2, 3)
234 0 : IMPL_FLOAT_PROP(CurvetoCubicRel, X, 4)
235 0 : IMPL_FLOAT_PROP(CurvetoCubicRel, Y, 5)
236 :
237 :
238 : ////////////////////////////////////////////////////////////////////////
239 :
240 0 : IMPL_FLOAT_PROP(CurvetoQuadraticAbs, X1, 0)
241 0 : IMPL_FLOAT_PROP(CurvetoQuadraticAbs, Y1, 1)
242 0 : IMPL_FLOAT_PROP(CurvetoQuadraticAbs, X, 2)
243 0 : IMPL_FLOAT_PROP(CurvetoQuadraticAbs, Y, 3)
244 :
245 :
246 : ////////////////////////////////////////////////////////////////////////
247 :
248 0 : IMPL_FLOAT_PROP(CurvetoQuadraticRel, X1, 0)
249 0 : IMPL_FLOAT_PROP(CurvetoQuadraticRel, Y1, 1)
250 0 : IMPL_FLOAT_PROP(CurvetoQuadraticRel, X, 2)
251 0 : IMPL_FLOAT_PROP(CurvetoQuadraticRel, Y, 3)
252 :
253 :
254 : ////////////////////////////////////////////////////////////////////////
255 :
256 0 : IMPL_FLOAT_PROP(ArcAbs, R1, 0)
257 0 : IMPL_FLOAT_PROP(ArcAbs, R2, 1)
258 0 : IMPL_FLOAT_PROP(ArcAbs, Angle, 2)
259 0 : IMPL_BOOL_PROP(ArcAbs, LargeArcFlag, 3)
260 0 : IMPL_BOOL_PROP(ArcAbs, SweepFlag, 4)
261 0 : IMPL_FLOAT_PROP(ArcAbs, X, 5)
262 0 : IMPL_FLOAT_PROP(ArcAbs, Y, 6)
263 :
264 :
265 : ////////////////////////////////////////////////////////////////////////
266 :
267 0 : IMPL_FLOAT_PROP(ArcRel, R1, 0)
268 0 : IMPL_FLOAT_PROP(ArcRel, R2, 1)
269 0 : IMPL_FLOAT_PROP(ArcRel, Angle, 2)
270 0 : IMPL_BOOL_PROP(ArcRel, LargeArcFlag, 3)
271 0 : IMPL_BOOL_PROP(ArcRel, SweepFlag, 4)
272 0 : IMPL_FLOAT_PROP(ArcRel, X, 5)
273 0 : IMPL_FLOAT_PROP(ArcRel, Y, 6)
274 :
275 :
276 : ////////////////////////////////////////////////////////////////////////
277 :
278 0 : IMPL_FLOAT_PROP(LinetoHorizontalAbs, X, 0)
279 :
280 :
281 : ////////////////////////////////////////////////////////////////////////
282 :
283 0 : IMPL_FLOAT_PROP(LinetoHorizontalRel, X, 0)
284 :
285 :
286 : ////////////////////////////////////////////////////////////////////////
287 :
288 0 : IMPL_FLOAT_PROP(LinetoVerticalAbs, Y, 0)
289 :
290 :
291 : ////////////////////////////////////////////////////////////////////////
292 :
293 0 : IMPL_FLOAT_PROP(LinetoVerticalRel, Y, 0)
294 :
295 :
296 : ////////////////////////////////////////////////////////////////////////
297 :
298 0 : IMPL_FLOAT_PROP(CurvetoCubicSmoothAbs, X2, 0)
299 0 : IMPL_FLOAT_PROP(CurvetoCubicSmoothAbs, Y2, 1)
300 0 : IMPL_FLOAT_PROP(CurvetoCubicSmoothAbs, X, 2)
301 0 : IMPL_FLOAT_PROP(CurvetoCubicSmoothAbs, Y, 3)
302 :
303 :
304 : ////////////////////////////////////////////////////////////////////////
305 :
306 0 : IMPL_FLOAT_PROP(CurvetoCubicSmoothRel, X2, 0)
307 0 : IMPL_FLOAT_PROP(CurvetoCubicSmoothRel, Y2, 1)
308 0 : IMPL_FLOAT_PROP(CurvetoCubicSmoothRel, X, 2)
309 0 : IMPL_FLOAT_PROP(CurvetoCubicSmoothRel, Y, 3)
310 :
311 :
312 : ////////////////////////////////////////////////////////////////////////
313 :
314 0 : IMPL_FLOAT_PROP(CurvetoQuadraticSmoothAbs, X, 0)
315 0 : IMPL_FLOAT_PROP(CurvetoQuadraticSmoothAbs, Y, 1)
316 :
317 :
318 : ////////////////////////////////////////////////////////////////////////
319 :
320 :
321 0 : IMPL_FLOAT_PROP(CurvetoQuadraticSmoothRel, X, 0)
322 0 : IMPL_FLOAT_PROP(CurvetoQuadraticSmoothRel, Y, 1)
323 :
324 :
325 :
326 : // This must come after DOMSVGPathSegClosePath et. al. have been declared.
327 : /* static */ DOMSVGPathSeg*
328 0 : DOMSVGPathSeg::CreateFor(DOMSVGPathSegList *aList,
329 : uint32_t aListIndex,
330 : bool aIsAnimValItem)
331 : {
332 0 : uint32_t dataIndex = aList->mItems[aListIndex].mInternalDataIndex;
333 0 : float *data = &aList->InternalList().mData[dataIndex];
334 0 : uint32_t type = SVGPathSegUtils::DecodeType(data[0]);
335 :
336 0 : switch (type)
337 : {
338 : case PATHSEG_CLOSEPATH:
339 0 : return new DOMSVGPathSegClosePath(aList, aListIndex, aIsAnimValItem);
340 : case PATHSEG_MOVETO_ABS:
341 0 : return new DOMSVGPathSegMovetoAbs(aList, aListIndex, aIsAnimValItem);
342 : case PATHSEG_MOVETO_REL:
343 0 : return new DOMSVGPathSegMovetoRel(aList, aListIndex, aIsAnimValItem);
344 : case PATHSEG_LINETO_ABS:
345 0 : return new DOMSVGPathSegLinetoAbs(aList, aListIndex, aIsAnimValItem);
346 : case PATHSEG_LINETO_REL:
347 0 : return new DOMSVGPathSegLinetoRel(aList, aListIndex, aIsAnimValItem);
348 : case PATHSEG_CURVETO_CUBIC_ABS:
349 0 : return new DOMSVGPathSegCurvetoCubicAbs(aList, aListIndex, aIsAnimValItem);
350 : case PATHSEG_CURVETO_CUBIC_REL:
351 0 : return new DOMSVGPathSegCurvetoCubicRel(aList, aListIndex, aIsAnimValItem);
352 : case PATHSEG_CURVETO_QUADRATIC_ABS:
353 0 : return new DOMSVGPathSegCurvetoQuadraticAbs(aList, aListIndex, aIsAnimValItem);
354 : case PATHSEG_CURVETO_QUADRATIC_REL:
355 0 : return new DOMSVGPathSegCurvetoQuadraticRel(aList, aListIndex, aIsAnimValItem);
356 : case PATHSEG_ARC_ABS:
357 0 : return new DOMSVGPathSegArcAbs(aList, aListIndex, aIsAnimValItem);
358 : case PATHSEG_ARC_REL:
359 0 : return new DOMSVGPathSegArcRel(aList, aListIndex, aIsAnimValItem);
360 : case PATHSEG_LINETO_HORIZONTAL_ABS:
361 0 : return new DOMSVGPathSegLinetoHorizontalAbs(aList, aListIndex, aIsAnimValItem);
362 : case PATHSEG_LINETO_HORIZONTAL_REL:
363 0 : return new DOMSVGPathSegLinetoHorizontalRel(aList, aListIndex, aIsAnimValItem);
364 : case PATHSEG_LINETO_VERTICAL_ABS:
365 0 : return new DOMSVGPathSegLinetoVerticalAbs(aList, aListIndex, aIsAnimValItem);
366 : case PATHSEG_LINETO_VERTICAL_REL:
367 0 : return new DOMSVGPathSegLinetoVerticalRel(aList, aListIndex, aIsAnimValItem);
368 : case PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
369 0 : return new DOMSVGPathSegCurvetoCubicSmoothAbs(aList, aListIndex, aIsAnimValItem);
370 : case PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
371 0 : return new DOMSVGPathSegCurvetoCubicSmoothRel(aList, aListIndex, aIsAnimValItem);
372 : case PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
373 0 : return new DOMSVGPathSegCurvetoQuadraticSmoothAbs(aList, aListIndex, aIsAnimValItem);
374 : case PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
375 0 : return new DOMSVGPathSegCurvetoQuadraticSmoothRel(aList, aListIndex, aIsAnimValItem);
376 : default:
377 0 : NS_NOTREACHED("Invalid path segment type");
378 0 : return nullptr;
379 : }
380 : }
381 :
382 : } // namespace mozilla
|