Bug 932761 - Implement Moz2D path builders for all of the SVG element types. r=dholbert

This commit is contained in:
Jonathan Watt 2013-11-02 11:10:38 +00:00
parent ac08cd69cc
commit 121dda43b7
24 changed files with 409 additions and 79 deletions

View File

@ -4,12 +4,15 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/SVGCircleElement.h"
#include "mozilla/gfx/2D.h"
#include "nsGkAtoms.h"
#include "gfxContext.h"
#include "mozilla/dom/SVGCircleElementBinding.h"
NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Circle)
using namespace mozilla::gfx;
namespace mozilla {
namespace dom {
@ -90,5 +93,20 @@ SVGCircleElement::ConstructPath(gfxContext *aCtx)
aCtx->Arc(gfxPoint(x, y), r, 0, 2*M_PI);
}
TemporaryRef<Path>
SVGCircleElement::BuildPath()
{
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
float x, y, r;
GetAnimatedLengthValues(&x, &y, &r, nullptr);
if (r > 0.0f) {
pathBuilder->Arc(Point(x, y), r, 0, Float(2*M_PI));
}
return pathBuilder->Finish();
}
} // namespace dom
} // namespace mozilla

View File

@ -32,6 +32,7 @@ public:
// nsSVGPathGeometryElement methods:
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;

View File

@ -565,3 +565,25 @@ SVGContentUtils::ParseInteger(const nsAString& aString,
int64_t(std::numeric_limits<int32_t>::max())));
return true;
}
float
SVGContentUtils::CoordToFloat(nsPresContext *aPresContext,
nsSVGElement *aContent,
const nsStyleCoord &aCoord)
{
switch (aCoord.GetUnit()) {
case eStyleUnit_Factor:
// user units
return aCoord.GetFactorValue();
case eStyleUnit_Coord:
return nsPresContext::AppUnitsToFloatCSSPixels(aCoord.GetCoordValue());
case eStyleUnit_Percent: {
SVGSVGElement* ctx = aContent->GetCtx();
return ctx ? aCoord.GetPercentValue() * ctx->GetLength(SVGContentUtils::XY) : 0.0f;
}
default:
return 0.0f;
}
}

View File

@ -16,7 +16,9 @@
class nsIContent;
class nsIDocument;
class nsIFrame;
class nsPresContext;
class nsStyleContext;
class nsStyleCoord;
class nsSVGElement;
namespace mozilla {
@ -169,6 +171,15 @@ public:
*/
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(nsPresContext *aPresContext,
nsSVGElement *aContent,
const nsStyleCoord &aCoord);
};
#endif

View File

@ -5,10 +5,14 @@
#include "mozilla/dom/SVGEllipseElement.h"
#include "mozilla/dom/SVGEllipseElementBinding.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/PathHelpers.h"
#include "gfxContext.h"
NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Ellipse)
using namespace mozilla::gfx;
namespace mozilla {
namespace dom {
@ -100,5 +104,20 @@ SVGEllipseElement::ConstructPath(gfxContext *aCtx)
}
}
TemporaryRef<Path>
SVGEllipseElement::BuildPath()
{
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
float x, y, rx, ry;
GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr);
if (rx > 0.0f && ry > 0.0f) {
AppendEllipseToPath(pathBuilder, Point(x, y), Size(2.0*rx, 2.0*ry));
}
return pathBuilder->Finish();
}
} // namespace dom
} // namespace mozilla

View File

@ -32,6 +32,7 @@ public:
// nsSVGPathGeometryElement methods:
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;

View File

