DOMSVGPathSeg.cpp 13 KB

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