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