SVGAnimatedPreserveAspectRatio.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  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 "mozilla/ArrayUtils.h"
  6. #include "SVGAnimatedPreserveAspectRatio.h"
  7. #include "mozilla/dom/SVGAnimatedPreserveAspectRatioBinding.h"
  8. #include "nsSMILValue.h"
  9. #include "nsSVGAttrTearoffTable.h"
  10. #include "nsWhitespaceTokenizer.h"
  11. #include "SMILEnumType.h"
  12. #include "SVGContentUtils.h"
  13. using namespace mozilla;
  14. using namespace mozilla::dom;
  15. ////////////////////////////////////////////////////////////////////////
  16. // SVGAnimatedPreserveAspectRatio class
  17. NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(DOMSVGAnimatedPreserveAspectRatio, mSVGElement)
  18. NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGAnimatedPreserveAspectRatio)
  19. NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGAnimatedPreserveAspectRatio)
  20. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGAnimatedPreserveAspectRatio)
  21. NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  22. NS_INTERFACE_MAP_ENTRY(nsISupports)
  23. NS_INTERFACE_MAP_END
  24. JSObject*
  25. DOMSVGAnimatedPreserveAspectRatio::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
  26. {
  27. return SVGAnimatedPreserveAspectRatioBinding::Wrap(aCx, this, aGivenProto);
  28. }
  29. /* Implementation */
  30. static const char *sAlignStrings[] =
  31. { "none", "xMinYMin", "xMidYMin", "xMaxYMin", "xMinYMid", "xMidYMid",
  32. "xMaxYMid", "xMinYMax", "xMidYMax", "xMaxYMax" };
  33. static const char *sMeetOrSliceStrings[] = { "meet", "slice" };
  34. static nsSVGAttrTearoffTable<SVGAnimatedPreserveAspectRatio, DOMSVGAnimatedPreserveAspectRatio>
  35. sSVGAnimatedPAspectRatioTearoffTable;
  36. static nsSVGAttrTearoffTable<SVGAnimatedPreserveAspectRatio, DOMSVGPreserveAspectRatio>
  37. sBaseSVGPAspectRatioTearoffTable;
  38. static nsSVGAttrTearoffTable<SVGAnimatedPreserveAspectRatio, DOMSVGPreserveAspectRatio>
  39. sAnimSVGPAspectRatioTearoffTable;
  40. static uint16_t
  41. GetAlignForString(const nsAString &aAlignString)
  42. {
  43. for (uint32_t i = 0 ; i < ArrayLength(sAlignStrings) ; i++) {
  44. if (aAlignString.EqualsASCII(sAlignStrings[i])) {
  45. return (i + SVG_ALIGN_MIN_VALID);
  46. }
  47. }
  48. return SVG_PRESERVEASPECTRATIO_UNKNOWN;
  49. }
  50. static void
  51. GetAlignString(nsAString& aAlignString, uint16_t aAlign)
  52. {
  53. NS_ASSERTION(
  54. aAlign >= SVG_ALIGN_MIN_VALID && aAlign <= SVG_ALIGN_MAX_VALID,
  55. "Unknown align");
  56. aAlignString.AssignASCII(
  57. sAlignStrings[aAlign - SVG_ALIGN_MIN_VALID]);
  58. }
  59. static uint16_t
  60. GetMeetOrSliceForString(const nsAString &aMeetOrSlice)
  61. {
  62. for (uint32_t i = 0 ; i < ArrayLength(sMeetOrSliceStrings) ; i++) {
  63. if (aMeetOrSlice.EqualsASCII(sMeetOrSliceStrings[i])) {
  64. return (i + SVG_MEETORSLICE_MIN_VALID);
  65. }
  66. }
  67. return SVG_MEETORSLICE_UNKNOWN;
  68. }
  69. static void
  70. GetMeetOrSliceString(nsAString& aMeetOrSliceString, uint16_t aMeetOrSlice)
  71. {
  72. NS_ASSERTION(
  73. aMeetOrSlice >= SVG_MEETORSLICE_MIN_VALID &&
  74. aMeetOrSlice <= SVG_MEETORSLICE_MAX_VALID,
  75. "Unknown meetOrSlice");
  76. aMeetOrSliceString.AssignASCII(
  77. sMeetOrSliceStrings[aMeetOrSlice - SVG_MEETORSLICE_MIN_VALID]);
  78. }
  79. already_AddRefed<DOMSVGPreserveAspectRatio>
  80. DOMSVGAnimatedPreserveAspectRatio::BaseVal()
  81. {
  82. RefPtr<DOMSVGPreserveAspectRatio> domBaseVal =
  83. sBaseSVGPAspectRatioTearoffTable.GetTearoff(mVal);
  84. if (!domBaseVal) {
  85. domBaseVal = new DOMSVGPreserveAspectRatio(mVal, mSVGElement, true);
  86. sBaseSVGPAspectRatioTearoffTable.AddTearoff(mVal, domBaseVal);
  87. }
  88. return domBaseVal.forget();
  89. }
  90. DOMSVGPreserveAspectRatio::~DOMSVGPreserveAspectRatio()
  91. {
  92. if (mIsBaseValue) {
  93. sBaseSVGPAspectRatioTearoffTable.RemoveTearoff(mVal);
  94. } else {
  95. sAnimSVGPAspectRatioTearoffTable.RemoveTearoff(mVal);
  96. }
  97. }
  98. already_AddRefed<DOMSVGPreserveAspectRatio>
  99. DOMSVGAnimatedPreserveAspectRatio::AnimVal()
  100. {
  101. RefPtr<DOMSVGPreserveAspectRatio> domAnimVal =
  102. sAnimSVGPAspectRatioTearoffTable.GetTearoff(mVal);
  103. if (!domAnimVal) {
  104. domAnimVal = new DOMSVGPreserveAspectRatio(mVal, mSVGElement, false);
  105. sAnimSVGPAspectRatioTearoffTable.AddTearoff(mVal, domAnimVal);
  106. }
  107. return domAnimVal.forget();
  108. }
  109. static nsresult
  110. ToPreserveAspectRatio(const nsAString &aString,
  111. SVGPreserveAspectRatio *aValue)
  112. {
  113. nsWhitespaceTokenizerTemplate<IsSVGWhitespace> tokenizer(aString);
  114. if (tokenizer.whitespaceBeforeFirstToken() ||
  115. !tokenizer.hasMoreTokens()) {
  116. return NS_ERROR_DOM_SYNTAX_ERR;
  117. }
  118. const nsAString &token = tokenizer.nextToken();
  119. nsresult rv;
  120. SVGPreserveAspectRatio val;
  121. rv = val.SetAlign(GetAlignForString(token));
  122. if (NS_FAILED(rv)) {
  123. return NS_ERROR_DOM_SYNTAX_ERR;
  124. }
  125. if (tokenizer.hasMoreTokens()) {
  126. rv = val.SetMeetOrSlice(GetMeetOrSliceForString(tokenizer.nextToken()));
  127. if (NS_FAILED(rv)) {
  128. return NS_ERROR_DOM_SYNTAX_ERR;
  129. }
  130. } else {
  131. val.SetMeetOrSlice(SVG_MEETORSLICE_MEET);
  132. }
  133. if (tokenizer.whitespaceAfterCurrentToken()) {
  134. return NS_ERROR_DOM_SYNTAX_ERR;
  135. }
  136. *aValue = val;
  137. return NS_OK;
  138. }
  139. nsresult
  140. SVGAnimatedPreserveAspectRatio::SetBaseValueString(
  141. const nsAString &aValueAsString, nsSVGElement *aSVGElement, bool aDoSetAttr)
  142. {
  143. SVGPreserveAspectRatio val;
  144. nsresult res = ToPreserveAspectRatio(aValueAsString, &val);
  145. if (NS_FAILED(res)) {
  146. return res;
  147. }
  148. nsAttrValue emptyOrOldValue;
  149. if (aDoSetAttr) {
  150. emptyOrOldValue = aSVGElement->WillChangePreserveAspectRatio();
  151. }
  152. mBaseVal = val;
  153. mIsBaseSet = true;
  154. if (!mIsAnimated) {
  155. mAnimVal = mBaseVal;
  156. }
  157. if (aDoSetAttr) {
  158. aSVGElement->DidChangePreserveAspectRatio(emptyOrOldValue);
  159. }
  160. if (mIsAnimated) {
  161. aSVGElement->AnimationNeedsResample();
  162. }
  163. return NS_OK;
  164. }
  165. void
  166. SVGAnimatedPreserveAspectRatio::GetBaseValueString(
  167. nsAString& aValueAsString) const
  168. {
  169. nsAutoString tmpString;
  170. aValueAsString.Truncate();
  171. GetAlignString(tmpString, mBaseVal.mAlign);
  172. aValueAsString.Append(tmpString);
  173. if (mBaseVal.mAlign != uint8_t(SVG_PRESERVEASPECTRATIO_NONE)) {
  174. aValueAsString.Append(' ');
  175. GetMeetOrSliceString(tmpString, mBaseVal.mMeetOrSlice);
  176. aValueAsString.Append(tmpString);
  177. }
  178. }
  179. void
  180. SVGAnimatedPreserveAspectRatio::SetBaseValue(const SVGPreserveAspectRatio &aValue,
  181. nsSVGElement *aSVGElement)
  182. {
  183. if (mIsBaseSet && mBaseVal == aValue) {
  184. return;
  185. }
  186. nsAttrValue emptyOrOldValue = aSVGElement->WillChangePreserveAspectRatio();
  187. mBaseVal = aValue;
  188. mIsBaseSet = true;
  189. if (!mIsAnimated) {
  190. mAnimVal = mBaseVal;
  191. }
  192. aSVGElement->DidChangePreserveAspectRatio(emptyOrOldValue);
  193. if (mIsAnimated) {
  194. aSVGElement->AnimationNeedsResample();
  195. }
  196. }
  197. static uint64_t
  198. PackPreserveAspectRatio(const SVGPreserveAspectRatio& par)
  199. {
  200. // All preserveAspectRatio values are enum values (do not interpolate), so we
  201. // can safely collate them and treat them as a single enum as for SMIL.
  202. uint64_t packed = 0;
  203. packed |= uint64_t(par.GetAlign()) << 8;
  204. packed |= uint64_t(par.GetMeetOrSlice());
  205. return packed;
  206. }
  207. void
  208. SVGAnimatedPreserveAspectRatio::SetAnimValue(uint64_t aPackedValue,
  209. nsSVGElement *aSVGElement)
  210. {
  211. if (mIsAnimated && PackPreserveAspectRatio(mAnimVal) == aPackedValue) {
  212. return;
  213. }
  214. mAnimVal.SetAlign(uint16_t((aPackedValue & 0xff00) >> 8));
  215. mAnimVal.SetMeetOrSlice(uint16_t(aPackedValue & 0xff));
  216. mIsAnimated = true;
  217. aSVGElement->DidAnimatePreserveAspectRatio();
  218. }
  219. already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
  220. SVGAnimatedPreserveAspectRatio::ToDOMAnimatedPreserveAspectRatio(
  221. nsSVGElement *aSVGElement)
  222. {
  223. RefPtr<DOMSVGAnimatedPreserveAspectRatio> domAnimatedPAspectRatio =
  224. sSVGAnimatedPAspectRatioTearoffTable.GetTearoff(this);
  225. if (!domAnimatedPAspectRatio) {
  226. domAnimatedPAspectRatio = new DOMSVGAnimatedPreserveAspectRatio(this, aSVGElement);
  227. sSVGAnimatedPAspectRatioTearoffTable.AddTearoff(this, domAnimatedPAspectRatio);
  228. }
  229. return domAnimatedPAspectRatio.forget();
  230. }
  231. DOMSVGAnimatedPreserveAspectRatio::~DOMSVGAnimatedPreserveAspectRatio()
  232. {
  233. sSVGAnimatedPAspectRatioTearoffTable.RemoveTearoff(mVal);
  234. }
  235. nsISMILAttr*
  236. SVGAnimatedPreserveAspectRatio::ToSMILAttr(nsSVGElement *aSVGElement)
  237. {
  238. return new SMILPreserveAspectRatio(this, aSVGElement);
  239. }
  240. // typedef for inner class, to make function signatures shorter below:
  241. typedef SVGAnimatedPreserveAspectRatio::SMILPreserveAspectRatio
  242. SMILPreserveAspectRatio;
  243. nsresult
  244. SMILPreserveAspectRatio::ValueFromString(const nsAString& aStr,
  245. const SVGAnimationElement* /*aSrcElement*/,
  246. nsSMILValue& aValue,
  247. bool& aPreventCachingOfSandwich) const
  248. {
  249. SVGPreserveAspectRatio par;
  250. nsresult res = ToPreserveAspectRatio(aStr, &par);
  251. NS_ENSURE_SUCCESS(res, res);
  252. nsSMILValue val(SMILEnumType::Singleton());
  253. val.mU.mUint = PackPreserveAspectRatio(par);
  254. aValue = val;
  255. aPreventCachingOfSandwich = false;
  256. return NS_OK;
  257. }
  258. nsSMILValue
  259. SMILPreserveAspectRatio::GetBaseValue() const
  260. {
  261. nsSMILValue val(SMILEnumType::Singleton());
  262. val.mU.mUint = PackPreserveAspectRatio(mVal->GetBaseValue());
  263. return val;
  264. }
  265. void
  266. SMILPreserveAspectRatio::ClearAnimValue()
  267. {
  268. if (mVal->mIsAnimated) {
  269. mVal->mIsAnimated = false;
  270. mVal->mAnimVal = mVal->mBaseVal;
  271. mSVGElement->DidAnimatePreserveAspectRatio();
  272. }
  273. }
  274. nsresult
  275. SMILPreserveAspectRatio::SetAnimValue(const nsSMILValue& aValue)
  276. {
  277. NS_ASSERTION(aValue.mType == SMILEnumType::Singleton(),
  278. "Unexpected type to assign animated value");
  279. if (aValue.mType == SMILEnumType::Singleton()) {
  280. mVal->SetAnimValue(aValue.mU.mUint, mSVGElement);
  281. }
  282. return NS_OK;
  283. }