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