Bug 1890793: Assert CallArgs::newTarget is not gray. r=spidermonkey-reviewers,sfink...
[gecko.git] / dom / svg / SVGContentUtils.h
blob8cd017b7092683116d2b19b8d32702d5e079ab5e
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/. */
7 #ifndef DOM_SVG_SVGCONTENTUTILS_H_
8 #define DOM_SVG_SVGCONTENTUTILS_H_
10 // include math.h to pick up definition of M_ maths defines e.g. M_PI
11 #include <math.h>
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 "nsTArray.h"
19 #include "gfx2DGlue.h"
20 #include "nsDependentSubstring.h"
22 class nsIContent;
24 class nsIFrame;
25 class nsPresContext;
27 namespace mozilla {
28 class ComputedStyle;
29 class SVGAnimatedTransformList;
30 class SVGAnimatedPreserveAspectRatio;
31 class SVGContextPaint;
32 class SVGPreserveAspectRatio;
33 union StyleLengthPercentageUnion;
34 namespace dom {
35 class Document;
36 class Element;
37 class SVGElement;
38 class SVGSVGElement;
39 class SVGViewportElement;
40 } // namespace dom
42 #define SVG_ZERO_LENGTH_PATH_FIX_FACTOR 512
44 /**
45 * SVGTransformTypes controls the transforms that PrependLocalTransformsTo
46 * applies.
48 * If aWhich is eAllTransforms, then all the transforms from the coordinate
49 * space established by this element for its children to the coordinate
50 * space established by this element's parent element for this element, are
51 * included.
53 * If aWhich is eUserSpaceToParent, then only the transforms from this
54 * element's userspace to the coordinate space established by its parent is
55 * included. This includes any transforms introduced by the 'transform'
56 * attribute, transform animations and animateMotion, but not any offsets
57 * due to e.g. 'x'/'y' attributes, or any transform due to a 'viewBox'
58 * attribute. (SVG userspace is defined to be the coordinate space in which
59 * coordinates on an element apply.)
61 * If aWhich is eChildToUserSpace, then only the transforms from the
62 * coordinate space established by this element for its childre to this
63 * elements userspace are included. This includes any offsets due to e.g.
64 * 'x'/'y' attributes, and any transform due to a 'viewBox' attribute, but
65 * does not include any transforms due to the 'transform' attribute.
67 enum SVGTransformTypes {
68 eAllTransforms,
69 eUserSpaceToParent,
70 eChildToUserSpace
73 /**
74 * Functions generally used by SVG Content classes. Functions here
75 * should not generally depend on layout methods/classes e.g. SVGUtils
77 class SVGContentUtils {
78 public:
79 using Float = gfx::Float;
80 using Matrix = gfx::Matrix;
81 using Rect = gfx::Rect;
82 using StrokeOptions = gfx::StrokeOptions;
85 * Get the outer SVG element of an nsIContent
87 static dom::SVGSVGElement* GetOuterSVGElement(dom::SVGElement* aSVGElement);
89 /**
90 * Moz2D's StrokeOptions requires someone else to own its mDashPattern
91 * buffer, which is a pain when you want to initialize a StrokeOptions object
92 * in a helper function and pass it out. This sub-class owns the mDashPattern
93 * buffer so that consumers of such a helper function don't need to worry
94 * about creating it, passing it in, or deleting it. (An added benefit is
95 * that in the typical case when stroke-dasharray is short it will avoid
96 * allocating.)
98 struct AutoStrokeOptions : public StrokeOptions {
99 AutoStrokeOptions() {
100 MOZ_ASSERT(mDashLength == 0, "InitDashPattern() depends on this");
102 ~AutoStrokeOptions() {
103 if (mDashPattern && mDashPattern != mSmallArray) {
104 delete[] mDashPattern;
108 * Creates the buffer to store the stroke-dasharray, assuming out-of-memory
109 * does not occur. The buffer's address is assigned to mDashPattern and
110 * returned to the caller as a non-const pointer (so that the caller can
111 * initialize the values in the buffer, since mDashPattern is const).
113 Float* InitDashPattern(size_t aDashCount) {
114 if (aDashCount <= MOZ_ARRAY_LENGTH(mSmallArray)) {
115 mDashPattern = mSmallArray;
116 return mSmallArray;
118 Float* nonConstArray = new (mozilla::fallible) Float[aDashCount];
119 mDashPattern = nonConstArray;
120 return nonConstArray;
122 void DiscardDashPattern() {
123 if (mDashPattern && mDashPattern != mSmallArray) {
124 delete[] mDashPattern;
126 mDashLength = 0;
127 mDashPattern = nullptr;
130 private:
131 // Most dasharrays will fit in this and save us allocating
132 Float mSmallArray[16];
135 enum StrokeOptionFlags { eAllStrokeOptions, eIgnoreStrokeDashing };
137 * Note: the linecap style returned in aStrokeOptions is not valid when
138 * ShapeTypeHasNoCorners(aElement) == true && aFlags == eIgnoreStrokeDashing,
139 * since when aElement has no corners the rendered linecap style depends on
140 * whether or not the stroke is dashed.
142 static void GetStrokeOptions(AutoStrokeOptions* aStrokeOptions,
143 dom::SVGElement* aElement,
144 const ComputedStyle* aComputedStyle,
145 const SVGContextPaint* aContextPaint,
146 StrokeOptionFlags aFlags = eAllStrokeOptions);
149 * Returns the current computed value of the CSS property 'stroke-width' for
150 * the given element. aComputedStyle may be provided as an optimization.
151 * aContextPaint is also optional.
153 * Note that this function does NOT take account of the value of the 'stroke'
154 * and 'stroke-opacity' properties to, say, return zero if they are "none" or
155 * "0", respectively.
157 static Float GetStrokeWidth(const dom::SVGElement* aElement,
158 const ComputedStyle* aComputedStyle,
159 const SVGContextPaint* aContextPaint);
162 * Get the number of CSS px (user units) per em (i.e. the em-height in user
163 * units) for an nsIContent
165 * XXX document the conditions under which these may fail, and what they
166 * return in those cases.
168 static float GetFontSize(const mozilla::dom::Element* aElement);
169 static float GetFontSize(const nsIFrame* aFrame);
170 static float GetFontSize(const ComputedStyle*, nsPresContext*);
172 * Get the number of CSS px (user units) per ex (i.e. the x-height in user
173 * units) for an nsIContent
175 * XXX document the conditions under which these may fail, and what they
176 * return in those cases.
178 static float GetFontXHeight(const mozilla::dom::Element* aElement);
179 static float GetFontXHeight(const nsIFrame* aFrame);
180 static float GetFontXHeight(const ComputedStyle*, nsPresContext*);
183 * Report a localized error message to the error console.
185 static nsresult ReportToConsole(const dom::Document* doc,
186 const char* aWarning,
187 const nsTArray<nsString>& aParams);
189 static Matrix GetCTM(dom::SVGElement* aElement, bool aScreenCTM);
192 * Gets the tight bounds-space stroke bounds of the non-scaling-stroked rect
193 * aRect.
194 * @param aToBoundsSpace transforms from source space to the space aBounds
195 * should be computed in. Must be rectilinear.
196 * @param aToNonScalingStrokeSpace transforms from source
197 * space to the space in which non-scaling stroke should be applied.
198 * Must be rectilinear.
200 static void RectilinearGetStrokeBounds(const Rect& aRect,
201 const Matrix& aToBoundsSpace,
202 const Matrix& aToNonScalingStrokeSpace,
203 float aStrokeWidth, Rect* aBounds);
206 * Check if this is one of the SVG elements that SVG 1.1 Full says
207 * establishes a viewport: svg, symbol, image or foreignObject.
209 static bool EstablishesViewport(const nsIContent* aContent);
211 static mozilla::dom::SVGViewportElement* GetNearestViewportElement(
212 const nsIContent* aContent);
214 /* enum for specifying coordinate direction for ObjectSpace/UserSpace */
215 enum ctxDirection { X, Y, XY };
218 * Computes sqrt((aWidth^2 + aHeight^2)/2);
220 static double ComputeNormalizedHypotenuse(double aWidth, double aHeight);
222 /* Returns the angle halfway between the two specified angles */
223 static float AngleBisect(float a1, float a2);
225 /* Generate a viewbox to viewport transformation matrix */
227 static Matrix GetViewBoxTransform(
228 float aViewportWidth, float aViewportHeight, float aViewboxX,
229 float aViewboxY, float aViewboxWidth, float aViewboxHeight,
230 const SVGAnimatedPreserveAspectRatio& aPreserveAspectRatio);
232 static Matrix GetViewBoxTransform(
233 float aViewportWidth, float aViewportHeight, float aViewboxX,
234 float aViewboxY, float aViewboxWidth, float aViewboxHeight,
235 const SVGPreserveAspectRatio& aPreserveAspectRatio);
237 static mozilla::RangedPtr<const char16_t> GetStartRangedPtr(
238 const nsAString& aString);
240 static mozilla::RangedPtr<const char16_t> GetEndRangedPtr(
241 const nsAString& aString);
244 * Parses the sign (+ or -) of a number and moves aIter to the next
245 * character if a sign is found.
246 * @param aSignMultiplier [outparam] -1 if the sign is negative otherwise 1
247 * @return false if we hit the end of the string (i.e. if aIter is initially
248 * at aEnd, or if we reach aEnd right after the sign character).
250 static inline bool ParseOptionalSign(
251 mozilla::RangedPtr<const char16_t>& aIter,
252 const mozilla::RangedPtr<const char16_t>& aEnd,
253 int32_t& aSignMultiplier) {
254 if (aIter == aEnd) {
255 return false;
257 aSignMultiplier = *aIter == '-' ? -1 : 1;
259 mozilla::RangedPtr<const char16_t> iter(aIter);
261 if (*iter == '-' || *iter == '+') {
262 ++iter;
263 if (iter == aEnd) {
264 return false;
267 aIter = iter;
268 return true;
272 * Parse a number of the form:
273 * number ::= integer ([Ee] integer)? | [+-]? [0-9]* "." [0-9]+ ([Ee]
274 * integer)? Parsing fails if the number cannot be represented by a floatType.
275 * If parsing succeeds, aIter is updated so that it points to the character
276 * after the end of the number, otherwise it is left unchanged
278 template <class floatType>
279 static bool ParseNumber(mozilla::RangedPtr<const char16_t>& aIter,
280 const mozilla::RangedPtr<const char16_t>& aEnd,
281 floatType& aValue);
284 * Parse a number of the form:
285 * number ::= integer ([Ee] integer)? | [+-]? [0-9]* "." [0-9]+ ([Ee]
286 * integer)? Parsing fails if there is anything left over after the number, or
287 * the number cannot be represented by a floatType.
289 template <class floatType>
290 static bool ParseNumber(const nsAString& aString, floatType& aValue);
293 * Parse an integer of the form:
294 * integer ::= [+-]? [0-9]+
295 * The returned number is clamped to an int32_t if outside that range.
296 * If parsing succeeds, aIter is updated so that it points to the character
297 * after the end of the number, otherwise it is left unchanged
299 static bool ParseInteger(mozilla::RangedPtr<const char16_t>& aIter,
300 const mozilla::RangedPtr<const char16_t>& aEnd,
301 int32_t& aValue);
304 * Parse an integer of the form:
305 * integer ::= [+-]? [0-9]+
306 * The returned number is clamped to an int32_t if outside that range.
307 * Parsing fails if there is anything left over after the number.
309 static bool ParseInteger(const nsAString& aString, int32_t& aValue);
311 // XXX This should rather use LengthPercentage instead of
312 // StyleLengthPercentageUnion, but that's a type alias defined in
313 // ServoStyleConsts.h, and we don't want to avoid including that large header
314 // with all its dependencies. If a forwarding header were generated by
315 // cbindgen, we could include that.
316 // https://github.com/eqrion/cbindgen/issues/617 addresses this.
318 * Converts a LengthPercentage into a userspace value, resolving percentage
319 * values relative to aContent's SVG viewport.
321 static float CoordToFloat(const dom::SVGElement* aContent,
322 const StyleLengthPercentageUnion&,
323 uint8_t aCtxType = SVGContentUtils::XY);
325 * Parse the SVG path string
326 * Returns a path
327 * string formatted as an SVG path
329 static already_AddRefed<mozilla::gfx::Path> GetPath(
330 const nsAString& aPathString);
333 * Returns true if aContent is one of the elements whose stroke is guaranteed
334 * to have no corners: circle or ellipse
336 static bool ShapeTypeHasNoCorners(const nsIContent* aContent);
339 * Return one token in aString, aString may have leading and trailing
340 * whitespace; aSuccess will be set to false if there is no token or more than
341 * one token, otherwise it's set to true.
343 static nsDependentSubstring GetAndEnsureOneToken(const nsAString& aString,
344 bool& aSuccess);
347 } // namespace mozilla
349 #endif // DOM_SVG_SVGCONTENTUTILS_H_