@ -6,6 +6,7 @@
#include "mozilla/Util.h"
#include "mozilla/dom/SVGImageElement.h"
#include "mozilla/gfx/2D.h"
#include "nsCOMPtr.h"
#include "nsIURI.h"
#include "nsNetUtil.h"
@ -16,6 +17,8 @@
NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Image)
using namespace mozilla::gfx;
namespace mozilla {
namespace dom {
@ -236,6 +239,29 @@ SVGImageElement::ConstructPath(gfxContext *aCtx)
aCtx->Rectangle(gfxRect(x, y, width, height));
}
TemporaryRef<Path>
SVGImageElement::BuildPath()
{
// We get called in order to get bounds for this element, and for
// hit-testing against it. For that we just pretend to be a rectangle.
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
float x, y, width, height;
GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
if (width <= 0 || height <= 0) {
Rect r(x, y, width, height);
pathBuilder->MoveTo(r.TopLeft());
pathBuilder->LineTo(r.TopRight());
pathBuilder->LineTo(r.BottomRight());
pathBuilder->LineTo(r.BottomLeft());
pathBuilder->Close();
}
return pathBuilder->Finish();
}
//----------------------------------------------------------------------
// nsSVGElement methods

View File

@ -55,6 +55,7 @@ public:
// nsSVGPathGeometryElement methods:
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
// nsSVGSVGElement methods:
virtual bool HasValidDimensions() const MOZ_OVERRIDE;

View File

@ -5,10 +5,13 @@
#include "mozilla/dom/SVGLineElement.h"
#include "mozilla/dom/SVGLineElementBinding.h"
#include "mozilla/gfx/2D.h"
#include "gfxContext.h"
NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Line)
using namespace mozilla::gfx;
namespace mozilla {
namespace dom {
@ -115,5 +118,19 @@ SVGLineElement::ConstructPath(gfxContext *aCtx)
aCtx->LineTo(gfxPoint(x2, y2));
}
TemporaryRef<Path>
SVGLineElement::BuildPath()
{
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
float x1, y1, x2, y2;
GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nullptr);
pathBuilder->MoveTo(Point(x1, y1));
pathBuilder->LineTo(Point(x2, y2));
return pathBuilder->Finish();
}
} // namespace dom
} // namespace mozilla

View File

@ -34,6 +34,7 @@ public:
virtual bool IsMarkable() MOZ_OVERRIDE { return true; }
virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) MOZ_OVERRIDE;
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;

View File

