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