/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 |