@ -16,6 +16,7 @@
#include "nsSVGPathDataParser.h"
#include "nsSVGPathGeometryElement.h" // for nsSVGMark
#include <stdarg.h>
#include "nsStyleConsts.h"
#include "SVGContentUtils.h"
#include "SVGPathSegUtils.h"
#include "gfxContext.h"
@ -217,18 +218,51 @@ SVGPathData::GetPathSegAtLength(float aDistance) const
*
* Cairo only does this for |stroke-linecap: round| and not for
* |stroke-linecap: square| (since that's what Adobe Acrobat has always done).
* Most likely the other backends that DrawTarget uses have the same behavior.
*
* To help us conform to the SVG spec we have this helper function to draw an
* approximation of square caps for zero length subpaths. It does this by
* inserting a subpath containing a single axis aligned straight line that is
* as small as it can be without cairo throwing it away for being too small to
* affect rendering. Cairo will then draw stroke caps for this axis aligned
* line, creating an axis aligned rectangle (approximating the square that
* would ideally be drawn).
* inserting a subpath containing a single user space axis aligned straight
* line that is as small as it can be while minimizing the risk of it being
* thrown away by the DrawTarget's backend for being too small to affect
* rendering. The idea is that we'll then get stroke caps drawn for this axis
* aligned line, creating an axis aligned rectangle that approximates the
* square that would ideally be drawn.
*
* Since we don't have any information about transforms from user space to
* device space, we choose the length of the small line that we insert by
* making it a small percentage of the stroke width of the path. This should
* hopefully allow us to make the line as long as possible (to avoid rounding
* issues in the backend resulting in the backend seeing it as having zero
* length) while still avoiding the small rectangle being noticably different
* from a square.
*
* Note that this function inserts a subpath into the current gfx path that
* will be present during both fill and stroke operations.
*/
static void
ApproximateZeroLengthSubpathSquareCaps(PathBuilder* aPB,
const Point& aPoint,
Float aStrokeWidth)
{
// Note that caps are proportional to stroke width, so if stroke width is
// zero it's actually fine for |tinyLength| below to end up being zero.
// However, it would be a waste to inserting a LineTo in that case, so better
// not to.
MOZ_ASSERT(aStrokeWidth > 0.0f,
"Make the caller check for this, or check it here");
// The fraction of the stroke width that we choose for the length of the
// line is rather arbitrary, other than being chosen to meet the requirements
// described in the comment above.
Float tinyLength = aStrokeWidth / 32;
aPB->MoveTo(aPoint);
aPB->LineTo(aPoint + Point(tinyLength, 0));
aPB->MoveTo(aPoint);
}
static void
ApproximateZeroLengthSubpathSquareCaps(const gfxPoint &aPoint, gfxContext *aCtx)
{
@ -244,32 +278,12 @@ ApproximateZeroLengthSubpathSquareCaps(const gfxPoint &aPoint, gfxContext *aCtx)
aCtx->MoveTo(aPoint);
}
static void
ApproximateZeroLengthSubpathSquareCaps(const Point& aPoint,
DrawTarget* aDT,
PathBuilder* aPB)
{
// Cairo's fixed point fractional part is 8 bits wide, so its device space
// coordinate granularity is 1/256 pixels. However, to prevent user space
// |aPoint| and |aPoint + tinyAdvance| being rounded to the same device
// coordinates, we double this for |tinyAdvance|:
Matrix currentTransform = aDT->GetTransform();
currentTransform.Invert();
Size tinyAdvance = currentTransform * Size(2.0/256.0, 0.0);
aPB->MoveTo(aPoint);
aPB->LineTo(aPoint + Point(tinyAdvance.width, tinyAdvance.height));
aPB->MoveTo(aPoint);
}
#define MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS_TO_DT \
do { \
if (capsAreSquare && !subpathHasLength && subpathContainsNonArc && \
SVGPathSegUtils::IsValidType(prevSegType) && \
(!IsMoveto(prevSegType) || \
segType == PATHSEG_CLOSEPATH)) { \
ApproximateZeroLengthSubpathSquareCaps(segStart, aDT, builder); \
if (capsAreSquare && !subpathHasLength && aStrokeWidth > 0 && \
subpathContainsNonArc && SVGPathSegUtils::IsValidType(prevSegType) && \
(!IsMoveto(prevSegType) || segType == PATHSEG_CLOSEPATH)) { \
ApproximateZeroLengthSubpathSquareCaps(builder, segStart, aStrokeWidth);\
} \
} while(0)
@ -284,17 +298,23 @@ ApproximateZeroLengthSubpathSquareCaps(const Point& aPoint,
} while(0)
TemporaryRef<Path>
SVGPathData::ConstructPath(DrawTarget *aDT,
FillRule aFillRule,
CapStyle aCapStyle) const
SVGPathData::BuildPath(FillRule aFillRule,
uint8_t aStrokeLineCap,
Float aStrokeWidth) const
{
if (mData.IsEmpty() || !IsMoveto(SVGPathSegUtils::DecodeType(mData[0]))) {
return nullptr; // paths without an initial moveto are invalid
}
RefPtr<PathBuilder> builder = aDT->CreatePathBuilder(aFillRule);
RefPtr<DrawTarget> drawTarget =
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
NS_ASSERTION(gfxPlatform::GetPlatform()->
SupportsAzureContentForDrawTarget(drawTarget),
"Should support Moz2D content drawing");
bool capsAreSquare = aCapStyle == CAP_SQUARE;
RefPtr<PathBuilder> builder = drawTarget->CreatePathBuilder(aFillRule);
bool capsAreSquare = aStrokeLineCap == NS_STYLE_STROKE_LINECAP_SQUARE;
bool subpathHasLength = false; // visual length
bool subpathContainsNonArc = false;

View File

@ -12,6 +12,7 @@
#include "nsINode.h"
#include "nsIWeakReferenceUtils.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/RefPtr.h"
#include "nsSVGElement.h"
#include "nsTArray.h"
@ -85,6 +86,7 @@ class SVGPathData
typedef gfx::DrawTarget DrawTarget;
typedef gfx::Path Path;
typedef gfx::FillRule FillRule;
typedef gfx::Float Float;
typedef gfx::CapStyle CapStyle;
public:
@ -161,9 +163,9 @@ public:
ToPath(const gfxMatrix& aMatrix) const;
void ConstructPath(gfxContext *aCtx) const;
TemporaryRef<Path> ConstructPath(DrawTarget* aDT,
FillRule aFillRule,
CapStyle aCapStyle) const;
TemporaryRef<Path> BuildPath(FillRule aFillRule,
uint8_t aCapStyle,
Float aStrokeWidth) const;
const_iterator begin() const { return mData.Elements(); }
const_iterator end() const { return mData.Elements() + mData.Length(); }

View File

@ -13,12 +13,18 @@
#include "gfxPath.h"
#include "mozilla/dom/SVGPathElementBinding.h"
#include "nsCOMPtr.h"
#include "nsComputedDOMStyle.h"
#include "nsGkAtoms.h"
#include "nsStyleConsts.h"
#include "nsStyleStruct.h"
#include "SVGContentUtils.h"
class gfxContext;
NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Path)
using namespace mozilla::gfx;
namespace mozilla {
namespace dom {
@ -350,5 +356,43 @@ SVGPathElement::GetPathLengthScale(PathLengthScaleForType aFor)
return 1.0;
}
TemporaryRef<Path>
SVGPathElement::BuildPath()
{
// The Moz2D PathBuilder that our SVGPathData will be using only cares about
// the fill rule. However, in order to fulfill the requirements of the SVG
// spec regarding zero length sub-paths when square line caps are in use,
// SVGPathData needs to know our stroke-linecap style and, if "square", then
// also our stroke width. See the comment for
// ApproximateZeroLengthSubpathSquareCaps for more info.
uint8_t strokeLineCap = NS_STYLE_STROKE_LINECAP_BUTT;
Float strokeWidth = 0;
nsRefPtr<nsStyleContext> styleContext =
nsComputedDOMStyle::GetStyleContextForElementNoFlush(this, nullptr, nullptr);
if (styleContext) {
const nsStyleSVG* style = styleContext->StyleSVG();
// Note: the path that we return may be used for hit-testing, and SVG
// exposes hit-testing of strokes that are not actually painted. For that
// reason we do not check for eStyleSVGPaintType_None or check the stroke
// opacity here.
if (style->mStrokeLinecap == NS_STYLE_STROKE_LINECAP_SQUARE) {
strokeLineCap = style->mStrokeLinecap;
strokeWidth = GetStrokeWidth();
}
}
// The fill rule that we pass must be the current
// computed value of our CSS 'fill-rule' property if the path that we return
// will be used for painting or hit-testing. For all other uses (bounds
// calculatons, length measurement, position-at-offset calculations) the fill
// rule that we pass doesn't matter. As a result we can just pass the current
// computed value regardless of who's calling us, or what they're going to do
// with the path that we return.
return mD.GetAnimValue().BuildPath(GetFillRule(), strokeLineCap, strokeWidth);
}
} // namespace dom
} // namespace mozilla

View File

@ -47,6 +47,7 @@ public:
virtual bool IsMarkable() MOZ_OVERRIDE;
virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) MOZ_OVERRIDE;
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
virtual already_AddRefed<gfxPath> GetPath(const gfxMatrix &aMatrix) MOZ_OVERRIDE;

