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 "mozilla/dom/SVGAnimatedTransformList.h"
8 #include "DOMSVGTransformList.h"
9 #include "nsSVGAnimatedTransformList.h"
10 #include "nsSVGAttrTearoffTable.h"
11 #include "mozilla/dom/SVGAnimatedTransformListBinding.h"
12 
13 namespace mozilla {
14 namespace dom {
15 
16 static
17   nsSVGAttrTearoffTable<nsSVGAnimatedTransformList, SVGAnimatedTransformList>
18   sSVGAnimatedTransformListTearoffTable;
19 
NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(SVGAnimatedTransformList,mElement)20 NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(SVGAnimatedTransformList, mElement)
21 
22 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(SVGAnimatedTransformList, AddRef)
23 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(SVGAnimatedTransformList, Release)
24 
25 JSObject*
26 SVGAnimatedTransformList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
27 {
28   return SVGAnimatedTransformListBinding::Wrap(aCx, this, aGivenProto);
29 }
30 
31 //----------------------------------------------------------------------
32 already_AddRefed<DOMSVGTransformList>
BaseVal()33 SVGAnimatedTransformList::BaseVal()
34 {
35   if (!mBaseVal) {
36     mBaseVal = new DOMSVGTransformList(this, InternalAList().GetBaseValue());
37   }
38   RefPtr<DOMSVGTransformList> baseVal = mBaseVal;
39   return baseVal.forget();
40 }
41 
42 already_AddRefed<DOMSVGTransformList>
AnimVal()43 SVGAnimatedTransformList::AnimVal()
44 {
45   if (!mAnimVal) {
46     mAnimVal = new DOMSVGTransformList(this, InternalAList().GetAnimValue());
47   }
48   RefPtr<DOMSVGTransformList> animVal = mAnimVal;
49   return animVal.forget();
50 }
51 
52 /* static */ already_AddRefed<SVGAnimatedTransformList>
GetDOMWrapper(nsSVGAnimatedTransformList * aList,nsSVGElement * aElement)53 SVGAnimatedTransformList::GetDOMWrapper(nsSVGAnimatedTransformList *aList,
54                                         nsSVGElement *aElement)
55 {
56   RefPtr<SVGAnimatedTransformList> wrapper =
57     sSVGAnimatedTransformListTearoffTable.GetTearoff(aList);
58   if (!wrapper) {
59     wrapper = new SVGAnimatedTransformList(aElement);
60     sSVGAnimatedTransformListTearoffTable.AddTearoff(aList, wrapper);
61   }
62   return wrapper.forget();
63 }
64 
65 /* static */ SVGAnimatedTransformList*
GetDOMWrapperIfExists(nsSVGAnimatedTransformList * aList)66 SVGAnimatedTransformList::GetDOMWrapperIfExists(
67   nsSVGAnimatedTransformList *aList)
68 {
69   return sSVGAnimatedTransformListTearoffTable.GetTearoff(aList);
70 }
71 
~SVGAnimatedTransformList()72 SVGAnimatedTransformList::~SVGAnimatedTransformList()
73 {
74   // Script no longer has any references to us, to our base/animVal objects, or
75   // to any of their list items.
76   sSVGAnimatedTransformListTearoffTable.RemoveTearoff(&InternalAList());
77 }
78 
79 void
InternalBaseValListWillChangeLengthTo(uint32_t aNewLength)80 SVGAnimatedTransformList::InternalBaseValListWillChangeLengthTo(
81   uint32_t aNewLength)
82 {
83   // When the number of items in our internal counterpart's baseVal changes,
84   // we MUST keep our baseVal in sync. If we don't, script will either see a
85   // list that is too short and be unable to access indexes that should be
86   // valid, or else, MUCH WORSE, script will see a list that is too long and be
87   // able to access "items" at indexes that are out of bounds (read/write to
88   // bad memory)!!
89 
90   RefPtr<SVGAnimatedTransformList> kungFuDeathGrip;
91   if (mBaseVal) {
92     if (aNewLength < mBaseVal->LengthNoFlush()) {
93       // InternalListLengthWillChange might clear last reference to |this|.
94       // Retain a temporary reference to keep from dying before returning.
95       kungFuDeathGrip = this;
96     }
97     mBaseVal->InternalListLengthWillChange(aNewLength);
98   }
99 
100   // If our attribute is not animating, then our animVal mirrors our baseVal
101   // and we must sync its length too. (If our attribute is animating, then the
102   // SMIL engine takes care of calling InternalAnimValListWillChangeLengthTo()
103   // if necessary.)
104 
105   if (!IsAnimating()) {
106     InternalAnimValListWillChangeLengthTo(aNewLength);
107   }
108 }
109 
110 void
InternalAnimValListWillChangeLengthTo(uint32_t aNewLength)111 SVGAnimatedTransformList::InternalAnimValListWillChangeLengthTo(
112   uint32_t aNewLength)
113 {
114   if (mAnimVal) {
115     mAnimVal->InternalListLengthWillChange(aNewLength);
116   }
117 }
118 
119 bool
IsAnimating() const120 SVGAnimatedTransformList::IsAnimating() const
121 {
122   return InternalAList().IsAnimating();
123 }
124 
125 nsSVGAnimatedTransformList&
InternalAList()126 SVGAnimatedTransformList::InternalAList()
127 {
128   return *mElement->GetAnimatedTransformList();
129 }
130 
131 const nsSVGAnimatedTransformList&
InternalAList() const132 SVGAnimatedTransformList::InternalAList() const
133 {
134   return *mElement->GetAnimatedTransformList();
135 }
136 
137 } // namespace dom
138 } // namespace mozilla
139