Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/svg/SVGContentUtils.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_SVGCONTENTUTILS_H
8
#define MOZILLA_SVGCONTENTUTILS_H
9
10
// include math.h to pick up definition of M_ maths defines e.g. M_PI
11
#include <math.h>
12
13
#include "mozilla/gfx/2D.h" // for StrokeOptions
14
#include "mozilla/gfx/Matrix.h"
15
#include "mozilla/RangedPtr.h"
16
#include "nsError.h"
17
#include "nsStringFwd.h"
18
#include "gfx2DGlue.h"
19
20
class nsIContent;
21
class nsIDocument;
22
class nsIFrame;
23
class nsPresContext;
24
class nsStyleCoord;
25
class nsSVGElement;
26
27
namespace mozilla {
28
class ComputedStyle;
29
class nsSVGAnimatedTransformList;
30
class SVGAnimatedPreserveAspectRatio;
31
class SVGContextPaint;
32
class SVGPreserveAspectRatio;
33
namespace dom {
34
class Element;
35
class SVGSVGElement;
36
class SVGViewportElement;
37
} // namespace dom
38
39
} // namespace mozilla
40
41
0
#define SVG_ZERO_LENGTH_PATH_FIX_FACTOR 512
42
43
/**
44
 * SVGTransformTypes controls the transforms that PrependLocalTransformsTo
45
 * applies.
46
 *
47
 * If aWhich is eAllTransforms, then all the transforms from the coordinate
48
 * space established by this element for its children to the coordinate
49
 * space established by this element's parent element for this element, are
50
 * included.
51
 *
52
 * If aWhich is eUserSpaceToParent, then only the transforms from this
53
 * element's userspace to the coordinate space established by its parent is
54
 * included. This includes any transforms introduced by the 'transform'
55
 * attribute, transform animations and animateMotion, but not any offsets
56
 * due to e.g. 'x'/'y' attributes, or any transform due to a 'viewBox'
57
 * attribute. (SVG userspace is defined to be the coordinate space in which
58
 * coordinates on an element apply.)
59
 *
60
 * If aWhich is eChildToUserSpace, then only the transforms from the
61
 * coordinate space established by this element for its childre to this
62
 * elements userspace are included. This includes any offsets due to e.g.
63
 * 'x'/'y' attributes, and any transform due to a 'viewBox' attribute, but
64
 * does not include any transforms due to the 'transform' attribute.
65
 */
66
enum SVGTransformTypes {
67
   eAllTransforms,
68
   eUserSpaceToParent,
69
   eChildToUserSpace
70
};
71
72
/**
73
 * Functions generally used by SVG Content classes. Functions here
74
 * should not generally depend on layout methods/classes e.g. nsSVGUtils
75
 */