View File

@ -8,6 +8,7 @@
#include "nsDebug.h"
#include "gfxPoint.h"
#include "mozilla/gfx/Point.h"
namespace mozilla {
@ -18,6 +19,8 @@ namespace mozilla {
*/
class SVGPoint
{
typedef mozilla::gfx::Point Point;
public:
SVGPoint()
@ -57,6 +60,10 @@ public:
return gfxPoint(mX, mY);
}
operator Point() const {
return Point(mX, mY);
}
#ifdef DEBUG
bool IsValid() const {
return NS_finite(mX) && NS_finite(mY);

View File

@ -7,10 +7,14 @@
#include "nsGkAtoms.h"
#include "gfxContext.h"
#include "mozilla/dom/SVGRectElementBinding.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/PathHelpers.h"
#include <algorithm>
NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Rect)
using namespace mozilla::gfx;
namespace mozilla {
namespace dom {
@ -148,5 +152,51 @@ SVGRectElement::ConstructPath(gfxContext *aCtx)
gfxCornerSizes(corner, corner, corner, corner));
}
TemporaryRef<Path>
SVGRectElement::BuildPath()
{
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
float x, y, width, height, rx, ry;
GetAnimatedLengthValues(&x, &y, &width, &height, &rx, &ry, nullptr);
if (width > 0 && height > 0) {
rx = std::max(rx, 0.0f);
ry = std::max(ry, 0.0f);
if (rx == 0 && ry == 0) {
// Optimization for the no rounded corners case.
Rect r(x, y, width, height);
pathBuilder->MoveTo(r.TopLeft());
pathBuilder->LineTo(r.TopRight());
pathBuilder->LineTo(r.BottomRight());
pathBuilder->LineTo(r.BottomLeft());
pathBuilder->Close();
} else {
// If either the 'rx' or the 'ry' attribute isn't set, then we have to
// set it to the value of the other:
bool hasRx = mLengthAttributes[ATTR_RX].IsExplicitlySet();
bool hasRy = mLengthAttributes[ATTR_RY].IsExplicitlySet();
MOZ_ASSERT(hasRx || hasRy);
if (hasRx && !hasRy) {
ry = rx;
} else if (hasRy && !hasRx) {
rx = ry;
}
// Clamp rx and ry to half the rect's width and height respectively:
rx = std::min(rx, width / 2);
ry = std::min(ry, height / 2);
Size cornerRadii(rx, ry);
Size radii[] = { cornerRadii, cornerRadii, cornerRadii, cornerRadii };
AppendRoundedRectToPath(pathBuilder, Rect(x, y, width, height), radii);
}
}
return pathBuilder->Finish();
}
} // namespace dom
} // namespace mozilla

