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