SVGNumberList.h (6661B)
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_SVGNUMBERLIST_H_ 8 #define DOM_SVG_SVGNUMBERLIST_H_ 9 10 #include "SVGElement.h" 11 #include "nsCOMPtr.h" 12 #include "nsDebug.h" 13 #include "nsIContent.h" 14 #include "nsINode.h" 15 #include "nsIWeakReferenceUtils.h" 16 #include "nsTArray.h" 17 18 namespace mozilla { 19 20 namespace dom { 21 class DOMSVGNumber; 22 class DOMSVGNumberList; 23 } // namespace dom 24 25 /** 26 * ATTENTION! WARNING! WATCH OUT!! 27 * 28 * Consumers that modify objects of this type absolutely MUST keep the DOM 29 * wrappers for those lists (if any) in sync!! That's why this class is so 30 * locked down. 31 * 32 * The DOM wrapper class for this class is DOMSVGNumberList. 33 */ 34 class SVGNumberList { 35 friend class dom::DOMSVGNumber; 36 friend class dom::DOMSVGNumberList; 37 friend class SVGAnimatedNumberList; 38 39 public: 40 SVGNumberList() = default; 41 ~SVGNumberList() = default; 42 43 SVGNumberList& operator=(const SVGNumberList& aOther) { 44 mNumbers.ClearAndRetainStorage(); 45 // Best-effort, really. 46 (void)mNumbers.AppendElements(aOther.mNumbers, fallible); 47 return *this; 48 } 49 50 SVGNumberList(const SVGNumberList& aOther) { *this = aOther; } 51 52 // Only methods that don't make/permit modification to this list are public. 53 // Only our friend classes can access methods that may change us. 54 55 /// This may return an incomplete string on OOM, but that's acceptable. 56 void GetValueAsString(nsAString& aValue) const; 57 58 bool IsEmpty() const { return mNumbers.IsEmpty(); } 59 60 uint32_t Length() const { return mNumbers.Length(); } 61 62 const float& operator[](uint32_t aIndex) const { return mNumbers[aIndex]; } 63 64 [[nodiscard]] FallibleTArray<float>::const_iterator begin() const { 65 return mNumbers.begin(); 66 } 67 [[nodiscard]] FallibleTArray<float>::const_iterator end() const { 68 return mNumbers.end(); 69 } 70 71 bool operator==(const SVGNumberList& rhs) const { 72 return mNumbers == rhs.mNumbers; 73 } 74 75 bool SetCapacity(uint32_t size) { 76 return mNumbers.SetCapacity(size, fallible); 77 } 78 79 void Compact() { mNumbers.Compact(); } 80 81 // Access to methods that can modify objects of this type is deliberately 82 // limited. This is to reduce the chances of someone modifying objects of 83 // this type without taking the necessary steps to keep DOM wrappers in sync. 84 // If you need wider access to these methods, consider adding a method to 85 // SVGAnimatedNumberList and having that class act as an intermediary so it 86 // can take care of keeping DOM wrappers in sync. 87 88 protected: 89 /** 90 * This may fail on OOM if the internal capacity needs to be increased, in 91 * which case the list will be left unmodified. 92 */ 93 nsresult CopyFrom(const SVGNumberList& rhs); 94 void SwapWith(SVGNumberList& aRhs) { mNumbers.SwapElements(aRhs.mNumbers); } 95 96 float& operator[](uint32_t aIndex) { return mNumbers[aIndex]; } 97 98 /** 99 * This may fail (return false) on OOM if the internal capacity is being 100 * increased, in which case the list will be left unmodified. 101 */ 102 bool SetLength(uint32_t aNumberOfItems) { 103 return mNumbers.SetLength(aNumberOfItems, fallible); 104 } 105 106 private: 107 // Marking the following private only serves to show which methods are only 108 // used by our friend classes (as opposed to our subclasses) - it doesn't 109 // really provide additional safety. 110 111 nsresult SetValueFromString(const nsAString& aValue); 112 113 void Clear() { mNumbers.Clear(); } 114 115 bool InsertItem(uint32_t aIndex, const float& aNumber) { 116 if (aIndex >= mNumbers.Length()) { 117 aIndex = mNumbers.Length(); 118 } 119 return !!mNumbers.InsertElementAt(aIndex, aNumber, fallible); 120 } 121 122 void ReplaceItem(uint32_t aIndex, const float& aNumber) { 123 MOZ_ASSERT(aIndex < mNumbers.Length(), 124 "DOM wrapper caller should have raised INDEX_SIZE_ERR"); 125 mNumbers[aIndex] = aNumber; 126 } 127 128 void RemoveItem(uint32_t aIndex) { 129 MOZ_ASSERT(aIndex < mNumbers.Length(), 130 "DOM wrapper caller should have raised INDEX_SIZE_ERR"); 131 mNumbers.RemoveElementAt(aIndex); 132 } 133 134 bool AppendItem(float aNumber) { 135 return !!mNumbers.AppendElement(aNumber, fallible); 136 } 137 138 protected: 139 /* See SVGLengthList for the rationale for using FallibleTArray<float> instead 140 * of FallibleTArray<float, 1>. 141 */ 142 FallibleTArray<float> mNumbers; 143 }; 144 145 /** 146 * This SVGNumberList subclass is used by the SMIL code when a number list 147 * is to be stored in a SMILValue instance. Since SMILValue objects may 148 * be cached, it is necessary for us to hold a strong reference to our element 149 * so that it doesn't disappear out from under us if, say, the element is 150 * removed from the DOM tree. 151 */ 152 class SVGNumberListAndInfo : public SVGNumberList { 153 public: 154 SVGNumberListAndInfo() : mElement(nullptr) {} 155 156 explicit SVGNumberListAndInfo(dom::SVGElement* aElement) 157 : mElement(do_GetWeakReference(static_cast<nsINode*>(aElement))) {} 158 159 void SetInfo(dom::SVGElement* aElement) { 160 mElement = do_GetWeakReference(static_cast<nsINode*>(aElement)); 161 } 162 163 dom::SVGElement* Element() const { 164 nsCOMPtr<nsIContent> e = do_QueryReferent(mElement); 165 return static_cast<dom::SVGElement*>(e.get()); 166 } 167 168 nsresult CopyFrom(const SVGNumberListAndInfo& rhs) { 169 mElement = rhs.mElement; 170 return SVGNumberList::CopyFrom(rhs); 171 } 172 173 // Instances of this special subclass do not have DOM wrappers that we need 174 // to worry about keeping in sync, so it's safe to expose any hidden base 175 // class methods required by the SMIL code, as we do below. 176 177 /** 178 * Exposed so that SVGNumberList baseVals can be copied to 179 * SVGNumberListAndInfo objects. Note that callers should also call 180 * SetInfo() when using this method! 181 */ 182 nsresult CopyFrom(const SVGNumberList& rhs) { 183 return SVGNumberList::CopyFrom(rhs); 184 } 185 const float& operator[](uint32_t aIndex) const { 186 return SVGNumberList::operator[](aIndex); 187 } 188 float& operator[](uint32_t aIndex) { 189 return SVGNumberList::operator[](aIndex); 190 } 191 bool SetLength(uint32_t aNumberOfItems) { 192 return SVGNumberList::SetLength(aNumberOfItems); 193 } 194 195 private: 196 // We must keep a weak reference to our element because we may belong to a 197 // cached baseVal SMILValue. See the comments starting at: 198 // https://bugzilla.mozilla.org/show_bug.cgi?id=515116#c15 199 // See also https://bugzilla.mozilla.org/show_bug.cgi?id=653497 200 nsWeakPtr mElement; 201 }; 202 203 } // namespace mozilla 204 205 #endif // DOM_SVG_SVGNUMBERLIST_H_