diff options
Diffstat (limited to 'dom/svg/SVGContentUtils.h')
-rw-r--r-- | dom/svg/SVGContentUtils.h | 400 |
1 files changed, 400 insertions, 0 deletions
diff --git a/dom/svg/SVGContentUtils.h b/dom/svg/SVGContentUtils.h new file mode 100644 index 0000000000..373adf9f05 --- /dev/null +++ b/dom/svg/SVGContentUtils.h @@ -0,0 +1,400 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_SVGCONTENTUTILS_H +#define MOZILLA_SVGCONTENTUTILS_H + +// include math.h to pick up definition of M_ maths defines e.g. M_PI +#include <math.h> + +#include "mozilla/gfx/2D.h" // for StrokeOptions +#include "mozilla/gfx/Matrix.h" +#include "mozilla/RangedPtr.h" +#include "nsError.h" +#include "nsStringFwd.h" +#include "gfx2DGlue.h" + +class nsIContent; +class nsIDocument; +class nsIFrame; +class nsStyleContext; +class nsStyleCoord; +class nsSVGElement; + +namespace mozilla { +class nsSVGAnimatedTransformList; +class SVGAnimatedPreserveAspectRatio; +class SVGContextPaint; +class SVGPreserveAspectRatio; +namespace dom { +class Element; +class SVGSVGElement; +} // namespace dom + +namespace gfx { +class Matrix; +} // namespace gfx +} // namespace mozilla + +#define SVG_ZERO_LENGTH_PATH_FIX_FACTOR 512 + +/** + * SVGTransformTypes controls the transforms that PrependLocalTransformsTo + * applies. + * + * If aWhich is eAllTransforms, then all the transforms from the coordinate + * space established by this element for its children to the coordinate + * space established by this element's parent element for this element, are + * included. + * + * If aWhich is eUserSpaceToParent, then only the transforms from this + * element's userspace to the coordinate space established by its parent is + * included. This includes any transforms introduced by the 'transform' + * attribute, transform animations and animateMotion, but not any offsets + * due to e.g. 'x'/'y' attributes, or any transform due to a 'viewBox' + * attribute. (SVG userspace is defined to be the coordinate space in which + * coordinates on an element apply.) + * + * If aWhich is eChildToUserSpace, then only the transforms from the + * coordinate space established by this element for its childre to this + * elements userspace are included. This includes any offsets due to e.g. + * 'x'/'y' attributes, and any transform due to a 'viewBox' attribute, but + * does not include any transforms due to the 'transform' attribute. + */ +enum SVGTransformTypes { + eAllTransforms, + eUserSpaceToParent, + eChildToUserSpace +}; + +inline bool +IsSVGWhitespace(char aChar) +{ + return aChar == '\x20' || aChar == '\x9' || + aChar == '\xD' || aChar == '\xA'; +} + +inline bool +IsSVGWhitespace(char16_t aChar) +{ + return aChar == char16_t('\x20') || aChar == char16_t('\x9') || + aChar == char16_t('\xD') || aChar == char16_t('\xA'); +} + +/** + * Functions generally used by SVG Content classes. Functions here + * should not generally depend on layout methods/classes e.g. nsSVGUtils + */ +class SVGContentUtils +{ +public: + typedef mozilla::gfx::Float Float; + typedef mozilla::gfx::Matrix Matrix; + typedef mozilla::gfx::Rect Rect; + typedef mozilla::gfx::StrokeOptions StrokeOptions; + typedef mozilla::SVGAnimatedPreserveAspectRatio SVGAnimatedPreserveAspectRatio; + typedef mozilla::SVGPreserveAspectRatio SVGPreserveAspectRatio; + + /* + * Get the outer SVG element of an nsIContent + */ + static mozilla::dom::SVGSVGElement *GetOuterSVGElement(nsSVGElement *aSVGElement); + + /** + * Activates the animation element aContent as a result of navigation to the + * fragment identifier that identifies aContent. aContent must be an instance + * of nsSVGAnimationElement. + * + * This is just a shim to allow nsSVGAnimationElement::ActivateByHyperlink to + * be called from layout/base without adding to that directory's include paths. + */ + static void ActivateByHyperlink(nsIContent *aContent); + + /** + * Moz2D's StrokeOptions requires someone else to own its mDashPattern + * buffer, which is a pain when you want to initialize a StrokeOptions object + * in a helper function and pass it out. This sub-class owns the mDashPattern + * buffer so that consumers of such a helper function don't need to worry + * about creating it, passing it in, or deleting it. (An added benefit is + * that in the typical case when stroke-dasharray is short it will avoid + * allocating.) + */ + struct AutoStrokeOptions : public StrokeOptions { + AutoStrokeOptions() + { + MOZ_ASSERT(mDashLength == 0, "InitDashPattern() depends on this"); + } + ~AutoStrokeOptions() { + if (mDashPattern && mDashPattern != mSmallArray) { + delete [] mDashPattern; + } + } + /** + * Creates the buffer to store the stroke-dasharray, assuming out-of-memory + * does not occur. The buffer's address is assigned to mDashPattern and + * returned to the caller as a non-const pointer (so that the caller can + * initialize the values in the buffer, since mDashPattern is const). + */ + Float* InitDashPattern(size_t aDashCount) { + if (aDashCount <= MOZ_ARRAY_LENGTH(mSmallArray)) { + mDashPattern = mSmallArray; + return mSmallArray; + } + Float* nonConstArray = new (mozilla::fallible) Float[aDashCount]; + mDashPattern = nonConstArray; + return nonConstArray; + } + void DiscardDashPattern() { + if (mDashPattern && mDashPattern != mSmallArray) { + delete [] mDashPattern; + } + mDashLength = 0; + mDashPattern = nullptr; + } + private: + // Most dasharrays will fit in this and save us allocating + Float mSmallArray[16]; + }; + + enum StrokeOptionFlags { + eAllStrokeOptions, + eIgnoreStrokeDashing + }; + /** + * Note: the linecap style returned in aStrokeOptions is not valid when + * ShapeTypeHasNoCorners(aElement) == true && aFlags == eIgnoreStrokeDashing, + * since when aElement has no corners the rendered linecap style depends on + * whether or not the stroke is dashed. + */ + static void GetStrokeOptions(AutoStrokeOptions* aStrokeOptions, + nsSVGElement* aElement, + nsStyleContext* aStyleContext, + mozilla::SVGContextPaint* aContextPaint, + StrokeOptionFlags aFlags = eAllStrokeOptions); + + /** + * Returns the current computed value of the CSS property 'stroke-width' for + * the given element. aStyleContext may be provided as an optimization. + * aContextPaint is also optional. + * + * Note that this function does NOT take account of the value of the 'stroke' + * and 'stroke-opacity' properties to, say, return zero if they are "none" or + * "0", respectively. + */ + static Float GetStrokeWidth(nsSVGElement* aElement, + nsStyleContext* aStyleContext, + mozilla::SVGContextPaint* aContextPaint); + + /* + * Get the number of CSS px (user units) per em (i.e. the em-height in user + * units) for an nsIContent + * + * XXX document the conditions under which these may fail, and what they + * return in those cases. + */ + static float GetFontSize(mozilla::dom::Element *aElement); + static float GetFontSize(nsIFrame *aFrame); + static float GetFontSize(nsStyleContext *aStyleContext); + /* + * Get the number of CSS px (user units) per ex (i.e. the x-height in user + * units) for an nsIContent + * + * XXX document the conditions under which these may fail, and what they + * return in those cases. + */ + static float GetFontXHeight(mozilla::dom::Element *aElement); + static float GetFontXHeight(nsIFrame *aFrame); + static float GetFontXHeight(nsStyleContext *aStyleContext); + + /* + * Report a localized error message to the error console. + */ + static nsresult ReportToConsole(nsIDocument* doc, + const char* aWarning, + const char16_t **aParams, + uint32_t aParamsLength); + + static Matrix GetCTM(nsSVGElement *aElement, bool aScreenCTM); + + /** + * Gets the tight bounds-space stroke bounds of the non-scaling-stroked rect + * aRect. + * @param aToBoundsSpace transforms from source space to the space aBounds + * should be computed in. Must be rectilinear. + * @param aToNonScalingStrokeSpace transforms from source + * space to the space in which non-scaling stroke should be applied. + * Must be rectilinear. + */ + static void + RectilinearGetStrokeBounds(const Rect& aRect, + const Matrix& aToBoundsSpace, + const Matrix& aToNonScalingStrokeSpace, + float aStrokeWidth, + Rect* aBounds); + + /** + * Check if this is one of the SVG elements that SVG 1.1 Full says + * establishes a viewport: svg, symbol, image or foreignObject. + */ + static bool EstablishesViewport(nsIContent *aContent); + + static nsSVGElement* + GetNearestViewportElement(nsIContent *aContent); + + /* enum for specifying coordinate direction for ObjectSpace/UserSpace */ + enum ctxDirection { X, Y, XY }; + + /** + * Computes sqrt((aWidth^2 + aHeight^2)/2); + */ + static double ComputeNormalizedHypotenuse(double aWidth, double aHeight); + + /* Returns the angle halfway between the two specified angles */ + static float + AngleBisect(float a1, float a2); + + /* Generate a viewbox to viewport tranformation matrix */ + + static Matrix + GetViewBoxTransform(float aViewportWidth, float aViewportHeight, + float aViewboxX, float aViewboxY, + float aViewboxWidth, float aViewboxHeight, + const SVGAnimatedPreserveAspectRatio &aPreserveAspectRatio); + + static Matrix + GetViewBoxTransform(float aViewportWidth, float aViewportHeight, + float aViewboxX, float aViewboxY, + float aViewboxWidth, float aViewboxHeight, + const SVGPreserveAspectRatio &aPreserveAspectRatio); + + static mozilla::RangedPtr<const char16_t> + GetStartRangedPtr(const nsAString& aString); + + static mozilla::RangedPtr<const char16_t> + GetEndRangedPtr(const nsAString& aString); + + /** + * True if 'aCh' is a decimal digit. + */ + static inline bool IsDigit(char16_t aCh) + { + return aCh >= '0' && aCh <= '9'; + } + + /** + * Assuming that 'aCh' is a decimal digit, return its numeric value. + */ + static inline uint32_t DecimalDigitValue(char16_t aCh) + { + MOZ_ASSERT(IsDigit(aCh), "Digit expected"); + return aCh - '0'; + } + + /** + * Parses the sign (+ or -) of a number and moves aIter to the next + * character if a sign is found. + * @param aSignMultiplier [outparam] -1 if the sign is negative otherwise 1 + * @return false if we hit the end of the string (i.e. if aIter is initially + * at aEnd, or if we reach aEnd right after the sign character). + */ + static inline bool + ParseOptionalSign(mozilla::RangedPtr<const char16_t>& aIter, + const mozilla::RangedPtr<const char16_t>& aEnd, + int32_t& aSignMultiplier) + { + if (aIter == aEnd) { + return false; + } + aSignMultiplier = *aIter == '-' ? -1 : 1; + + mozilla::RangedPtr<const char16_t> iter(aIter); + + if (*iter == '-' || *iter == '+') { + ++iter; + if (iter == aEnd) { + return false; + } + } + aIter = iter; + return true; + } + + /** + * Parse a number of the form: + * number ::= integer ([Ee] integer)? | [+-]? [0-9]* "." [0-9]+ ([Ee] integer)? + * Parsing fails if the number cannot be represented by a floatType. + * If parsing succeeds, aIter is updated so that it points to the character + * after the end of the number, otherwise it is left unchanged + */ + template<class floatType> + static bool + ParseNumber(mozilla::RangedPtr<const char16_t>& aIter, + const mozilla::RangedPtr<const char16_t>& aEnd, + floatType& aValue); + + /** + * Parse a number of the form: + * number ::= integer ([Ee] integer)? | [+-]? [0-9]* "." [0-9]+ ([Ee] integer)? + * Parsing fails if there is anything left over after the number, + * or the number cannot be represented by a floatType. + */ + template<class floatType> + static bool + ParseNumber(const nsAString& aString, floatType& aValue); + + /** + * Parse an integer of the form: + * integer ::= [+-]? [0-9]+ + * The returned number is clamped to an int32_t if outside that range. + * If parsing succeeds, aIter is updated so that it points to the character + * after the end of the number, otherwise it is left unchanged + */ + static bool ParseInteger(mozilla::RangedPtr<const char16_t>& aIter, + const mozilla::RangedPtr<const char16_t>& aEnd, + int32_t& aValue); + + /** + * Parse an integer of the form: + * integer ::= [+-]? [0-9]+ + * The returned number is clamped to an int32_t if outside that range. + * Parsing fails if there is anything left over after the number. + */ + static bool ParseInteger(const nsAString& aString, int32_t& aValue); + + /** + * Converts an nsStyleCoord into a userspace value. Handles units + * Factor (straight userspace), Coord (dimensioned), and Percent (of + * aContent's SVG viewport) + */ + static float CoordToFloat(nsSVGElement *aContent, + const nsStyleCoord &aCoord); + /** + * Parse the SVG path string + * Returns a path + * string formatted as an SVG path + */ + static already_AddRefed<mozilla::gfx::Path> + GetPath(const nsAString& aPathString); + + /** + * Returns true if aContent is one of the elements whose stroke is guaranteed + * to have no corners: circle or ellipse + */ + static bool ShapeTypeHasNoCorners(const nsIContent* aContent); + + /** + * Prepends an element's local transforms to the transform matrix. + * This is a helper for nsSVGElement::PrependLocalTransformsTo. + * Any callers probably really want to call that method instead of this one. + */ + static gfxMatrix PrependLocalTransformsTo( + const gfxMatrix &aMatrix, + SVGTransformTypes aWhich, + const Matrix* aAnimateMotionTransform, + const mozilla::nsSVGAnimatedTransformList* aTransforms); +}; + +#endif |