View File

@ -32,6 +32,7 @@ public:
// nsSVGPathGeometryElement methods:
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;

View File

@ -4,7 +4,15 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsSVGPathGeometryElement.h"
#include "gfxPlatform.h"
#include "mozilla/gfx/2D.h"
#include "nsComputedDOMStyle.h"
#include "nsSVGLength2.h"
#include "SVGContentUtils.h"
using namespace mozilla;
using namespace mozilla::gfx;
//----------------------------------------------------------------------
// Implementation
@ -57,3 +65,61 @@ nsSVGPathGeometryElement::GetPath(const gfxMatrix &aMatrix)
{
return nullptr;
}
TemporaryRef<PathBuilder>
nsSVGPathGeometryElement::CreatePathBuilder()
{
RefPtr<DrawTarget> drawTarget =
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
NS_ASSERTION(gfxPlatform::GetPlatform()->
SupportsAzureContentForDrawTarget(drawTarget),
"Should support Moz2D content drawing");
// The fill rule that we pass to CreatePathBuilder must be the current
// computed value of our CSS 'fill-rule' property if the path that we return
// will be used for painting or hit-testing. For all other uses (bounds
// calculatons, length measurement, position-at-offset calculations) the fill
// rule that we pass doesn't matter. As a result we can just pass the current
// computed value regardless of who's calling us, or what they're going to do
// with the path that we return.
return drawTarget->CreatePathBuilder(GetFillRule());
}
FillRule
nsSVGPathGeometryElement::GetFillRule()
{
FillRule fillRule = FILL_WINDING; // Equivalent to NS_STYLE_FILL_RULE_NONZERO
nsRefPtr<nsStyleContext> styleContext =
nsComputedDOMStyle::GetStyleContextForElementNoFlush(this, nullptr,
nullptr);
if (styleContext) {
MOZ_ASSERT(styleContext->StyleSVG()->mFillRule ==
NS_STYLE_FILL_RULE_NONZERO ||
styleContext->StyleSVG()->mFillRule ==
NS_STYLE_FILL_RULE_EVENODD);
if (styleContext->StyleSVG()->mFillRule == NS_STYLE_FILL_RULE_EVENODD) {
fillRule = FILL_EVEN_ODD;
}
} else {
// ReportToConsole
NS_WARNING("Couldn't get style context for content in GetFillRule");
}
return fillRule;
}
Float
nsSVGPathGeometryElement::GetStrokeWidth()
{
nsRefPtr<nsStyleContext> styleContext =
nsComputedDOMStyle::GetStyleContextForElementNoFlush(this, nullptr,
nullptr);
return styleContext ?
SVGContentUtils::CoordToFloat(styleContext->PresContext(), this,
styleContext->StyleSVG()->mStrokeWidth) :
0.0f;
}