76
class SVGContentUtils
77
{
78
public:
79
  typedef mozilla::ComputedStyle ComputedStyle;
80
  typedef mozilla::gfx::Float Float;
81
  typedef mozilla::gfx::Matrix Matrix;
82
  typedef mozilla::gfx::Rect Rect;
83
  typedef mozilla::gfx::StrokeOptions StrokeOptions;
84
  typedef mozilla::SVGAnimatedPreserveAspectRatio SVGAnimatedPreserveAspectRatio;
85
  typedef mozilla::SVGPreserveAspectRatio SVGPreserveAspectRatio;
86
87
  /*
88
   * Get the outer SVG element of an nsIContent
89
   */
90
  static mozilla::dom::SVGSVGElement *GetOuterSVGElement(nsSVGElement *aSVGElement);
91
92
  /**
93
   * Activates the animation element aContent as a result of navigation to the
94
   * fragment identifier that identifies aContent. aContent must be an instance
95
   * of nsSVGAnimationElement.
96
   *
97
   * This is just a shim to allow nsSVGAnimationElement::ActivateByHyperlink to
98
   * be called from layout/base without adding to that directory's include paths.
99
   */
100
  static void ActivateByHyperlink(nsIContent *aContent);
101
102
  /**
103
   * Moz2D's StrokeOptions requires someone else to own its mDashPattern
104
   * buffer, which is a pain when you want to initialize a StrokeOptions object
105
   * in a helper function and pass it out. This sub-class owns the mDashPattern
106
   * buffer so that consumers of such a helper function don't need to worry
107
   * about creating it, passing it in, or deleting it. (An added benefit is
108
   * that in the typical case when stroke-dasharray is short it will avoid
109
   * allocating.)
110
   */
111
  struct AutoStrokeOptions : public StrokeOptions {
112
    AutoStrokeOptions()
113
0
    {
114
0
      MOZ_ASSERT(mDashLength == 0, "InitDashPattern() depends on this");
115
0
    }
116
0
    ~AutoStrokeOptions() {
117
0
      if (mDashPattern && mDashPattern != mSmallArray) {
118
0
        delete [] mDashPattern;
119
0
      }
120
0
    }
121
    /**
122
     * Creates the buffer to store the stroke-dasharray, assuming out-of-memory
123
     * does not occur. The buffer's address is assigned to mDashPattern and
124
     * returned to the caller as a non-const pointer (so that the caller can
125
     * initialize the values in the buffer, since mDashPattern is const).
126
     */
127
0
    Float* InitDashPattern(size_t aDashCount) {
128
0
      if (aDashCount <= MOZ_ARRAY_LENGTH(mSmallArray)) {
129
0
        mDashPattern = mSmallArray;
130
0
        return mSmallArray;
131
0
      }
132
0
      Float* nonConstArray = new (mozilla::fallible) Float[aDashCount];
133
0
      mDashPattern = nonConstArray;
134
0
      return nonConstArray;
135
0
    }
136
0
    void DiscardDashPattern() {
137
0
      if (mDashPattern && mDashPattern != mSmallArray) {
138
0
        delete [] mDashPattern;
139
0
      }
140
0
      mDashLength = 0;
141
0
      mDashPattern = nullptr;
142
0
    }
143
  private:
144
    // Most dasharrays will fit in this and save us allocating
145
    Float mSmallArray[16];
146
  };
147
148
  enum StrokeOptionFlags {
149
    eAllStrokeOptions,
150
    eIgnoreStrokeDashing
151
  };
152
  /**
153
   * Note: the linecap style returned in aStrokeOptions is not valid when
154
   * ShapeTypeHasNoCorners(aElement) == true && aFlags == eIgnoreStrokeDashing,
155
   * since when aElement has no corners the rendered linecap style depends on
156
   * whether or not the stroke is dashed.
157
   */
158
  static void GetStrokeOptions(AutoStrokeOptions* aStrokeOptions,
159
                               nsSVGElement* aElement,
160
                               ComputedStyle* aComputedStyle,
161
                               mozilla::SVGContextPaint* aContextPaint,
162
                               StrokeOptionFlags aFlags = eAllStrokeOptions);
163
164
  /**
165
   * Returns the current computed value of the CSS property 'stroke-width' for
166
   * the given element. aComputedStyle may be provided as an optimization.
167
   * aContextPaint is also optional.
168
   *
169
   * Note that this function does NOT take account of the value of the 'stroke'
170
   * and 'stroke-opacity' properties to, say, return zero if they are "none" or
171
   * "0", respectively.
172
   */
173
  static Float GetStrokeWidth(nsSVGElement* aElement,
174
                              ComputedStyle* aComputedStyle,
175
                              mozilla::SVGContextPaint* aContextPaint);
176
177
  /*
178
   * Get the number of CSS px (user units) per em (i.e. the em-height in user
179
   * units) for an nsIContent
180
   *
181
   * XXX document the conditions under which these may fail, and what they
182
   * return in those cases.
183
   */
184
  static float GetFontSize(mozilla::dom::Element* aElement);
185
  static float GetFontSize(nsIFrame* aFrame);
186
  static float GetFontSize(ComputedStyle*, nsPresContext*);
187
  /*
188
   * Get the number of CSS px (user units) per ex (i.e. the x-height in user
189
   * units) for an nsIContent
190
   *
191
   * XXX document the conditions under which these may fail, and what they
192
   * return in those cases.
193
   */
194
  static float GetFontXHeight(mozilla::dom::Element* aElement);
195
  static float GetFontXHeight(nsIFrame* aFrame);
196
  static float GetFontXHeight(ComputedStyle*, nsPresContext*);
197
198
  /*
199
   * Report a localized error message to the error console.
200
   */
201
  static nsresult ReportToConsole(nsIDocument* doc,
202
                                  const char* aWarning,
203
                                  const char16_t **aParams,
204
                                  uint32_t aParamsLength);
205
206
  static Matrix GetCTM(nsSVGElement *aElement, bool aScreenCTM);
207
208
  /**
209
   * Gets the tight bounds-space stroke bounds of the non-scaling-stroked rect
210
   * aRect.
211
   * @param aToBoundsSpace transforms from source space to the space aBounds
212
   *        should be computed in.  Must be rectilinear.
213
   * @param aToNonScalingStrokeSpace transforms from source
214
   *        space to the space in which non-scaling stroke should be applied.
215
   *        Must be rectilinear.
216
   */
217
  static void
218
  RectilinearGetStrokeBounds(const Rect& aRect,
219
                             const Matrix& aToBoundsSpace,
220
                             const Matrix& aToNonScalingStrokeSpace,
221
                             float aStrokeWidth,
222
                             Rect* aBounds);
223
224
  /**
225
   * Check if this is one of the SVG elements that SVG 1.1 Full says
226
   * establishes a viewport: svg, symbol, image or foreignObject.
227
   */
228
  static bool EstablishesViewport(nsIContent *aContent);
229
230
  static mozilla::dom::SVGViewportElement*
231
  GetNearestViewportElement(const nsIContent *aContent);
232
233
  /* enum for specifying coordinate direction for ObjectSpace/UserSpace */
234
  enum ctxDirection { X, Y, XY };
235
236
  /**
237
   * Computes sqrt((aWidth^2 + aHeight^2)/2);
238
   */
239
  static double ComputeNormalizedHypotenuse(double aWidth, double aHeight);
240
241
  /* Returns the angle halfway between the two specified angles */
242
  static float
243
  AngleBisect(float a1, float a2);
244
245
  /* Generate a viewbox to viewport transformation matrix */
246
247
  static Matrix
248
  GetViewBoxTransform(float aViewportWidth, float aViewportHeight,
249
                      float aViewboxX, float aViewboxY,
250
                      float aViewboxWidth, float aViewboxHeight,
251
                      const SVGAnimatedPreserveAspectRatio &aPreserveAspectRatio);
252
253
  static Matrix
254
  GetViewBoxTransform(float aViewportWidth, float aViewportHeight,
255
                      float aViewboxX, float aViewboxY,
256
                      float aViewboxWidth, float aViewboxHeight,
257
                      const SVGPreserveAspectRatio &aPreserveAspectRatio);
258
259
  static mozilla::RangedPtr<const char16_t>
260
  GetStartRangedPtr(const nsAString& aString);
261
262
  static mozilla::RangedPtr<const char16_t>
263
  GetEndRangedPtr(const nsAString& aString);
264
265
  /**
266
   * Parses the sign (+ or -) of a number and moves aIter to the next
267
   * character if a sign is found.
268
   * @param aSignMultiplier [outparam] -1 if the sign is negative otherwise 1
269
   * @return false if we hit the end of the string (i.e. if aIter is initially
270
   *         at aEnd, or if we reach aEnd right after the sign character).
271
   */
272
  static inline bool
273
  ParseOptionalSign(mozilla::RangedPtr<const char16_t>& aIter,
274
                    const mozilla::RangedPtr<const char16_t>& aEnd,
275
                    int32_t& aSignMultiplier)
276
0
  {
277
0
    if (aIter == aEnd) {
278
0
      return false;
279
0
    }
280
0
    aSignMultiplier = *aIter == '-' ? -1 : 1;
281
0
282
0
    mozilla::RangedPtr<const char16_t> iter(aIter);
283
0
284
0
    if (*iter == '-' || *iter == '+') {
285
0
      ++iter;
286
0
      if (iter == aEnd) {
287
0
        return false;
288
0
      }
289
0
    }
290
0
    aIter = iter;
291
0
    return true;
292
0
  }
293
294
  /**
295
   * Parse a number of the form:
296
   * number ::= integer ([Ee] integer)? | [+-]? [0-9]* "." [0-9]+ ([Ee] integer)?
297
   * Parsing fails if the number cannot be represented by a floatType.
298
   * If parsing succeeds, aIter is updated so that it points to the character
299
   * after the end of the number, otherwise it is left unchanged
300
   */
301
  template<class floatType>
302
  static bool
303
  ParseNumber(mozilla::RangedPtr<const char16_t>& aIter,
304
              const mozilla::RangedPtr<const char16_t>& aEnd,
305
              floatType& aValue);
306
307
  /**
308
   * Parse a number of the form:
309
   * number ::= integer ([Ee] integer)? | [+-]? [0-9]* "." [0-9]+ ([Ee] integer)?
310
   * Parsing fails if there is anything left over after the number,
311
   * or the number cannot be represented by a floatType.
312
   */
313
  template<class floatType>
314
  static bool
315
  ParseNumber(const nsAString& aString, floatType& aValue);
316
317
  /**
318
   * Parse an integer of the form:
319
   * integer ::= [+-]? [0-9]+
320
   * The returned number is clamped to an int32_t if outside that range.
321
   * If parsing succeeds, aIter is updated so that it points to the character
322
   * after the end of the number, otherwise it is left unchanged
323
   */
324
  static bool ParseInteger(mozilla::RangedPtr<const char16_t>& aIter,
325
                           const mozilla::RangedPtr<const char16_t>& aEnd,
326
                           int32_t& aValue);
327
328
  /**
329
   * Parse an integer of the form:
330
   * integer ::= [+-]? [0-9]+
331
   * The returned number is clamped to an int32_t if outside that range.
332
   * Parsing fails if there is anything left over after the number.
333
   */
334
  static bool ParseInteger(const nsAString& aString, int32_t& aValue);
335
336
  /**
337
   * Converts an nsStyleCoord into a userspace value.  Handles units
338
   * Factor (straight userspace), Coord (dimensioned), and Percent (of
339
   * aContent's SVG viewport)
340
   */
341
  static float CoordToFloat(nsSVGElement *aContent,
342
                            const nsStyleCoord &aCoord);
343
  /**
344
   * Parse the SVG path string
345
   * Returns a path
346
   * string formatted as an SVG path
347
   */
348
  static already_AddRefed<mozilla::gfx::Path>
349
  GetPath(const nsAString& aPathString);
350
351
  /**
352
   *  Returns true if aContent is one of the elements whose stroke is guaranteed
353
   *  to have no corners: circle or ellipse
354
   */
355
  static bool ShapeTypeHasNoCorners(const nsIContent* aContent);
356
};
357
358
#endif