DOMSVGLengthList.h (7272B)
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 #ifndef DOM_SVG_DOMSVGLENGTHLIST_H_ 8 #define DOM_SVG_DOMSVGLENGTHLIST_H_ 9 10 #include "DOMSVGAnimatedLengthList.h" 11 #include "SVGLengthList.h" 12 #include "mozAutoDocUpdate.h" 13 #include "mozilla/Attributes.h" 14 #include "nsCycleCollectionParticipant.h" 15 #include "nsDebug.h" 16 #include "nsTArray.h" 17 18 // {cbecb7a4-d6f3-47b5-b5a3-3e5bdbf5b2f9} 19 #define MOZILLA_DOMSVGLENGTHLIST_IID \ 20 {0xcbecb7a4, 0xd6f3, 0xd6f3, {0xb5, 0xa3, 0x3e, 0x5b, 0xdb, 0xf5, 0xb2, 0xf9}} 21 22 namespace mozilla { 23 class ErrorResult; 24 25 namespace dom { 26 class DOMSVGLength; 27 class SVGElement; 28 29 //---------------------------------------------------------------------- 30 // Helper class: AutoChangeLengthListNotifier 31 // Stack-based helper class to pair calls to WillChangeLengthList and 32 // DidChangeLengthList. Used by DOMSVGLength and DOMSVGLengthList. 33 template <class T> 34 class MOZ_RAII AutoChangeLengthListNotifier : public mozAutoDocUpdate { 35 public: 36 explicit AutoChangeLengthListNotifier(T* aValue) 37 : mozAutoDocUpdate(aValue->Element()->GetComposedDoc(), true), 38 mValue(aValue) { 39 MOZ_ASSERT(aValue, "Expecting non-null value"); 40 mValue->Element()->WillChangeLengthList(mValue->AttrEnum(), *this); 41 } 42 43 ~AutoChangeLengthListNotifier() { 44 mValue->Element()->DidChangeLengthList(mValue->AttrEnum(), *this); 45 if (mValue->IsAnimating()) { 46 mValue->Element()->AnimationNeedsResample(); 47 } 48 } 49 50 private: 51 T* const mValue; 52 }; 53 54 /** 55 * Class DOMSVGLengthList 56 * 57 * This class is used to create the DOM tearoff objects that wrap internal 58 * SVGLengthList objects. 59 * 60 * See the architecture comment in DOMSVGAnimatedLengthList.h. 61 * 62 * This class is strongly intertwined with DOMSVGAnimatedLengthList and 63 * DOMSVGLength. We are a friend of DOMSVGAnimatedLengthList, and are 64 * responsible for nulling out our DOMSVGAnimatedLengthList's pointer to us 65 * when we die, essentially making its pointer to us a weak pointer. Similarly, 66 * our DOMSVGLength items are friends of us and responsible for nulling out our 67 * pointers to them. 68 * 69 * Our DOM items are created lazily on demand as and when script requests them. 70 */ 71 class DOMSVGLengthList final : public nsISupports, public nsWrapperCache { 72 template <class T> 73 friend class AutoChangeLengthListNotifier; 74 friend class DOMSVGLength; 75 76 ~DOMSVGLengthList() { 77 // Our mAList's weak ref to us must be nulled out when we die. If GC has 78 // unlinked us using the cycle collector code, then that has already 79 // happened, and mAList is null. 80 if (mAList) { 81 (IsAnimValList() ? mAList->mAnimVal : mAList->mBaseVal) = nullptr; 82 } 83 } 84 85 public: 86 NS_INLINE_DECL_STATIC_IID(MOZILLA_DOMSVGLENGTHLIST_IID) 87 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 88 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMSVGLengthList) 89 90 DOMSVGLengthList(DOMSVGAnimatedLengthList* aAList, 91 const SVGLengthList& aInternalList) 92 : mAList(aAList) { 93 // aInternalList must be passed in explicitly because we can't use 94 // InternalList() here. (Because it depends on IsAnimValList, which depends 95 // on this object having been assigned to aAList's mBaseVal or mAnimVal, 96 // which hasn't happened yet.) 97 98 InternalListLengthWillChange(aInternalList.Length()); // Sync mItems 99 } 100 101 JSObject* WrapObject(JSContext* cx, 102 JS::Handle<JSObject*> aGivenProto) override; 103 104 nsISupports* GetParentObject() { return static_cast<nsIContent*>(Element()); } 105 106 /** 107 * This will normally be the same as InternalList().Length(), except if we've 108 * hit OOM in which case our length will be zero. 109 */ 110 uint32_t LengthNoFlush() const { 111 MOZ_ASSERT( 112 mItems.Length() == 0 || mItems.Length() == InternalList().Length(), 113 "DOM wrapper's list length is out of sync"); 114 return mItems.Length(); 115 } 116 117 /// Called to notify us to synchronize our length and detach excess items. 118 void InternalListLengthWillChange(uint32_t aNewLength); 119 120 /** 121 * Returns true if our attribute is animating (in which case our animVal is 122 * not simply a mirror of our baseVal). 123 */ 124 bool IsAnimating() const { return mAList->IsAnimating(); } 125 /** 126 * Returns true if there is an animated list mirroring the base list. 127 */ 128 bool AnimListMirrorsBaseList() const { 129 return mAList->mAnimVal && !mAList->IsAnimating(); 130 } 131 132 uint32_t NumberOfItems() const { 133 if (IsAnimValList()) { 134 Element()->FlushAnimations(); 135 } 136 return LengthNoFlush(); 137 } 138 void Clear(ErrorResult& aError); 139 already_AddRefed<DOMSVGLength> Initialize(DOMSVGLength& newItem, 140 ErrorResult& aRv); 141 already_AddRefed<DOMSVGLength> GetItem(uint32_t index, ErrorResult& aRv); 142 already_AddRefed<DOMSVGLength> IndexedGetter(uint32_t index, bool& found, 143 ErrorResult& aRv); 144 already_AddRefed<DOMSVGLength> InsertItemBefore(DOMSVGLength& newItem, 145 uint32_t index, 146 ErrorResult& aRv); 147 already_AddRefed<DOMSVGLength> ReplaceItem(DOMSVGLength& newItem, 148 uint32_t index, ErrorResult& aRv); 149 already_AddRefed<DOMSVGLength> RemoveItem(uint32_t index, ErrorResult& aRv); 150 already_AddRefed<DOMSVGLength> AppendItem(DOMSVGLength& newItem, 151 ErrorResult& aRv) { 152 return InsertItemBefore(newItem, LengthNoFlush(), aRv); 153 } 154 void IndexedSetter(uint32_t index, DOMSVGLength& newValue, ErrorResult& aRv); 155 uint32_t Length() const { return NumberOfItems(); } 156 157 private: 158 dom::SVGElement* Element() const { return mAList->mElement; } 159 160 uint8_t AttrEnum() const { return mAList->mAttrEnum; } 161 162 uint8_t Axis() const { return mAList->mAxis; } 163 164 /// Used to determine if this list is the baseVal or animVal list. 165 bool IsAnimValList() const { 166 MOZ_ASSERT(this == mAList->mBaseVal || this == mAList->mAnimVal, 167 "Calling IsAnimValList() too early?!"); 168 return this == mAList->mAnimVal; 169 } 170 171 /** 172 * Get a reference to this object's corresponding internal SVGLengthList. 173 * 174 * To simplify the code we just have this one method for obtaining both 175 * baseVal and animVal internal lists. This means that animVal lists don't 176 * get const protection, but our setter methods guard against changing 177 * animVal lists. 178 */ 179 SVGLengthList& InternalList() const; 180 181 /// Returns the DOMSVGLength at aIndex, creating it if necessary. 182 already_AddRefed<DOMSVGLength> GetItemAt(uint32_t aIndex); 183 184 void MaybeInsertNullInAnimValListAt(uint32_t aIndex); 185 void MaybeRemoveItemFromAnimValListAt(uint32_t aIndex); 186 187 // Weak refs to our DOMSVGLength items. The items are friends and take care 188 // of clearing our pointer to them when they die. 189 FallibleTArray<DOMSVGLength*> mItems; 190 191 RefPtr<DOMSVGAnimatedLengthList> mAList; 192 }; 193 194 } // namespace dom 195 } // namespace mozilla 196 197 #endif // DOM_SVG_DOMSVGLENGTHLIST_H_