View File

@ -6,6 +6,7 @@
#ifndef __NS_SVGPATHGEOMETRYELEMENT_H__
#define __NS_SVGPATHGEOMETRYELEMENT_H__
#include "mozilla/gfx/2D.h"
#include "SVGGraphicsElement.h"
class gfxPath;
@ -33,6 +34,12 @@ typedef mozilla::dom::SVGGraphicsElement nsSVGPathGeometryElementBase;
class nsSVGPathGeometryElement : public nsSVGPathGeometryElementBase
{
protected:
typedef mozilla::gfx::FillRule FillRule;
typedef mozilla::gfx::Float Float;
typedef mozilla::gfx::Path Path;
typedef mozilla::gfx::PathBuilder PathBuilder;
public:
nsSVGPathGeometryElement(already_AddRefed<nsINodeInfo> aNodeInfo);
@ -52,7 +59,34 @@ public:
virtual bool IsMarkable();
virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks);
virtual void ConstructPath(gfxContext *aCtx) = 0;
/**
* Returns a Path that can be used to paint, hit-test or calculate bounds for
* this element.
*/
virtual mozilla::TemporaryRef<Path> BuildPath() = 0;
virtual already_AddRefed<gfxPath> GetPath(const gfxMatrix &aMatrix);
/**
* Returns a PathBuilder object created using the current computed value of
* the CSS property 'fill-rule' for this element.
*/
mozilla::TemporaryRef<PathBuilder> CreatePathBuilder();
/**
* Returns the current computed value of the CSS property 'fill-rule' for
* this element.
*/
FillRule GetFillRule();
/**
* Returns the current computed value of the CSS property 'stroke-width' for
* this element. (I.e. this 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.)
*/
Float GetStrokeWidth();
};
#endif

View File

@ -6,9 +6,11 @@
#include "nsSVGPolyElement.h"
#include "DOMSVGPointList.h"
#include "gfxContext.h"
#include "mozilla/gfx/2D.h"
#include "SVGContentUtils.h"
using namespace mozilla;
using namespace mozilla::gfx;
//----------------------------------------------------------------------
// nsISupports methods
@ -120,3 +122,19 @@ nsSVGPolyElement::ConstructPath(gfxContext *aCtx)
}
}
TemporaryRef<Path>
nsSVGPolyElement::BuildPath()
{
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
const SVGPointList &points = mPoints.GetAnimValue();
if (!points.IsEmpty()) {
pathBuilder->MoveTo(points[0]);
for (uint32_t i = 1; i < points.Length(); ++i) {
pathBuilder->LineTo(points[i]);
}
}
return pathBuilder->Finish();
}

View File

