Coverage Report

Created: 2018-09-25 14:53

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