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