зеркало из https://github.com/mozilla/pjs.git
Bug 349178 - Implement getPathSegAtLength.
Patch by amenzie@us.ibm.com, r=tor, sr=roc
This commit is contained in:
Родитель
18d12280d2
Коммит
c3caf33717
|
@ -1075,104 +1075,27 @@ nsSVGPathDataParserToInternal::ConvertArcToCurves(float x2, float y2,
|
|||
PRBool largeArcFlag,
|
||||
PRBool sweepFlag)
|
||||
{
|
||||
const double radPerDeg = M_PI/180.0;
|
||||
|
||||
double x1=mPx, y1=mPy;
|
||||
|
||||
// 1. Treat out-of-range parameters as described in
|
||||
float x1=mPx, y1=mPy, x3, y3;
|
||||
// Treat out-of-range parameters as described in
|
||||
// http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
|
||||
|
||||
// If the endpoints (x1, y1) and (x2, y2) are identical, then this
|
||||
// is equivalent to omitting the elliptical arc segment entirely
|
||||
if (x1 == x2 && y1 == y2)
|
||||
if (x1 == x2 && y1 == y2) {
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
// If rX = 0 or rY = 0 then this arc is treated as a straight line
|
||||
// segment (a "lineto") joining the endpoints.
|
||||
if (rx == 0.0f || ry == 0.0f) {
|
||||
return PathLineTo(x2, y2);
|
||||
}
|
||||
nsSVGArcConverter converter(x1, y1, x2, y2, rx, ry, angle,
|
||||
largeArcFlag, sweepFlag);
|
||||
|
||||
// If rX or rY have negative signs, these are dropped; the absolute
|
||||
// value is used instead.
|
||||
if (rx<0.0) rx = -rx;
|
||||
if (ry<0.0) ry = -ry;
|
||||
|
||||
// 2. convert to center parameterization as shown in
|
||||
// http://www.w3.org/TR/SVG/implnote.html
|
||||
double sinPhi = sin(angle*radPerDeg);
|
||||
double cosPhi = cos(angle*radPerDeg);
|
||||
|
||||
double x1dash = cosPhi * (x1-x2)/2.0 + sinPhi * (y1-y2)/2.0;
|
||||
double y1dash = -sinPhi * (x1-x2)/2.0 + cosPhi * (y1-y2)/2.0;
|
||||
|
||||
double root;
|
||||
double numerator = rx*rx*ry*ry - rx*rx*y1dash*y1dash - ry*ry*x1dash*x1dash;
|
||||
|
||||
if (numerator < 0.0) {
|
||||
// If rX , rY and are such that there is no solution (basically,
|
||||
// the ellipse is not big enough to reach from (x1, y1) to (x2,
|
||||
// y2)) then the ellipse is scaled up uniformly until there is
|
||||
// exactly one solution (until the ellipse is just big enough).
|
||||
|
||||
// -> find factor s, such that numerator' with rx'=s*rx and
|
||||
// ry'=s*ry becomes 0 :
|
||||
float s = (float)sqrt(1.0 - numerator/(rx*rx*ry*ry));
|
||||
|
||||
rx *= s;
|
||||
ry *= s;
|
||||
root = 0.0;
|
||||
|
||||
}
|
||||
else {
|
||||
root = (largeArcFlag == sweepFlag ? -1.0 : 1.0) *
|
||||
sqrt( numerator/(rx*rx*y1dash*y1dash + ry*ry*x1dash*x1dash) );
|
||||
}
|
||||
|
||||
double cxdash = root*rx*y1dash/ry;
|
||||
double cydash = -root*ry*x1dash/rx;
|
||||
|
||||
double cx = cosPhi * cxdash - sinPhi * cydash + (x1+x2)/2.0;
|
||||
double cy = sinPhi * cxdash + cosPhi * cydash + (y1+y2)/2.0;
|
||||
double theta1 = CalcVectorAngle(1.0, 0.0, (x1dash-cxdash)/rx, (y1dash-cydash)/ry);
|
||||
double dtheta = CalcVectorAngle((x1dash-cxdash)/rx, (y1dash-cydash)/ry,
|
||||
(-x1dash-cxdash)/rx, (-y1dash-cydash)/ry);
|
||||
if (!sweepFlag && dtheta>0)
|
||||
dtheta -= 2.0*M_PI;
|
||||
else if (sweepFlag && dtheta<0)
|
||||
dtheta += 2.0*M_PI;
|
||||
|
||||
// 3. convert into cubic bezier segments <= 90deg
|
||||
int segments = (int)ceil(fabs(dtheta/(M_PI/2.0)));
|
||||
double delta = dtheta/segments;
|
||||
double t = 8.0/3.0 * sin(delta/4.0) * sin(delta/4.0) / sin(delta/2.0);
|
||||
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
double cosTheta1 = cos(theta1);
|
||||
double sinTheta1 = sin(theta1);
|
||||
double theta2 = theta1 + delta;
|
||||
double cosTheta2 = cos(theta2);
|
||||
double sinTheta2 = sin(theta2);
|
||||
|
||||
// a) calculate endpoint of the segment:
|
||||
double xe = cosPhi * rx*cosTheta2 - sinPhi * ry*sinTheta2 + cx;
|
||||
double ye = sinPhi * rx*cosTheta2 + cosPhi * ry*sinTheta2 + cy;
|
||||
|
||||
// b) calculate gradients at start/end points of segment:
|
||||
double dx1 = t * ( - cosPhi * rx*sinTheta1 - sinPhi * ry*cosTheta1);
|
||||
double dy1 = t * ( - sinPhi * rx*sinTheta1 + cosPhi * ry*cosTheta1);
|
||||
|
||||
double dxe = t * ( cosPhi * rx*sinTheta2 + sinPhi * ry*cosTheta2);
|
||||
double dye = t * ( sinPhi * rx*sinTheta2 - cosPhi * ry*cosTheta2);
|
||||
|
||||
while (converter.GetNextSegment(&x1, &y1, &x2, &y2, &x3, &y3)) {
|
||||
// c) draw the cubic bezier:
|
||||
nsresult rv = PathCurveTo(x1+dx1, y1+dy1, xe+dxe, ye+dye, xe, ye);
|
||||
nsresult rv = PathCurveTo(x1, y1, x2, y2, x3, y3);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// do next segment
|
||||
theta1 = theta2;
|
||||
x1 = (float)xe;
|
||||
y1 = (float)ye;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -1420,3 +1343,107 @@ nsSVGPathDataParserToDOM::StoreEllipticalArc(PRBool absCoords,
|
|||
largeArcFlag, sweepFlag));
|
||||
}
|
||||
|
||||
nsSVGArcConverter::nsSVGArcConverter(float x1, float y1,
|
||||
float x2, float y2,
|
||||
float rx, float ry,
|
||||
float angle,
|
||||
PRBool largeArcFlag,
|
||||
PRBool sweepFlag)
|
||||
{
|
||||
const double radPerDeg = M_PI/180.0;
|
||||
|
||||
// If rX or rY have negative signs, these are dropped; the absolute
|
||||
// value is used instead.
|
||||
mRx = fabs(rx);
|
||||
mRy = fabs(ry);
|
||||
|
||||
// Convert to center parameterization as shown in
|
||||
// http://www.w3.org/TR/SVG/implnote.html
|
||||
mSinPhi = sin(angle*radPerDeg);
|
||||
mCosPhi = cos(angle*radPerDeg);
|
||||
|
||||
double x1dash = mCosPhi * (x1-x2)/2.0 + mSinPhi * (y1-y2)/2.0;
|
||||
double y1dash = -mSinPhi * (x1-x2)/2.0 + mCosPhi * (y1-y2)/2.0;
|
||||
|
||||
double root;
|
||||
double numerator = mRx*mRx*mRy*mRy - mRx*mRx*y1dash*y1dash -
|
||||
mRy*mRy*x1dash*x1dash;
|
||||
|
||||
if (numerator < 0.0) {
|
||||
// If mRx , mRy and are such that there is no solution (basically,
|
||||
// the ellipse is not big enough to reach from (x1, y1) to (x2,
|
||||
// y2)) then the ellipse is scaled up uniformly until there is
|
||||
// exactly one solution (until the ellipse is just big enough).
|
||||
|
||||
// -> find factor s, such that numerator' with mRx'=s*mRx and
|
||||
// mRy'=s*mRy becomes 0 :
|
||||
float s = (float)sqrt(1.0 - numerator/(mRx*mRx*mRy*mRy));
|
||||
|
||||
mRx *= s;
|
||||
mRy *= s;
|
||||
root = 0.0;
|
||||
|
||||
}
|
||||
else {
|
||||
root = (largeArcFlag == sweepFlag ? -1.0 : 1.0) *
|
||||
sqrt( numerator/(mRx*mRx*y1dash*y1dash + mRy*mRy*x1dash*x1dash) );
|
||||
}
|
||||
|
||||
double cxdash = root*mRx*y1dash/mRy;
|
||||
double cydash = -root*mRy*x1dash/mRx;
|
||||
|
||||
mCx = mCosPhi * cxdash - mSinPhi * cydash + (x1+x2)/2.0;
|
||||
mCy = mSinPhi * cxdash + mCosPhi * cydash + (y1+y2)/2.0;
|
||||
mTheta = CalcVectorAngle(1.0, 0.0, (x1dash-cxdash)/mRx, (y1dash-cydash)/mRy);
|
||||
double dtheta = CalcVectorAngle((x1dash-cxdash)/mRx, (y1dash-cydash)/mRy,
|
||||
(-x1dash-cxdash)/mRx, (-y1dash-cydash)/mRy);
|
||||
if (!sweepFlag && dtheta>0)
|
||||
dtheta -= 2.0*M_PI;
|
||||
else if (sweepFlag && dtheta<0)
|
||||
dtheta += 2.0*M_PI;
|
||||
|
||||
// Convert into cubic bezier segments <= 90deg
|
||||
mNumSegs = NS_STATIC_CAST(int, ceil(fabs(dtheta/(M_PI/2.0))));
|
||||
mDelta = dtheta/mNumSegs;
|
||||
mT = 8.0/3.0 * sin(mDelta/4.0) * sin(mDelta/4.0) / sin(mDelta/2.0);
|
||||
|
||||
mX1 = x1;
|
||||
mY1 = y1;
|
||||
mSegIndex = 0;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSVGArcConverter::GetNextSegment(float *x1, float *y1,
|
||||
float *x2, float *y2,
|
||||
float *x3, float *y3)
|
||||
{
|
||||
if (mSegIndex == mNumSegs) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
float cosTheta1 = cos(mTheta);
|
||||
float sinTheta1 = sin(mTheta);
|
||||
float theta2 = mTheta + mDelta;
|
||||
float cosTheta2 = cos(theta2);
|
||||
float sinTheta2 = sin(theta2);
|
||||
|
||||
// a) calculate endpoint of the segment:
|
||||
*x3 = mCosPhi * mRx*cosTheta2 - mSinPhi * mRy*sinTheta2 + mCx;
|
||||
*y3 = mSinPhi * mRx*cosTheta2 + mCosPhi * mRy*sinTheta2 + mCy;
|
||||
|
||||
// b) calculate gradients at start/end points of segment:
|
||||
*x1 = mX1 + mT * ( - mCosPhi * mRx*sinTheta1 - mSinPhi * mRy*cosTheta1);
|
||||
*y1 = mY1 + mT * ( - mSinPhi * mRx*sinTheta1 + mCosPhi * mRy*cosTheta1);
|
||||
|
||||
*x2 = *x3 + mT * ( mCosPhi * mRx*sinTheta2 + mSinPhi * mRy*cosTheta2);
|
||||
*y2 = *y3 + mT * ( mSinPhi * mRx*sinTheta2 - mCosPhi * mRy*cosTheta2);
|
||||
|
||||
// do next segment
|
||||
mTheta = theta2;
|
||||
mX1 = *x3;
|
||||
mY1 = *y3;
|
||||
++mSegIndex;
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -221,4 +221,24 @@ private:
|
|||
nsCOMArray<nsIDOMSVGPathSeg>* mData;
|
||||
};
|
||||
|
||||
class nsSVGArcConverter
|
||||
{
|
||||
public:
|
||||
nsSVGArcConverter(float x1, float y1,
|
||||
float x2, float y2,
|
||||
float rx, float ry,
|
||||
float angle,
|
||||
PRBool largeArcFlag,
|
||||
PRBool sweepFlag);
|
||||
PRBool GetNextSegment(float *x1, float *y1,
|
||||
float *x2, float *y2,
|
||||
float *x3, float *y3);
|
||||
protected:
|
||||
PRInt32 mNumSegs, mSegIndex;
|
||||
float mTheta, mDelta, mT;
|
||||
float mSinPhi, mCosPhi;
|
||||
float mX1, mY1, mRx, mRy, mCx, mCy;
|
||||
|
||||
};
|
||||
|
||||
#endif // __NS_SVGPATHDATAPARSER_H__
|
||||
|
|
|
@ -139,7 +139,38 @@ nsSVGPathElement::GetPointAtLength(float distance, nsIDOMSVGPoint **_retval)
|
|||
NS_IMETHODIMP
|
||||
nsSVGPathElement::GetPathSegAtLength(float distance, PRUint32 *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
//Check if mSegments is null
|
||||
nsresult rv = CreatePathSegList();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRUint32 i = 0, numSegments;
|
||||
float distCovered = 0;
|
||||
nsSVGPathSegTraversalState ts;
|
||||
|
||||
mSegments->GetNumberOfItems(&numSegments);
|
||||
|
||||
// There is no need to check to see if distance falls within the last segment
|
||||
// because if distance is longer than the total length of the path we return
|
||||
// the index of the final segment anyway.
|
||||
while (distCovered < distance && i < numSegments - 1) {
|
||||
nsIDOMSVGPathSeg *iSeg;
|
||||
mSegments->GetItem(i, &iSeg);
|
||||
nsSVGPathSeg* curSeg = NS_STATIC_CAST(nsSVGPathSeg*, iSeg);
|
||||
if (i == 0) {
|
||||
curSeg->GetLength(&ts);
|
||||
} else {
|
||||
distCovered += curSeg->GetLength(&ts);
|
||||
}
|
||||
|
||||
if (distCovered >= distance) {
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
*_retval = i;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* nsIDOMSVGPathSegClosePath createSVGPathSegClosePath (); */
|
||||
|
|
|
@ -42,6 +42,15 @@
|
|||
#include "nsTextFormatter.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
|
||||
struct PathPoint {
|
||||
float x, y;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Error threshold to use when calculating the length of Bezier curves
|
||||
static const float PATH_SEG_LENGTH_TOLERANCE = 0.0000001f;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// implementation helper macros
|
||||
|
||||
|
@ -54,6 +63,73 @@ NS_INTERFACE_MAP_BEGIN(ns##basename) \
|
|||
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(basename) \
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsSVGPathSeg)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// GetLength Helper Functions
|
||||
|
||||
static float GetDistance(float x1, float x2, float y1, float y2)
|
||||
{
|
||||
return sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
|
||||
}
|
||||
|
||||
static void SplitQuadraticBezier(PathPoint *curve,
|
||||
PathPoint *left,
|
||||
PathPoint *right)
|
||||
{
|
||||
left[0].x = curve[0].x;
|
||||
left[0].y = curve[0].y;
|
||||
right[2].x = curve[2].x;
|
||||
right[2].y = curve[2].y;
|
||||
left[1].x = (curve[0].x + curve[1].x) / 2;
|
||||
left[1].y = (curve[0].y + curve[1].y) / 2;
|
||||
right[1].x = (curve[1].x + curve[2].x) / 2;
|
||||
right[1].y = (curve[1].y + curve[2].y) / 2;
|
||||
left[2].x = right[0].x = (left[1].x + right[1].x) / 2;
|
||||
left[2].y = right[0].y = (left[1].y + right[1].y) / 2;
|
||||
}
|
||||
|
||||
static void SplitCubicBezier(PathPoint *curve,
|
||||
PathPoint *left,
|
||||
PathPoint *right)
|
||||
{
|
||||
PathPoint tmp;
|
||||
tmp.x = (curve[1].x + curve[2].x) / 4;
|
||||
tmp.y = (curve[1].y + curve[2].y) / 4;
|
||||
left[0].x = curve[0].x;
|
||||
left[0].y = curve[0].y;
|
||||
right[3].x = curve[3].x;
|
||||
right[3].y = curve[3].y;
|
||||
left[1].x = (curve[0].x + curve[1].x) / 2;
|
||||
left[1].y = (curve[0].y + curve[1].y) / 2;
|
||||
right[2].x = (curve[2].x + curve[3].x) / 2;
|
||||
right[2].y = (curve[2].y + curve[3].y) / 2;
|
||||
left[2].x = left[1].x / 2 + tmp.x;
|
||||
left[2].y = left[1].y / 2 + tmp.y;
|
||||
right[1].x = right[2].x / 2 + tmp.x;
|
||||
right[1].y = right[2].y / 2 + tmp.y;
|
||||
left[3].x = right[0].x = (left[2].x + right[1].x) / 2;
|
||||
left[3].y = right[0].y = (left[2].y + right[1].y) / 2;
|
||||
}
|
||||
|
||||
static float CalcBezLength(PathPoint *curve,PRUint32 numPts,
|
||||
void (*split)(PathPoint*, PathPoint*, PathPoint*))
|
||||
{
|
||||
PathPoint left[4];
|
||||
PathPoint right[4];
|
||||
float length = 0, dist;
|
||||
PRUint32 i;
|
||||
for (i = 0; i < numPts - 1; i++) {
|
||||
length += GetDistance(curve[i].x, curve[i+1].x, curve[i].y, curve[i+1].y);
|
||||
}
|
||||
dist = GetDistance(curve[0].x, curve[numPts - 1].x,
|
||||
curve[0].y, curve[numPts - 1].y);
|
||||
if (length - dist > PATH_SEG_LENGTH_TOLERANCE) {
|
||||
split(curve, left, right);
|
||||
return CalcBezLength(left, numPts, split) +
|
||||
CalcBezLength(right, numPts, split);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// nsSVGPathSeg
|
||||
|
||||
|
@ -127,7 +203,7 @@ public:
|
|||
|
||||
// nsSVGPathSeg methods:
|
||||
NS_IMETHOD GetValueString(nsAString& aValue);
|
||||
|
||||
virtual float GetLength(nsSVGPathSegTraversalState *ts);
|
||||
virtual PRUint16 GetSegType()
|
||||
{ return nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH; }
|
||||
};
|
||||
|
@ -154,6 +230,16 @@ nsSVGPathSegClosePath::GetValueString(nsAString& aValue)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGPathSegClosePath::GetLength(nsSVGPathSegTraversalState *ts)
|
||||
{
|
||||
float dist = GetDistance(ts->startPosX, ts->curPosX,
|
||||
ts->startPosY, ts->curPosY);
|
||||
ts->quadCPX = ts->cubicCPX = ts->curPosX = ts->startPosX;
|
||||
ts->quadCPY = ts->cubicCPY = ts->curPosY = ts->startPosY;
|
||||
return dist;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// nsSVGPathSegMovetoAbs
|
||||
|
||||
|
@ -171,7 +257,7 @@ public:
|
|||
|
||||
// nsSVGPathSeg methods:
|
||||
NS_IMETHOD GetValueString(nsAString& aValue);
|
||||
|
||||
virtual float GetLength(nsSVGPathSegTraversalState *ts);
|
||||
virtual PRUint16 GetSegType()
|
||||
{ return nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS; }
|
||||
|
||||
|
@ -210,6 +296,14 @@ nsSVGPathSegMovetoAbs::GetValueString(nsAString& aValue)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGPathSegMovetoAbs::GetLength(nsSVGPathSegTraversalState *ts)
|
||||
{
|
||||
ts->cubicCPX = ts->quadCPX = ts->startPosX = ts->curPosX = mX;
|
||||
ts->cubicCPY = ts->quadCPY = ts->startPosY = ts->curPosY = mY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGPathSegMovetoAbs methods:
|
||||
|
||||
|
@ -257,7 +351,7 @@ public:
|
|||
|
||||
// nsSVGPathSeg methods:
|
||||
NS_IMETHOD GetValueString(nsAString& aValue);
|
||||
|
||||
virtual float GetLength(nsSVGPathSegTraversalState *ts);
|
||||
virtual PRUint16 GetSegType()
|
||||
{ return nsIDOMSVGPathSeg::PATHSEG_MOVETO_REL; }
|
||||
|
||||
|
@ -295,6 +389,15 @@ nsSVGPathSegMovetoRel::GetValueString(nsAString& aValue)
|
|||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGPathSegMovetoRel::GetLength(nsSVGPathSegTraversalState *ts)
|
||||
{
|
||||
ts->cubicCPX = ts->quadCPX = ts->startPosX = ts->curPosX += mX;
|
||||
ts->cubicCPY = ts->quadCPY = ts->startPosY = ts->curPosY += mY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGPathSegMovetoRel methods:
|
||||
|
||||
|
@ -341,7 +444,7 @@ public:
|
|||
|
||||
// nsSVGPathSeg methods:
|
||||
NS_IMETHOD GetValueString(nsAString& aValue);
|
||||
|
||||
virtual float GetLength(nsSVGPathSegTraversalState *ts);
|
||||
virtual PRUint16 GetSegType()
|
||||
{ return nsIDOMSVGPathSeg::PATHSEG_LINETO_ABS; }
|
||||
|
||||
|
@ -379,6 +482,17 @@ nsSVGPathSegLinetoAbs::GetValueString(nsAString& aValue)
|
|||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGPathSegLinetoAbs::GetLength(nsSVGPathSegTraversalState *ts)
|
||||
{
|
||||
|
||||
float dist = GetDistance(ts->curPosX, mX, ts->curPosY, mY);
|
||||
ts->cubicCPX = ts->quadCPX = ts->curPosX = mX;
|
||||
ts->cubicCPY = ts->quadCPY = ts->curPosY = mY;
|
||||
return dist;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGPathSegLinetoAbs methods:
|
||||
|
||||
|
@ -426,7 +540,7 @@ public:
|
|||
|
||||
// nsSVGPathSeg methods:
|
||||
NS_IMETHOD GetValueString(nsAString& aValue);
|
||||
|
||||
virtual float GetLength(nsSVGPathSegTraversalState *ts);
|
||||
virtual PRUint16 GetSegType()
|
||||
{ return nsIDOMSVGPathSeg::PATHSEG_LINETO_REL; }
|
||||
|
||||
|
@ -465,6 +579,14 @@ nsSVGPathSegLinetoRel::GetValueString(nsAString& aValue)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGPathSegLinetoRel::GetLength(nsSVGPathSegTraversalState *ts)
|
||||
{
|
||||
ts->cubicCPX = ts->quadCPX = ts->curPosX += mX;
|
||||
ts->cubicCPY = ts->quadCPY = ts->curPosY += mY;
|
||||
return sqrt(mX * mX + mY * mY);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGPathSegLinetoRel methods:
|
||||
|
||||
|
@ -514,7 +636,7 @@ public:
|
|||
|
||||
// nsSVGPathSeg methods:
|
||||
NS_IMETHOD GetValueString(nsAString& aValue);
|
||||
|
||||
virtual float GetLength(nsSVGPathSegTraversalState *ts);
|
||||
virtual PRUint16 GetSegType()
|
||||
{ return nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS; }
|
||||
|
||||
|
@ -558,6 +680,22 @@ nsSVGPathSegCurvetoCubicAbs::GetValueString(nsAString& aValue)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGPathSegCurvetoCubicAbs::GetLength(nsSVGPathSegTraversalState *ts)
|
||||
{
|
||||
PathPoint curve[4] = { {ts->curPosX, ts->curPosY},
|
||||
{mX1, mY1},
|
||||
{mX2, mY2},
|
||||
{mX, mY} };
|
||||
float dist = CalcBezLength(curve, 4, SplitCubicBezier);
|
||||
|
||||
ts->quadCPX = ts->curPosX = mX;
|
||||
ts->quadCPY = ts->curPosY = mY;
|
||||
ts->cubicCPX = mX2;
|
||||
ts->cubicCPY = mY2;
|
||||
return dist;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGPathSegCurvetoCubicAbs methods:
|
||||
|
||||
|
@ -659,7 +797,7 @@ public:
|
|||
|
||||
// nsSVGPathSeg methods:
|
||||
NS_IMETHOD GetValueString(nsAString& aValue);
|
||||
|
||||
virtual float GetLength(nsSVGPathSegTraversalState *ts);
|
||||
virtual PRUint16 GetSegType()
|
||||
{ return nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL; }
|
||||
|
||||
|
@ -703,6 +841,19 @@ nsSVGPathSegCurvetoCubicRel::GetValueString(nsAString& aValue)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGPathSegCurvetoCubicRel::GetLength(nsSVGPathSegTraversalState *ts)
|
||||
{
|
||||
PathPoint curve[4] = { {0, 0}, {mX1, mY1}, {mX2, mY2}, {mX, mY} };
|
||||
float dist = CalcBezLength(curve, 4, SplitCubicBezier);
|
||||
|
||||
ts->cubicCPX = mX2 + ts->curPosX;
|
||||
ts->cubicCPY = mY2 + ts->curPosY;
|
||||
ts->quadCPX = ts->curPosX += mX;
|
||||
ts->quadCPY = ts->curPosY += mY;
|
||||
return dist;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGPathSegCurvetoCubicRel methods:
|
||||
|
||||
|
@ -802,7 +953,7 @@ public:
|
|||
|
||||
// nsSVGPathSeg methods:
|
||||
NS_IMETHOD GetValueString(nsAString& aValue);
|
||||
|
||||
virtual float GetLength(nsSVGPathSegTraversalState *ts);
|
||||
virtual PRUint16 GetSegType()
|
||||
{ return nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS; }
|
||||
|
||||
|
@ -845,6 +996,19 @@ nsSVGPathSegCurvetoQuadraticAbs::GetValueString(nsAString& aValue)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGPathSegCurvetoQuadraticAbs::GetLength(nsSVGPathSegTraversalState *ts)
|
||||
{
|
||||
PathPoint curve[3] = { {ts->curPosX, ts->curPosY}, {mX1, mY1}, {mX, mY} };
|
||||
float dist = CalcBezLength(curve, 3, SplitQuadraticBezier);
|
||||
|
||||
ts->quadCPX = mX1;
|
||||
ts->quadCPY = mY1;
|
||||
ts->cubicCPX = ts->curPosX = mX;
|
||||
ts->cubicCPY = ts->curPosY = mY;
|
||||
return dist;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGPathSegCurvetoQuadraticAbs methods:
|
||||
|
||||
|
@ -919,7 +1083,7 @@ public:
|
|||
|
||||
// nsSVGPathSeg methods:
|
||||
NS_IMETHOD GetValueString(nsAString& aValue);
|
||||
|
||||
virtual float GetLength(nsSVGPathSegTraversalState *ts);
|
||||
virtual PRUint16 GetSegType()
|
||||
{ return nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL; }
|
||||
|
||||
|
@ -963,6 +1127,19 @@ nsSVGPathSegCurvetoQuadraticRel::GetValueString(nsAString& aValue)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGPathSegCurvetoQuadraticRel::GetLength(nsSVGPathSegTraversalState *ts)
|
||||
{
|
||||
PathPoint curve[3] = { {0, 0}, {mX1, mY1}, {mX, mY} };
|
||||
float dist = CalcBezLength(curve, 3, SplitQuadraticBezier);
|
||||
|
||||
ts->quadCPX = mX1 + ts->curPosX;
|
||||
ts->quadCPY = mY1 + ts->curPosY;
|
||||
ts->cubicCPX = ts->curPosX += mX;
|
||||
ts->cubicCPY = ts->curPosY += mY;
|
||||
return dist;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGPathSegCurvetoQuadraticRel methods:
|
||||
|
||||
|
@ -1038,7 +1215,7 @@ public:
|
|||
|
||||
// nsSVGPathSeg methods:
|
||||
NS_IMETHOD GetValueString(nsAString& aValue);
|
||||
|
||||
virtual float GetLength(nsSVGPathSegTraversalState *ts);
|
||||
virtual PRUint16 GetSegType()
|
||||
{ return nsIDOMSVGPathSeg::PATHSEG_ARC_ABS; }
|
||||
|
||||
|
@ -1086,6 +1263,25 @@ nsSVGPathSegArcAbs::GetValueString(nsAString& aValue)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGPathSegArcAbs::GetLength(nsSVGPathSegTraversalState *ts)
|
||||
{
|
||||
PathPoint bez[4] = { {ts->curPosX, ts->curPosY}, {0,0}, {0,0}, {0,0}};
|
||||
nsSVGArcConverter converter(ts->curPosX, ts->curPosY, mX, mY, mR1,
|
||||
mR2, mAngle, mLargeArcFlag, mSweepFlag);
|
||||
float dist = 0;
|
||||
while (converter.GetNextSegment(&bez[1].x, &bez[1].y, &bez[2].x, &bez[2].y,
|
||||
&bez[3].x, &bez[3].y))
|
||||
{
|
||||
dist += CalcBezLength(bez, 4, SplitCubicBezier);
|
||||
bez[0].x = bez[3].x;
|
||||
bez[0].y = bez[3].y;
|
||||
}
|
||||
ts->cubicCPX = ts->quadCPX = ts->curPosX = mX;
|
||||
ts->cubicCPY = ts->quadCPY = ts->curPosY = mY;
|
||||
return dist;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGPathSegArcAbs methods:
|
||||
|
||||
|
@ -1200,7 +1396,7 @@ public:
|
|||
|
||||
// nsSVGPathSeg methods:
|
||||
NS_IMETHOD GetValueString(nsAString& aValue);
|
||||
|
||||
virtual float GetLength(nsSVGPathSegTraversalState *ts);
|
||||
virtual PRUint16 GetSegType()
|
||||
{ return nsIDOMSVGPathSeg::PATHSEG_ARC_REL; }
|
||||
|
||||
|
@ -1247,6 +1443,26 @@ nsSVGPathSegArcRel::GetValueString(nsAString& aValue)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGPathSegArcRel::GetLength(nsSVGPathSegTraversalState *ts)
|
||||
{
|
||||
PathPoint bez[4] = { {0, 0}, {0,0}, {0,0}, {0,0}};
|
||||
nsSVGArcConverter converter(0, 0, mX, mY, mR1, mR2, mAngle,
|
||||
mLargeArcFlag, mSweepFlag);
|
||||
float dist = 0;
|
||||
while (converter.GetNextSegment(&bez[1].x, &bez[1].y, &bez[2].x, &bez[2].y,
|
||||
&bez[3].x, &bez[3].y))
|
||||
{
|
||||
dist += CalcBezLength(bez, 4, SplitCubicBezier);
|
||||
bez[0].x = bez[3].x;
|
||||
bez[0].y = bez[3].y;
|
||||
}
|
||||
|
||||
ts->cubicCPX = ts->quadCPX = ts->curPosX += mX;
|
||||
ts->cubicCPY = ts->quadCPY = ts->curPosY += mY;
|
||||
return dist;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGPathSegArcRel methods:
|
||||
|
||||
|
@ -1359,7 +1575,7 @@ public:
|
|||
|
||||
// nsSVGPathSeg methods:
|
||||
NS_IMETHOD GetValueString(nsAString& aValue);
|
||||
|
||||
virtual float GetLength(nsSVGPathSegTraversalState *ts);
|
||||
virtual PRUint16 GetSegType()
|
||||
{ return nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_ABS; }
|
||||
|
||||
|
@ -1399,6 +1615,15 @@ nsSVGPathSegLinetoHorizontalAbs::GetValueString(nsAString& aValue)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGPathSegLinetoHorizontalAbs::GetLength(nsSVGPathSegTraversalState *ts)
|
||||
{
|
||||
float dist = fabs(mX - ts->curPosX);
|
||||
ts->cubicCPX = ts->quadCPX = ts->curPosX = mX;
|
||||
ts->cubicCPY = ts->quadCPY = ts->curPosY;
|
||||
return dist;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGPathSegLinetoHorizontalAbs methods:
|
||||
|
||||
|
@ -1432,7 +1657,7 @@ public:
|
|||
|
||||
// nsSVGPathSeg methods:
|
||||
NS_IMETHOD GetValueString(nsAString& aValue);
|
||||
|
||||
virtual float GetLength(nsSVGPathSegTraversalState *ts);
|
||||
virtual PRUint16 GetSegType()
|
||||
{ return nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_REL; }
|
||||
|
||||
|
@ -1472,6 +1697,14 @@ nsSVGPathSegLinetoHorizontalRel::GetValueString(nsAString& aValue)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGPathSegLinetoHorizontalRel::GetLength(nsSVGPathSegTraversalState *ts)
|
||||
{
|
||||
ts->cubicCPX = ts->quadCPX = ts->curPosX += mX;
|
||||
ts->cubicCPY = ts->quadCPY = ts->curPosY;
|
||||
return fabs(mX);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGPathSegLinetoHorizontalRel methods:
|
||||
|
||||
|
@ -1505,7 +1738,7 @@ public:
|
|||
|
||||
// nsSVGPathSeg methods:
|
||||
NS_IMETHOD GetValueString(nsAString& aValue);
|
||||
|
||||
virtual float GetLength(nsSVGPathSegTraversalState *ts);
|
||||
virtual PRUint16 GetSegType()
|
||||
{ return nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_ABS; }
|
||||
|
||||
|
@ -1545,6 +1778,15 @@ nsSVGPathSegLinetoVerticalAbs::GetValueString(nsAString& aValue)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGPathSegLinetoVerticalAbs::GetLength(nsSVGPathSegTraversalState *ts)
|
||||
{
|
||||
float dist = fabs(mY - ts->curPosY);
|
||||
ts->cubicCPY = ts->quadCPY = ts->curPosY = mY;
|
||||
ts->cubicCPX = ts->quadCPX = ts->curPosX;
|
||||
return dist;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGPathSegLinetoVerticalAbs methods:
|
||||
|
||||
|
@ -1578,7 +1820,7 @@ public:
|
|||
|
||||
// nsSVGPathSeg methods:
|
||||
NS_IMETHOD GetValueString(nsAString& aValue);
|
||||
|
||||
virtual float GetLength(nsSVGPathSegTraversalState *ts);
|
||||
virtual PRUint16 GetSegType()
|
||||
{ return nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_REL; }
|
||||
|
||||
|
@ -1619,6 +1861,14 @@ nsSVGPathSegLinetoVerticalRel::GetValueString(nsAString& aValue)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGPathSegLinetoVerticalRel::GetLength(nsSVGPathSegTraversalState *ts)
|
||||
{
|
||||
ts->cubicCPY = ts->quadCPY = ts->curPosY += mY;
|
||||
ts->cubicCPX = ts->quadCPX = ts->curPosX;
|
||||
return fabs(mY);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGPathSegLinetoVerticalRel methods:
|
||||
|
||||
|
@ -1653,7 +1903,7 @@ public:
|
|||
|
||||
// nsSVGPathSeg methods:
|
||||
NS_IMETHOD GetValueString(nsAString& aValue);
|
||||
|
||||
virtual float GetLength(nsSVGPathSegTraversalState *ts);
|
||||
virtual PRUint16 GetSegType()
|
||||
{ return nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS; }
|
||||
|
||||
|
@ -1696,6 +1946,25 @@ nsSVGPathSegCurvetoCubicSmoothAbs::GetValueString(nsAString& aValue)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGPathSegCurvetoCubicSmoothAbs::GetLength(nsSVGPathSegTraversalState *ts)
|
||||
{
|
||||
float x1 = 2 * ts->curPosX - ts->cubicCPX;
|
||||
float y1 = 2 * ts->curPosY - ts->cubicCPY;
|
||||
|
||||
PathPoint curve[4] = { {ts->curPosX, ts->curPosY},
|
||||
{x1, y1},
|
||||
{mX2, mY2},
|
||||
{mX, mY} };
|
||||
float dist = CalcBezLength(curve, 4, SplitCubicBezier);
|
||||
|
||||
ts->cubicCPX = mX2;
|
||||
ts->cubicCPY = mY2;
|
||||
ts->quadCPX = ts->curPosX = mX;
|
||||
ts->quadCPY = ts->curPosY = mY;
|
||||
return dist;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGPathSegCurvetoCubicSmoothAbs methods:
|
||||
|
||||
|
@ -1769,7 +2038,7 @@ public:
|
|||
|
||||
// nsSVGPathSeg methods:
|
||||
NS_IMETHOD GetValueString(nsAString& aValue);
|
||||
|
||||
virtual float GetLength(nsSVGPathSegTraversalState *ts);
|
||||
virtual PRUint16 GetSegType()
|
||||
{ return nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL; }
|
||||
|
||||
|
@ -1812,6 +2081,23 @@ nsSVGPathSegCurvetoCubicSmoothRel::GetValueString(nsAString& aValue)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGPathSegCurvetoCubicSmoothRel::GetLength(nsSVGPathSegTraversalState *ts)
|
||||
{
|
||||
|
||||
float x1 = ts->curPosX - ts->cubicCPX;
|
||||
float y1 = ts->curPosY - ts->cubicCPY;
|
||||
|
||||
PathPoint curve[4] = { {0, 0}, {x1, y1}, {mX2, mY2}, {mX, mY} };
|
||||
float dist = CalcBezLength(curve, 4, SplitCubicBezier);
|
||||
|
||||
ts->cubicCPX = mX2 + ts->curPosX;
|
||||
ts->cubicCPY = mY2 + ts->curPosY;
|
||||
ts->quadCPX = ts->curPosX += mX;
|
||||
ts->quadCPY = ts->curPosY += mY;
|
||||
return dist;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGPathSegCurvetoCubicSmoothRel methods:
|
||||
|
||||
|
@ -1884,7 +2170,7 @@ public:
|
|||
|
||||
// nsSVGPathSeg methods:
|
||||
NS_IMETHOD GetValueString(nsAString& aValue);
|
||||
|
||||
virtual float GetLength(nsSVGPathSegTraversalState *ts);
|
||||
virtual PRUint16 GetSegType()
|
||||
{ return nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS; }
|
||||
|
||||
|
@ -1923,6 +2209,22 @@ nsSVGPathSegCurvetoQuadraticSmoothAbs::GetValueString(nsAString& aValue)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGPathSegCurvetoQuadraticSmoothAbs::GetLength(nsSVGPathSegTraversalState *ts)
|
||||
{
|
||||
ts->quadCPX = 2 * ts->curPosX - ts->quadCPX;
|
||||
ts->quadCPY = 2 * ts->curPosY - ts->quadCPY;
|
||||
|
||||
PathPoint bez[3] = { {ts->curPosX, ts->curPosY},
|
||||
{ts->quadCPX, ts->quadCPY},
|
||||
{mX, mY} };
|
||||
float dist = CalcBezLength(bez, 3, SplitQuadraticBezier);
|
||||
|
||||
ts->cubicCPX = ts->curPosX = mX;
|
||||
ts->cubicCPY = ts->curPosY = mY;
|
||||
return dist;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGPathSegCurvetoQuadraticSmoothAbs methods:
|
||||
|
||||
|
@ -1969,7 +2271,7 @@ public:
|
|||
|
||||
// nsSVGPathSeg methods:
|
||||
NS_IMETHOD GetValueString(nsAString& aValue);
|
||||
|
||||
virtual float GetLength(nsSVGPathSegTraversalState *ts);
|
||||
virtual PRUint16 GetSegType()
|
||||
{ return nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL; }
|
||||
|
||||
|
@ -2010,6 +2312,23 @@ nsSVGPathSegCurvetoQuadraticSmoothRel::GetValueString(nsAString& aValue)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGPathSegCurvetoQuadraticSmoothRel::GetLength(nsSVGPathSegTraversalState *ts)
|
||||
{
|
||||
ts->quadCPX = ts->curPosX - ts->quadCPX;
|
||||
ts->quadCPY = ts->curPosY - ts->quadCPY;
|
||||
|
||||
PathPoint bez[3] = { {0, 0}, {ts->quadCPX, ts->quadCPY}, {mX, mY} };
|
||||
float dist = CalcBezLength(bez, 3, SplitQuadraticBezier);
|
||||
|
||||
ts->quadCPX += ts->curPosX;
|
||||
ts->quadCPY += ts->curPosY;
|
||||
|
||||
ts->cubicCPX = ts->curPosX += mX;
|
||||
ts->cubicCPY = ts->curPosY += mY;
|
||||
return dist;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGPathSegCurvetoQuadraticSmoothRel methods:
|
||||
|
||||
|
|
|
@ -41,10 +41,22 @@
|
|||
|
||||
#include "nsIDOMSVGPathSeg.h"
|
||||
#include "nsIWeakReference.h"
|
||||
#include "nsSVGUtils.h"
|
||||
#include "nsSVGPathDataParser.h"
|
||||
|
||||
class nsSVGPathSegList;
|
||||
class nsISVGValue;
|
||||
|
||||
struct nsSVGPathSegTraversalState {
|
||||
float curPosX, startPosX, quadCPX, cubicCPX;
|
||||
float curPosY, startPosY, quadCPY, cubicCPY;
|
||||
nsSVGPathSegTraversalState()
|
||||
{
|
||||
curPosX = startPosX = quadCPX = cubicCPX = 0;
|
||||
curPosY = startPosY = quadCPY = cubicCPY = 0;
|
||||
}
|
||||
};
|
||||
|
||||
class nsSVGPathSeg : public nsIDOMSVGPathSeg
|
||||
{
|
||||
public:
|
||||
|
@ -58,6 +70,9 @@ public:
|
|||
NS_DECL_NSIDOMSVGPATHSEG
|
||||
NS_IMETHOD GetValueString(nsAString& aValue) = 0;
|
||||
|
||||
// nsSVGPathSeg methods:
|
||||
virtual float GetLength(nsSVGPathSegTraversalState *ts) = 0;
|
||||
|
||||
protected:
|
||||
virtual PRUint16 GetSegType() = 0;
|
||||
void DidModify();
|
||||
|
|
Загрузка…
Ссылка в новой задаче