1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla SVG Project code.
16 : *
17 : * The Initial Developer of the Original Code is the Mozilla Foundation.
18 : * Portions created by the Initial Developer are Copyright (C) 2010
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : *
23 : * Alternatively, the contents of this file may be used under the terms of
24 : * either the GNU General Public License Version 2 or later (the "GPL"), or
25 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 : * in which case the provisions of the GPL or the LGPL are applicable instead
27 : * of those above. If you wish to allow use of your version of this file only
28 : * under the terms of either the GPL or the LGPL, and not to allow others to
29 : * use your version of this file under the terms of the MPL, indicate your
30 : * decision by deleting the provisions above and replace them with the notice
31 : * and other provisions required by the GPL or the LGPL. If you do not delete
32 : * the provisions above, a recipient may use your version of this file under
33 : * the terms of any one of the MPL, the GPL or the LGPL.
34 : *
35 : * ***** END LICENSE BLOCK ***** */
36 :
37 : #ifndef MOZILLA_SVGPATHSEGUTILS_H__
38 : #define MOZILLA_SVGPATHSEGUTILS_H__
39 :
40 : #include "gfxPoint.h"
41 : #include "nsDebug.h"
42 : #include "nsIDOMSVGPathSeg.h"
43 : #include "nsMemory.h"
44 :
45 : #define NS_SVG_PATH_SEG_MAX_ARGS 7
46 : #define NS_SVG_PATH_SEG_FIRST_VALID_TYPE nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH
47 : #define NS_SVG_PATH_SEG_LAST_VALID_TYPE nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL
48 : #define NS_SVG_PATH_SEG_TYPE_COUNT (NS_SVG_PATH_SEG_LAST_VALID_TYPE + 1)
49 :
50 : namespace mozilla {
51 :
52 : /**
53 : * Code that works with path segments can use an instance of this class to
54 : * store/provide information about the start of the current subpath and the
55 : * last path segment (if any).
56 : */
57 : struct SVGPathTraversalState
58 : {
59 : enum TraversalMode {
60 : eUpdateAll,
61 : eUpdateOnlyStartAndCurrentPos
62 : };
63 :
64 0 : SVGPathTraversalState()
65 : : start(0.0, 0.0)
66 : , pos(0.0, 0.0)
67 : , cp1(0.0, 0.0)
68 : , cp2(0.0, 0.0)
69 : , length(0.0)
70 0 : , mode(eUpdateAll)
71 0 : {}
72 :
73 0 : bool ShouldUpdateLengthAndControlPoints() { return mode == eUpdateAll; }
74 :
75 : gfxPoint start; // start point of current sub path (reset each moveto)
76 :
77 : gfxPoint pos; // current position (end point of previous segment)
78 :
79 : gfxPoint cp1; // quadratic control point - if the previous segment was a
80 : // quadratic bezier curve then this is set to the absolute
81 : // position of its control point, otherwise its set to pos
82 :
83 : gfxPoint cp2; // cubic control point - if the previous segment was a cubic
84 : // bezier curve then this is set to the absolute position of
85 : // its second control point, otherwise it's set to pos
86 :
87 : float length; // accumulated path length
88 :
89 : TraversalMode mode; // indicates what to track while traversing a path
90 : };
91 :
92 :
93 : /**
94 : * This class is just a collection of static methods - it doesn't have any data
95 : * members, and it's not possible to create instances of this class. This class
96 : * exists purely as a convenient place to gather together a bunch of methods
97 : * related to manipulating and answering questions about path segments.
98 : * Internally we represent path segments purely as an array of floats. See the
99 : * comment documenting SVGPathData for more info on that.
100 : *
101 : * The DOM wrapper classes for encoded path segments (data contained in
102 : * instances of SVGPathData) is DOMSVGPathSeg and its sub-classes. Note that
103 : * there are multiple different DOM classes for path segs - one for each of the
104 : * 19 SVG 1.1 segment types.
105 : */
106 : class SVGPathSegUtils
107 : {
108 : private:
109 : SVGPathSegUtils(){} // private to prevent instances
110 :
111 : public:
112 :
113 : static void GetValueAsString(const float *aSeg, nsAString& aValue);
114 :
115 : /**
116 : * Encode a segment type enum to a float.
117 : *
118 : * At some point in the future we will likely want to encode other
119 : * information into the float, such as whether the command was explicit or
120 : * not. For now all this method does is save on int to float runtime
121 : * conversion by requiring PRUint32 and float to be of the same size so we
122 : * can simply do a bitwise PRUint32<->float copy.
123 : */
124 0 : static float EncodeType(PRUint32 aType) {
125 : PR_STATIC_ASSERT(sizeof(PRUint32) == sizeof(float));
126 0 : NS_ABORT_IF_FALSE(IsValidType(aType), "Seg type not recognized");
127 0 : return *(reinterpret_cast<float*>(&aType));
128 : }
129 :
130 0 : static PRUint32 DecodeType(float aType) {
131 : PR_STATIC_ASSERT(sizeof(PRUint32) == sizeof(float));
132 0 : PRUint32 type = *(reinterpret_cast<PRUint32*>(&aType));
133 0 : NS_ABORT_IF_FALSE(IsValidType(type), "Seg type not recognized");
134 0 : return type;
135 : }
136 :
137 0 : static PRUnichar GetPathSegTypeAsLetter(PRUint32 aType) {
138 0 : NS_ABORT_IF_FALSE(IsValidType(aType), "Seg type not recognized");
139 :
140 : static const PRUnichar table[] = {
141 : PRUnichar('x'), // 0 == PATHSEG_UNKNOWN
142 : PRUnichar('z'), // 1 == PATHSEG_CLOSEPATH
143 : PRUnichar('M'), // 2 == PATHSEG_MOVETO_ABS
144 : PRUnichar('m'), // 3 == PATHSEG_MOVETO_REL
145 : PRUnichar('L'), // 4 == PATHSEG_LINETO_ABS
146 : PRUnichar('l'), // 5 == PATHSEG_LINETO_REL
147 : PRUnichar('C'), // 6 == PATHSEG_CURVETO_CUBIC_ABS
148 : PRUnichar('c'), // 7 == PATHSEG_CURVETO_CUBIC_REL
149 : PRUnichar('Q'), // 8 == PATHSEG_CURVETO_QUADRATIC_ABS
150 : PRUnichar('q'), // 9 == PATHSEG_CURVETO_QUADRATIC_REL
151 : PRUnichar('A'), // 10 == PATHSEG_ARC_ABS
152 : PRUnichar('a'), // 11 == PATHSEG_ARC_REL
153 : PRUnichar('H'), // 12 == PATHSEG_LINETO_HORIZONTAL_ABS
154 : PRUnichar('h'), // 13 == PATHSEG_LINETO_HORIZONTAL_REL
155 : PRUnichar('V'), // 14 == PATHSEG_LINETO_VERTICAL_ABS
156 : PRUnichar('v'), // 15 == PATHSEG_LINETO_VERTICAL_REL
157 : PRUnichar('S'), // 16 == PATHSEG_CURVETO_CUBIC_SMOOTH_ABS
158 : PRUnichar('s'), // 17 == PATHSEG_CURVETO_CUBIC_SMOOTH_REL
159 : PRUnichar('T'), // 18 == PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS
160 : PRUnichar('t') // 19 == PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL
161 : };
162 : PR_STATIC_ASSERT(NS_ARRAY_LENGTH(table) == NS_SVG_PATH_SEG_TYPE_COUNT);
163 :
164 0 : return table[aType];
165 : }
166 :
167 0 : static PRUint32 ArgCountForType(PRUint32 aType) {
168 0 : NS_ABORT_IF_FALSE(IsValidType(aType), "Seg type not recognized");
169 :
170 : static const PRUint8 table[] = {
171 : 0, // 0 == PATHSEG_UNKNOWN
172 : 0, // 1 == PATHSEG_CLOSEPATH
173 : 2, // 2 == PATHSEG_MOVETO_ABS
174 : 2, // 3 == PATHSEG_MOVETO_REL
175 : 2, // 4 == PATHSEG_LINETO_ABS
176 : 2, // 5 == PATHSEG_LINETO_REL
177 : 6, // 6 == PATHSEG_CURVETO_CUBIC_ABS
178 : 6, // 7 == PATHSEG_CURVETO_CUBIC_REL
179 : 4, // 8 == PATHSEG_CURVETO_QUADRATIC_ABS
180 : 4, // 9 == PATHSEG_CURVETO_QUADRATIC_REL
181 : 7, // 10 == PATHSEG_ARC_ABS
182 : 7, // 11 == PATHSEG_ARC_REL
183 : 1, // 12 == PATHSEG_LINETO_HORIZONTAL_ABS
184 : 1, // 13 == PATHSEG_LINETO_HORIZONTAL_REL
185 : 1, // 14 == PATHSEG_LINETO_VERTICAL_ABS
186 : 1, // 15 == PATHSEG_LINETO_VERTICAL_REL
187 : 4, // 16 == PATHSEG_CURVETO_CUBIC_SMOOTH_ABS
188 : 4, // 17 == PATHSEG_CURVETO_CUBIC_SMOOTH_REL
189 : 2, // 18 == PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS
190 : 2 // 19 == PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL
191 : };
192 : PR_STATIC_ASSERT(NS_ARRAY_LENGTH(table) == NS_SVG_PATH_SEG_TYPE_COUNT);
193 :
194 0 : return table[aType];
195 : }
196 :
197 : /**
198 : * Convenience so that callers can pass a float containing an encoded type
199 : * and have it decoded implicitly.
200 : */
201 0 : static PRUint32 ArgCountForType(float aType) {
202 0 : return ArgCountForType(DecodeType(aType));
203 : }
204 :
205 0 : static bool IsValidType(PRUint32 aType) {
206 : return aType >= NS_SVG_PATH_SEG_FIRST_VALID_TYPE &&
207 0 : aType <= NS_SVG_PATH_SEG_LAST_VALID_TYPE;
208 : }
209 :
210 0 : static bool IsCubicType(PRUint32 aType) {
211 : return aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL ||
212 : aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS ||
213 : aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL ||
214 0 : aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS;
215 : }
216 :
217 0 : static bool IsQuadraticType(PRUint32 aType) {
218 : return aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL ||
219 : aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS ||
220 : aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL ||
221 0 : aType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS;
222 : }
223 :
224 0 : static bool IsArcType(PRUint32 aType) {
225 : return aType == nsIDOMSVGPathSeg::PATHSEG_ARC_ABS ||
226 0 : aType == nsIDOMSVGPathSeg::PATHSEG_ARC_REL;
227 : }
228 :
229 0 : static bool IsRelativeOrAbsoluteType(PRUint32 aType) {
230 0 : NS_ABORT_IF_FALSE(IsValidType(aType), "Seg type not recognized");
231 :
232 : // When adding a new path segment type, ensure that the returned condition
233 : // below is still correct.
234 : PR_STATIC_ASSERT(NS_SVG_PATH_SEG_LAST_VALID_TYPE ==
235 : nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL);
236 :
237 0 : return aType >= nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS;
238 : }
239 :
240 0 : static bool IsRelativeType(PRUint32 aType) {
241 0 : NS_ABORT_IF_FALSE
242 : (IsRelativeOrAbsoluteType(aType),
243 : "IsRelativeType called with segment type that does not come in relative and absolute forms");
244 :
245 : // When adding a new path segment type, ensure that the returned condition
246 : // below is still correct.
247 : PR_STATIC_ASSERT(NS_SVG_PATH_SEG_LAST_VALID_TYPE ==
248 : nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL);
249 :
250 0 : return aType & 1;
251 : }
252 :
253 0 : static PRUint32 RelativeVersionOfType(PRUint32 aType) {
254 0 : NS_ABORT_IF_FALSE
255 : (IsRelativeOrAbsoluteType(aType),
256 : "RelativeVersionOfType called with segment type that does not come in relative and absolute forms");
257 :
258 : // When adding a new path segment type, ensure that the returned condition
259 : // below is still correct.
260 : PR_STATIC_ASSERT(NS_SVG_PATH_SEG_LAST_VALID_TYPE ==
261 : nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL);
262 :
263 0 : return aType | 1;
264 : }
265 :
266 0 : static PRUint32 SameTypeModuloRelativeness(PRUint32 aType1, PRUint32 aType2) {
267 0 : if (!IsRelativeOrAbsoluteType(aType1)) {
268 0 : return aType1 == aType2;
269 : }
270 :
271 0 : return RelativeVersionOfType(aType1) == RelativeVersionOfType(aType2);
272 : }
273 :
274 : /**
275 : * Traverse the given path segment and update the SVGPathTraversalState
276 : * object.
277 : */
278 : static void TraversePathSegment(const float* aData,
279 : SVGPathTraversalState& aState);
280 : };
281 :
282 : } // namespace mozilla
283 :
284 : #endif // MOZILLA_SVGPATHSEGUTILS_H__
|