@ -43,6 +43,7 @@ public:
virtual bool IsMarkable() MOZ_OVERRIDE { return true; }
virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) MOZ_OVERRIDE;
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
virtual mozilla::TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
// WebIDL
already_AddRefed<mozilla::DOMSVGPointList> Points();

View File

@ -5058,9 +5058,9 @@ nsSVGTextFrame2::ShouldRenderAsPath(nsRenderingContext* aContext,
// Text has a stroke.
if (!(style->mStroke.mType == eStyleSVGPaintType_None ||
style->mStrokeOpacity == 0 ||
nsSVGUtils::CoordToFloat(PresContext(),
static_cast<nsSVGElement*>(mContent),
style->mStrokeWidth) == 0)) {
SVGContentUtils::CoordToFloat(PresContext(),
static_cast<nsSVGElement*>(mContent),
style->mStrokeWidth) == 0)) {
return true;
}

View File

@ -391,28 +391,6 @@ nsSVGUtils::ComputeAlphaMask(uint8_t *aData,
}
}
float
nsSVGUtils::CoordToFloat(nsPresContext *aPresContext,
nsSVGElement *aContent,
const nsStyleCoord &aCoord)
{
switch (aCoord.GetUnit()) {
case eStyleUnit_Factor:
// user units
return aCoord.GetFactorValue();
case eStyleUnit_Coord:
return nsPresContext::AppUnitsToFloatCSSPixels(aCoord.GetCoordValue());
case eStyleUnit_Percent: {
SVGSVGElement* ctx = aContent->GetCtx();
return ctx ? aCoord.GetPercentValue() * ctx->GetLength(SVGContentUtils::XY) : 0.0f;
}
default:
return 0.0f;
}
}
nsSVGDisplayContainerFrame*
nsSVGUtils::GetNearestSVGViewport(nsIFrame *aFrame)
{
@ -1621,8 +1599,8 @@ nsSVGUtils::GetStrokeWidth(nsIFrame* aFrame, gfxTextContextPaint *aContextPaint)
nsSVGElement *ctx = static_cast<nsSVGElement*>(content);
return CoordToFloat(aFrame->PresContext(), ctx,
style->mStrokeWidth);
return SVGContentUtils::CoordToFloat(aFrame->PresContext(), ctx,
style->mStrokeWidth);
}
void
@ -1713,9 +1691,9 @@ GetStrokeDashData(nsIFrame* aFrame,
const nsStyleCoord *dasharray = style->mStrokeDasharray;
for (uint32_t i = 0; i < count; i++) {
aDashes[i] = nsSVGUtils::CoordToFloat(presContext,
ctx,
dasharray[i]) * pathScale;
aDashes[i] = SVGContentUtils::CoordToFloat(presContext,
ctx,
dasharray[i]) * pathScale;
if (aDashes[i] < 0.0) {
return false;
}
@ -1726,9 +1704,9 @@ GetStrokeDashData(nsIFrame* aFrame,
if (aContextPaint && style->mStrokeDashoffsetFromObject) {
*aDashOffset = aContextPaint->GetStrokeDashOffset();
} else {
*aDashOffset = nsSVGUtils::CoordToFloat(presContext,
ctx,
style->mStrokeDashoffset);
*aDashOffset = SVGContentUtils::CoordToFloat(presContext,
ctx,
style->mStrokeDashoffset);
}
return (totalLength > 0.0);

View File

@ -292,15 +292,6 @@ public:
const nsIntRect &aRect,
float aOpacity);
/*
* Converts a nsStyleCoord into a userspace value. Handles units
* Factor (straight userspace), Coord (dimensioned), and Percent (of
* the current SVG viewport)
*/
static float CoordToFloat(nsPresContext *aPresContext,
nsSVGElement *aContent,
const nsStyleCoord &aCoord);
/**
* Gets the nearest nsSVGInnerSVGFrame or nsSVGOuterSVGFrame frame. aFrame
* must be an SVG frame. If aFrame is of type nsGkAtoms::svgOuterSVGFrame,