2015-05-03 22:32:37 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2012-09-22 23:26:05 +04:00
|
|
|
/* 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>
|
|
|
|
|
2014-07-06 00:53:04 +04:00
|
|
|
#include "mozilla/gfx/2D.h" // for StrokeOptions
|
2014-03-18 06:41:34 +04:00
|
|
|
#include "mozilla/gfx/Matrix.h"
|
2013-10-29 21:15:39 +04:00
|
|
|
#include "mozilla/RangedPtr.h"
|
2014-03-18 06:41:34 +04:00
|
|
|
#include "nsError.h"
|
|
|
|
#include "nsStringFwd.h"
|
2014-03-24 17:31:19 +04:00
|
|
|
#include "gfx2DGlue.h"
|
2012-09-22 23:26:05 +04:00
|
|
|
|
|
|
|
class nsIContent;
|
|
|
|
class nsIDocument;
|
|
|
|
class nsIFrame;
|
2018-04-06 15:52:12 +03:00
|
|
|
class nsPresContext;
|
2013-11-02 15:10:38 +04:00
|
|
|
class nsStyleCoord;
|
2012-09-22 23:26:05 +04:00
|
|
|
|
|
|
|
namespace mozilla {
|
2018-03-22 21:20:41 +03:00
|
|
|
class ComputedStyle;
|
2015-12-03 01:36:23 +03:00
|
|
|
class nsSVGAnimatedTransformList;
|
2012-09-22 23:26:05 +04:00
|
|
|
class SVGAnimatedPreserveAspectRatio;
|
2016-07-22 16:56:09 +03:00
|
|
|
class SVGContextPaint;
|
2012-09-22 23:26:05 +04:00
|
|
|
class SVGPreserveAspectRatio;
|
|
|
|
namespace dom {
|
|
|
|
class Element;
|
2018-12-21 11:58:14 +03:00
|
|
|
class SVGElement;
|
2013-01-10 03:02:45 +04:00
|
|
|
class SVGSVGElement;
|
2017-10-10 09:58:34 +03:00
|
|
|
class SVGViewportElement;
|
2012-09-22 23:26:05 +04:00
|
|
|
} // namespace dom
|
2013-12-30 10:50:17 +04:00
|
|
|
|
2015-08-01 11:09:00 +03:00
|
|
|
#define SVG_ZERO_LENGTH_PATH_FIX_FACTOR 512
|
|
|
|
|
2015-12-03 01:36:23 +03:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
};
|
|
|
|
|
2012-09-22 23:26:05 +04:00
|
|
|
/**
|
|
|
|
* Functions generally used by SVG Content classes. Functions here
|
|
|
|
* should not generally depend on layout methods/classes e.g. nsSVGUtils
|
|
|
|
*/
|
|
|
|
class SVGContentUtils {
|
|
|
|
public:
|
2014-07-06 00:53:04 +04:00
|
|
|
typedef mozilla::gfx::Float Float;
|
2015-09-01 07:17:00 +03:00
|
|
|
typedef mozilla::gfx::Matrix Matrix;
|
|
|
|
typedef mozilla::gfx::Rect Rect;
|
2014-07-06 00:53:04 +04:00
|
|
|
typedef mozilla::gfx::StrokeOptions StrokeOptions;
|
2012-09-22 23:26:05 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the outer SVG element of an nsIContent
|
|
|
|
*/
|
2018-12-21 11:58:14 +03:00
|
|
|
static dom::SVGSVGElement* GetOuterSVGElement(dom::SVGElement* aSVGElement);
|
2012-09-22 23:26:05 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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);
|
|
|
|
|
2014-07-06 00:53:04 +04:00
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
}
|
2015-01-28 12:00:40 +03:00
|
|
|
Float* nonConstArray = new (mozilla::fallible) Float[aDashCount];
|
2014-07-06 00:53:04 +04:00
|
|
|
mDashPattern = nonConstArray;
|
|
|
|
return nonConstArray;
|
|
|
|
}
|
2014-09-30 21:08:13 +04:00
|
|
|
void DiscardDashPattern() {
|
|
|
|
if (mDashPattern && mDashPattern != mSmallArray) {
|
|
|
|
delete[] mDashPattern;
|
|
|
|
}
|
|
|
|
mDashLength = 0;
|
|
|
|
mDashPattern = nullptr;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-07-06 00:53:04 +04:00
|
|
|
private:
|
|
|
|
// Most dasharrays will fit in this and save us allocating
|
|
|
|
Float mSmallArray[16];
|
|
|
|
};
|
|
|
|
|
2014-10-03 12:50:43 +04:00
|
|
|
enum StrokeOptionFlags { eAllStrokeOptions, eIgnoreStrokeDashing };
|
2016-01-26 21:30:36 +03:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2014-07-06 00:53:04 +04:00
|
|
|
static void GetStrokeOptions(AutoStrokeOptions* aStrokeOptions,
|
2018-12-21 11:58:14 +03:00
|
|
|
dom::SVGElement* aElement,
|
2018-03-22 21:20:41 +03:00
|
|
|
ComputedStyle* aComputedStyle,
|
2016-07-22 16:56:09 +03:00
|
|
|
mozilla::SVGContextPaint* aContextPaint,
|
2014-10-03 12:50:43 +04:00
|
|
|
StrokeOptionFlags aFlags = eAllStrokeOptions);
|
2014-07-06 00:53:04 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the current computed value of the CSS property 'stroke-width' for
|
2018-03-22 21:20:41 +03:00
|
|
|
* the given element. aComputedStyle may be provided as an optimization.
|
2014-07-06 00:53:04 +04:00
|
|
|
* 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.
|
|
|
|
*/
|
2018-12-21 11:58:14 +03:00
|
|
|
static Float GetStrokeWidth(dom::SVGElement* aElement,
|
2018-03-22 21:20:41 +03:00
|
|
|
ComputedStyle* aComputedStyle,
|
2016-07-22 16:56:09 +03:00
|
|
|
mozilla::SVGContextPaint* aContextPaint);
|
2014-07-06 00:53:04 +04:00
|
|
|
|
2012-09-22 23:26:05 +04:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2018-04-06 15:52:12 +03:00
|
|
|
static float GetFontSize(mozilla::dom::Element* aElement);
|
|
|
|
static float GetFontSize(nsIFrame* aFrame);
|
|
|
|
static float GetFontSize(ComputedStyle*, nsPresContext*);
|
2012-09-22 23:26:05 +04:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2018-04-06 15:52:12 +03:00
|
|
|
static float GetFontXHeight(mozilla::dom::Element* aElement);
|
|
|
|
static float GetFontXHeight(nsIFrame* aFrame);
|
|
|
|
static float GetFontXHeight(ComputedStyle*, nsPresContext*);
|
2012-09-22 23:26:05 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Report a localized error message to the error console.
|
|
|
|
*/
|
|
|
|
static nsresult ReportToConsole(nsIDocument* doc, const char* aWarning,
|
2014-01-04 19:02:17 +04:00
|
|
|
const char16_t** aParams,
|
2012-09-22 23:26:05 +04:00
|
|
|
uint32_t aParamsLength);
|
|
|
|
|
2018-12-21 11:58:14 +03:00
|
|
|
static Matrix GetCTM(dom::SVGElement* aElement, bool aScreenCTM);
|
2015-09-01 07:17:00 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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);
|
2012-09-22 23:26:05 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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);
|
|
|
|
|
2017-10-10 09:58:34 +03:00
|
|
|
static mozilla::dom::SVGViewportElement* GetNearestViewportElement(
|
|
|
|
const nsIContent* aContent);
|
2012-09-22 23:26:05 +04:00
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
2018-03-18 21:09:51 +03:00
|
|
|
/* Generate a viewbox to viewport transformation matrix */
|
2012-09-22 23:26:05 +04:00
|
|
|
|
2015-09-01 07:17:00 +03:00
|
|
|
static Matrix GetViewBoxTransform(
|
2013-03-03 12:11:03 +04:00
|
|
|
float aViewportWidth, float aViewportHeight, float aViewboxX,
|
2012-09-22 23:26:05 +04:00
|
|
|
float aViewboxY, float aViewboxWidth, float aViewboxHeight,
|
|
|
|
const SVGAnimatedPreserveAspectRatio& aPreserveAspectRatio);
|
|
|
|
|
2015-09-01 07:17:00 +03:00
|
|
|
static Matrix GetViewBoxTransform(
|
2013-03-03 12:11:03 +04:00
|
|
|
float aViewportWidth, float aViewportHeight, float aViewboxX,
|
2012-09-22 23:26:05 +04:00
|
|
|
float aViewboxY, float aViewboxWidth, float aViewboxHeight,
|
|
|
|
const SVGPreserveAspectRatio& aPreserveAspectRatio);
|
|
|
|
|
2014-01-04 19:02:17 +04:00
|
|
|
static mozilla::RangedPtr<const char16_t> GetStartRangedPtr(
|
2013-10-29 21:15:39 +04:00
|
|
|
const nsAString& aString);
|
|
|
|
|
2014-01-04 19:02:17 +04:00
|
|
|
static mozilla::RangedPtr<const char16_t> GetEndRangedPtr(
|
2013-10-29 21:15:39 +04:00
|
|
|
const nsAString& aString);
|
|
|
|
|
2013-11-25 23:46:20 +04:00
|
|
|
/**
|
|
|
|
* 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(
|
2014-01-04 19:02:17 +04:00
|
|
|
mozilla::RangedPtr<const char16_t>& aIter,
|
|
|
|
const mozilla::RangedPtr<const char16_t>& aEnd,
|
2013-11-25 23:46:20 +04:00
|
|
|
int32_t& aSignMultiplier) {
|
|
|
|
if (aIter == aEnd) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
aSignMultiplier = *aIter == '-' ? -1 : 1;
|
|
|
|
|
2014-01-04 19:02:17 +04:00
|
|
|
mozilla::RangedPtr<const char16_t> iter(aIter);
|
2013-11-25 23:46:20 +04:00
|
|
|
|
|
|
|
if (*iter == '-' || *iter == '+') {
|
|
|
|
++iter;
|
|
|
|
if (iter == aEnd) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
aIter = iter;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-10-01 11:50:40 +04:00
|
|
|
/**
|
|
|
|
* 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.
|
2013-10-29 21:15:39 +04:00
|
|
|
* If parsing succeeds, aIter is updated so that it points to the character
|
|
|
|
* after the end of the number, otherwise it is left unchanged
|
2013-10-01 11:50:40 +04:00
|
|
|
*/
|
|
|
|
template <class floatType>
|
2014-01-04 19:02:17 +04:00
|
|
|
static bool ParseNumber(mozilla::RangedPtr<const char16_t>& aIter,
|
|
|
|
const mozilla::RangedPtr<const char16_t>& aEnd,
|
2013-10-29 21:15:39 +04:00
|
|
|
floatType& aValue);
|
2013-10-01 11:50:40 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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]+
|
2013-11-25 23:46:20 +04:00
|
|
|
* 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
|
|
|
|
*/
|
2014-01-04 19:02:17 +04:00
|
|
|
static bool ParseInteger(mozilla::RangedPtr<const char16_t>& aIter,
|
|
|
|
const mozilla::RangedPtr<const char16_t>& aEnd,
|
2013-11-25 23:46:20 +04:00
|
|
|
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.
|
2013-10-01 11:50:40 +04:00
|
|
|
*/
|
2013-11-25 23:46:20 +04:00
|
|
|
static bool ParseInteger(const nsAString& aString, int32_t& aValue);
|
2013-11-02 15:10:38 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Converts an nsStyleCoord into a userspace value. Handles units
|
|
|
|
* Factor (straight userspace), Coord (dimensioned), and Percent (of
|
|
|
|
* aContent's SVG viewport)
|
|
|
|
*/
|
2018-12-21 11:58:14 +03:00
|
|
|
static float CoordToFloat(dom::SVGElement* aContent,
|
|
|
|
const nsStyleCoord& aCoord);
|
2014-03-24 17:31:19 +04:00
|
|
|
/**
|
|
|
|
* Parse the SVG path string
|
|
|
|
* Returns a path
|
|
|
|
* string formatted as an SVG path
|
|
|
|
*/
|
2015-06-17 17:00:52 +03:00
|
|
|
static already_AddRefed<mozilla::gfx::Path> GetPath(
|
2014-03-24 17:31:19 +04:00
|
|
|
const nsAString& aPathString);
|
2015-06-29 21:19:00 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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);
|
2012-09-22 23:26:05 +04:00
|
|
|
};
|
|
|
|
|
2018-12-20 10:58:08 +03:00
|
|
|
} // namespace mozilla
|
|
|
|
|
2012-09-22 23:26:05 +04:00
|
|
|
#endif
|