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