mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
Bug 334999 - Compact path storage. r+sr=roc
This commit is contained in:
parent
c659dbc2d9
commit
74c52378a7
@ -167,6 +167,8 @@ EXPORTS = \
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
CFLAGS += $(MOZ_CAIRO_CFLAGS)
|
||||
CXXFLAGS += $(MOZ_CAIRO_CFLAGS)
|
||||
|
||||
INCLUDES += \
|
||||
-I$(srcdir)/../../../shared/public \
|
||||
|
@ -41,6 +41,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
class nsIFrame;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// nsISVGPathFlatten
|
||||
|
||||
|
@ -38,7 +38,11 @@
|
||||
|
||||
#include "nsSVGPathDataParser.h"
|
||||
#include "nsSVGPathSeg.h"
|
||||
#include "nsSVGPathElement.h"
|
||||
#include "prdtoa.h"
|
||||
#include "nsSVGUtils.h"
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// helper macros
|
||||
@ -48,32 +52,28 @@
|
||||
//----------------------------------------------------------------------
|
||||
// public interface
|
||||
|
||||
nsSVGPathDataParser::nsSVGPathDataParser(nsVoidArray* data)
|
||||
: mData(data)
|
||||
{
|
||||
}
|
||||
|
||||
nsresult nsSVGPathDataParser::Parse(const char* str)
|
||||
nsresult
|
||||
nsSVGPathDataParser::Parse(const nsAString &aValue)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
char *str = ToNewCString(aValue);
|
||||
if (!str)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
inputpos = str;
|
||||
getNextToken();
|
||||
rv = matchSvgPath();
|
||||
if (tokentype != END)
|
||||
rv = NS_ERROR_FAILURE; // not all tokens were consumed
|
||||
|
||||
nsMemory::Free(str);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// helpers
|
||||
nsresult nsSVGPathDataParser::AppendSegment(nsIDOMSVGPathSeg* seg)
|
||||
{
|
||||
NS_ADDREF(seg);
|
||||
mData->AppendElement((void*)seg);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
void nsSVGPathDataParser::getNextToken()
|
||||
{
|
||||
@ -314,21 +314,8 @@ nsresult nsSVGPathDataParser::matchMovetoArgSeq(PRBool absCoords)
|
||||
float x, y;
|
||||
ENSURE_MATCHED(matchCoordPair(&x, &y));
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMSVGPathSeg> seg;
|
||||
if (absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegMovetoAbs> segAbs;
|
||||
rv = NS_NewSVGPathSegMovetoAbs(getter_AddRefs(segAbs), x, y);
|
||||
seg = segAbs;
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegMovetoRel> segRel;
|
||||
rv = NS_NewSVGPathSegMovetoRel(getter_AddRefs(segRel), x, y);
|
||||
seg = segRel;
|
||||
}
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = AppendSegment(seg);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
nsresult rv = StoreMoveTo(absCoords, x, y);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
const char* pos = tokenpos;
|
||||
|
||||
@ -359,14 +346,7 @@ nsresult nsSVGPathDataParser::matchClosePath()
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMSVGPathSegClosePath> seg;
|
||||
rv = NS_NewSVGPathSegClosePath(getter_AddRefs(seg));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = AppendSegment(seg);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return NS_OK;
|
||||
return StoreClosePath();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@ -403,22 +383,9 @@ nsresult nsSVGPathDataParser::matchLinetoArgSeq(PRBool absCoords)
|
||||
float x, y;
|
||||
ENSURE_MATCHED(matchCoordPair(&x, &y));
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMSVGPathSeg> seg;
|
||||
if (absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegLinetoAbs> segAbs;
|
||||
rv = NS_NewSVGPathSegLinetoAbs(getter_AddRefs(segAbs), x, y);
|
||||
seg = segAbs;
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegLinetoRel> segRel;
|
||||
rv = NS_NewSVGPathSegLinetoRel(getter_AddRefs(segRel), x, y);
|
||||
seg = segRel;
|
||||
}
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = AppendSegment(seg);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsresult rv = StoreLineTo(absCoords, x, y);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
const char* pos = tokenpos;
|
||||
|
||||
if (isTokenCommaWspStarter()) {
|
||||
@ -473,22 +440,9 @@ nsresult nsSVGPathDataParser::matchHorizontalLinetoArgSeq(PRBool absCoords)
|
||||
float x;
|
||||
ENSURE_MATCHED(matchCoord(&x));
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMSVGPathSeg> seg;
|
||||
if (absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegLinetoHorizontalAbs> segAbs;
|
||||
rv = NS_NewSVGPathSegLinetoHorizontalAbs(getter_AddRefs(segAbs), x);
|
||||
seg = segAbs;
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegLinetoHorizontalRel> segRel;
|
||||
rv = NS_NewSVGPathSegLinetoHorizontalRel(getter_AddRefs(segRel), x);
|
||||
seg = segRel;
|
||||
}
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = AppendSegment(seg);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsresult rv = StoreHLineTo(absCoords, x);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
const char* pos = tokenpos;
|
||||
|
||||
if (isTokenCommaWspStarter()) {
|
||||
@ -538,22 +492,9 @@ nsresult nsSVGPathDataParser::matchVerticalLinetoArgSeq(PRBool absCoords)
|
||||
float y;
|
||||
ENSURE_MATCHED(matchCoord(&y));
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMSVGPathSeg> seg;
|
||||
if (absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegLinetoVerticalAbs> segAbs;
|
||||
rv = NS_NewSVGPathSegLinetoVerticalAbs(getter_AddRefs(segAbs), y);
|
||||
seg = segAbs;
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegLinetoVerticalRel> segRel;
|
||||
rv = NS_NewSVGPathSegLinetoVerticalRel(getter_AddRefs(segRel), y);
|
||||
seg = segRel;
|
||||
}
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = AppendSegment(seg);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsresult rv = StoreVLineTo(absCoords, y);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
const char* pos = tokenpos;
|
||||
|
||||
if (isTokenCommaWspStarter()) {
|
||||
@ -603,22 +544,9 @@ nsresult nsSVGPathDataParser::matchCurvetoArgSeq(PRBool absCoords)
|
||||
while(1) {
|
||||
float x, y, x1, y1, x2, y2;
|
||||
ENSURE_MATCHED(matchCurvetoArg(&x, &y, &x1, &y1, &x2, &y2));
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMSVGPathSeg> seg;
|
||||
if (absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicAbs> segAbs;
|
||||
rv = NS_NewSVGPathSegCurvetoCubicAbs(getter_AddRefs(segAbs), x, y, x1, y1, x2, y2);
|
||||
seg = segAbs;
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicRel> segRel;
|
||||
rv = NS_NewSVGPathSegCurvetoCubicRel(getter_AddRefs(segRel), x, y, x1, y1, x2, y2);
|
||||
seg = segRel;
|
||||
}
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = AppendSegment(seg);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsresult rv = StoreCurveTo(absCoords, x, y, x1, y1, x2, y2);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
const char* pos = tokenpos;
|
||||
|
||||
@ -695,21 +623,8 @@ nsresult nsSVGPathDataParser::matchSmoothCurvetoArgSeq(PRBool absCoords)
|
||||
float x, y, x2, y2;
|
||||
ENSURE_MATCHED(matchSmoothCurvetoArg(&x, &y, &x2, &y2));
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMSVGPathSeg> seg;
|
||||
if (absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicSmoothAbs> segAbs;
|
||||
rv = NS_NewSVGPathSegCurvetoCubicSmoothAbs(getter_AddRefs(segAbs), x, y, x2, y2);
|
||||
seg = segAbs;
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicSmoothRel> segRel;
|
||||
rv = NS_NewSVGPathSegCurvetoCubicSmoothRel(getter_AddRefs(segRel), x, y, x2, y2);
|
||||
seg = segRel;
|
||||
}
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = AppendSegment(seg);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
nsresult rv = StoreSmoothCurveTo(absCoords, x, y, x2, y2);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
const char* pos = tokenpos;
|
||||
|
||||
@ -777,22 +692,9 @@ nsresult nsSVGPathDataParser::matchQuadBezierCurvetoArgSeq(PRBool absCoords)
|
||||
while(1) {
|
||||
float x, y, x1, y1;
|
||||
ENSURE_MATCHED(matchQuadBezierCurvetoArg(&x, &y, &x1, &y1));
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMSVGPathSeg> seg;
|
||||
if (absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticAbs> segAbs;
|
||||
rv = NS_NewSVGPathSegCurvetoQuadraticAbs(getter_AddRefs(segAbs), x, y, x1, y1);
|
||||
seg = segAbs;
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticRel> segRel;
|
||||
rv = NS_NewSVGPathSegCurvetoQuadraticRel(getter_AddRefs(segRel), x, y, x1, y1);
|
||||
seg = segRel;
|
||||
}
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = AppendSegment(seg);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsresult rv = StoreQuadCurveTo(absCoords, x, y, x1, y1);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
const char* pos = tokenpos;
|
||||
|
||||
@ -860,23 +762,10 @@ nsresult nsSVGPathDataParser::matchSmoothQuadBezierCurvetoArgSeq(PRBool absCoord
|
||||
while(1) {
|
||||
float x, y;
|
||||
ENSURE_MATCHED(matchCoordPair(&x, &y));
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMSVGPathSeg> seg;
|
||||
if (absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticSmoothAbs> segAbs;
|
||||
rv = NS_NewSVGPathSegCurvetoQuadraticSmoothAbs(getter_AddRefs(segAbs), x, y);
|
||||
seg = segAbs;
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticSmoothRel> segRel;
|
||||
rv = NS_NewSVGPathSegCurvetoQuadraticSmoothRel(getter_AddRefs(segRel), x, y);
|
||||
seg = segRel;
|
||||
}
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = AppendSegment(seg);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
|
||||
nsresult rv = StoreSmoothQuadCurveTo(absCoords, x, y);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
const char* pos = tokenpos;
|
||||
|
||||
if (isTokenCommaWspStarter()) {
|
||||
@ -920,6 +809,7 @@ nsresult nsSVGPathDataParser::matchEllipticalArc()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult nsSVGPathDataParser::matchEllipticalArcArgSeq(PRBool absCoords)
|
||||
{
|
||||
while(1) {
|
||||
@ -927,24 +817,10 @@ nsresult nsSVGPathDataParser::matchEllipticalArcArgSeq(PRBool absCoords)
|
||||
PRBool largeArcFlag, sweepFlag;
|
||||
|
||||
ENSURE_MATCHED(matchEllipticalArcArg(&x, &y, &r1, &r2, &angle, &largeArcFlag, &sweepFlag));
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMSVGPathSeg> seg;
|
||||
if (absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegArcAbs> segAbs;
|
||||
rv = NS_NewSVGPathSegArcAbs(getter_AddRefs(segAbs), x, y, r1, r2, angle,
|
||||
largeArcFlag, sweepFlag);
|
||||
seg = segAbs;
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegArcRel> segRel;
|
||||
rv = NS_NewSVGPathSegArcRel(getter_AddRefs(segRel), x, y, r1, r2, angle,
|
||||
largeArcFlag, sweepFlag);
|
||||
seg = segRel;
|
||||
}
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = AppendSegment(seg);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsresult rv = StoreEllipticalArc(absCoords, x, y, r1, r2, angle,
|
||||
largeArcFlag, sweepFlag);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
const char* pos = tokenpos;
|
||||
|
||||
@ -1252,3 +1128,673 @@ PRBool nsSVGPathDataParser::isTokenWspStarter()
|
||||
return (tokentype == WSP);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// nsSVGPathDataParserToInternal
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToInternal::Parse(const nsAString &aValue)
|
||||
{
|
||||
mPathData->Clear();
|
||||
mPx = mPy = mCx = mCy = mStartX = mStartY = 0;
|
||||
mNumArguments = mSizeCommandArray = mSizeArgumentArray = 0;
|
||||
mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_UNKNOWN;
|
||||
|
||||
nsresult rv = nsSVGPathDataParser::Parse(aValue);
|
||||
|
||||
PathFini();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToInternal::StoreMoveTo(PRBool absCoords, float x, float y)
|
||||
{
|
||||
if (absCoords) {
|
||||
mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS;
|
||||
} else {
|
||||
x += mPx;
|
||||
y += mPy;
|
||||
mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_MOVETO_REL;
|
||||
}
|
||||
return PathMoveTo(x, y);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToInternal::StoreClosePath()
|
||||
{
|
||||
mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH;
|
||||
|
||||
return PathClose();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToInternal::StoreLineTo(PRBool absCoords, float x, float y)
|
||||
{
|
||||
if (absCoords) {
|
||||
mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_LINETO_ABS;
|
||||
} else {
|
||||
x += mPx;
|
||||
y += mPy;
|
||||
mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_LINETO_REL;
|
||||
}
|
||||
return PathLineTo(x, y);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToInternal::StoreHLineTo(PRBool absCoords, float x)
|
||||
{
|
||||
if (absCoords) {
|
||||
mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_ABS;
|
||||
} else {
|
||||
x += mPx;
|
||||
mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_REL;
|
||||
}
|
||||
return PathLineTo(x, mPy);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToInternal::StoreVLineTo(PRBool absCoords, float y)
|
||||
{
|
||||
if (absCoords) {
|
||||
mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_ABS;
|
||||
} else {
|
||||
y += mPy;
|
||||
mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_REL;
|
||||
}
|
||||
return PathLineTo(mPx, y);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToInternal::StoreCurveTo(PRBool absCoords,
|
||||
float x, float y,
|
||||
float x1, float y1,
|
||||
float x2, float y2)
|
||||
{
|
||||
if (absCoords) {
|
||||
mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS;
|
||||
} else {
|
||||
x += mPx; x1 += mPx; x2 += mPx;
|
||||
y += mPy; y1 += mPy; y2 += mPy;
|
||||
mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL;
|
||||
}
|
||||
mCx = x2;
|
||||
mCy = y2;
|
||||
return PathCurveTo(x1, y1, x2, y2, x, y);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToInternal::StoreSmoothCurveTo(PRBool absCoords,
|
||||
float x, float y,
|
||||
float x2, float y2)
|
||||
{
|
||||
float x1, y1;
|
||||
|
||||
// first controlpoint = reflection last one about current point
|
||||
if (mPrevSeg == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL ||
|
||||
mPrevSeg == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS ||
|
||||
mPrevSeg == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL ||
|
||||
mPrevSeg == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS ) {
|
||||
x1 = 2 * mPx - mCx;
|
||||
y1 = 2 * mPy - mCy;
|
||||
} else {
|
||||
x1 = mPx;
|
||||
y1 = mPy;
|
||||
}
|
||||
if (absCoords) {
|
||||
mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS;
|
||||
} else {
|
||||
x += mPx;
|
||||
x2 += mPx;
|
||||
y += mPy;
|
||||
y2 += mPy;
|
||||
mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL;
|
||||
}
|
||||
mCx = x2;
|
||||
mCy = y2;
|
||||
return PathCurveTo(x1, y1, x2, y2, x, y);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToInternal::StoreQuadCurveTo(PRBool absCoords,
|
||||
float x, float y,
|
||||
float x1, float y1)
|
||||
{
|
||||
if (absCoords) {
|
||||
mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS;
|
||||
} else {
|
||||
x += mPx;
|
||||
x1 += mPx;
|
||||
y += mPy;
|
||||
y1 += mPy;
|
||||
mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL;
|
||||
}
|
||||
|
||||
float x31, y31, x32, y32;
|
||||
// conversion of quadratic bezier curve to cubic bezier curve:
|
||||
x31 = mPx + (x1 - mPx) * 2 / 3;
|
||||
y31 = mPy + (y1 - mPy) * 2 / 3;
|
||||
x32 = x1 + (x - x1) / 3;
|
||||
y32 = y1 + (y - y1) / 3;
|
||||
|
||||
mCx = x1;
|
||||
mCy = y1;
|
||||
return PathCurveTo(x31, y31, x32, y32, x, y);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToInternal::StoreSmoothQuadCurveTo(PRBool absCoords,
|
||||
float x, float y)
|
||||
{
|
||||
float x1, y1;
|
||||
|
||||
// first controlpoint = reflection last one about current point
|
||||
if (mPrevSeg == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL ||
|
||||
mPrevSeg == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS ||
|
||||
mPrevSeg == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL ||
|
||||
mPrevSeg == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS ) {
|
||||
x1 = 2 * mPx - mCx;
|
||||
y1 = 2 * mPy - mCy;
|
||||
} else {
|
||||
x1 = mPx;
|
||||
y1 = mPy;
|
||||
}
|
||||
if (absCoords) {
|
||||
mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS;
|
||||
} else {
|
||||
x += mPx;
|
||||
y += mPy;
|
||||
mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL;
|
||||
}
|
||||
|
||||
float x31, y31, x32, y32;
|
||||
// conversion of quadratic bezier curve to cubic bezier curve:
|
||||
x31 = mPx + (x1 - mPx) * 2 / 3;
|
||||
y31 = mPy + (y1 - mPy) * 2 / 3;
|
||||
x32 = x1 + (x - x1) / 3;
|
||||
y32 = y1 + (y - y1) / 3;
|
||||
|
||||
mCx = x1;
|
||||
mCy = y1;
|
||||
return PathCurveTo(x31, y31, x32, y32, x, y);
|
||||
}
|
||||
|
||||
static double
|
||||
CalcVectorAngle(double ux, double uy, double vx, double vy)
|
||||
{
|
||||
double ta = atan2(uy, ux);
|
||||
double tb = atan2(vy, vx);
|
||||
if (tb >= ta)
|
||||
return tb-ta;
|
||||
return 2 * M_PI - (ta-tb);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToInternal::ConvertArcToCurves(float x2, float y2,
|
||||
float rx, float ry,
|
||||
float angle,
|
||||
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
|
||||
// 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)
|
||||
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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// c) draw the cubic bezier:
|
||||
nsresult rv = PathCurveTo(x1+dx1, y1+dy1, xe+dxe, ye+dye, xe, ye);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// do next segment
|
||||
theta1 = theta2;
|
||||
x1 = (float)xe;
|
||||
y1 = (float)ye;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToInternal::StoreEllipticalArc(PRBool absCoords,
|
||||
float x, float y,
|
||||
float r1, float r2,
|
||||
float angle,
|
||||
PRBool largeArcFlag,
|
||||
PRBool sweepFlag)
|
||||
{
|
||||
if (absCoords) {
|
||||
mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_ARC_ABS;
|
||||
} else {
|
||||
x += mPx;
|
||||
y += mPy;
|
||||
mPrevSeg = nsIDOMSVGPathSeg::PATHSEG_ARC_REL;
|
||||
}
|
||||
return ConvertArcToCurves(x, y, r1, r2, angle, largeArcFlag, sweepFlag);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToInternal::PathEnsureSpace(PRUint32 aNumArgs)
|
||||
{
|
||||
const PRUint32 expansionRatio = 2;
|
||||
|
||||
if (mPathData->mNumCommands + 1 > mSizeCommandArray) {
|
||||
PRUint32 newSize = (mSizeCommandArray + 1) * expansionRatio;
|
||||
PRUint8 *tmp;
|
||||
tmp = (PRUint8*)realloc(mPathData->mCommands, (newSize + 3) / 4);
|
||||
if (!tmp)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
mSizeCommandArray = newSize;
|
||||
mPathData->mCommands = tmp;
|
||||
}
|
||||
|
||||
if (mNumArguments + aNumArgs > mSizeArgumentArray) {
|
||||
PRUint32 newSize = (mSizeArgumentArray + aNumArgs) * expansionRatio;
|
||||
float *tmp;
|
||||
tmp = (float*)realloc(mPathData->mArguments,
|
||||
newSize * sizeof(float));
|
||||
if (!tmp)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
mSizeArgumentArray = newSize;
|
||||
mPathData->mArguments = tmp;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGPathDataParserToInternal::PathAddCommandCode(PRUint8 aCommand)
|
||||
{
|
||||
PRUint32 offset = mPathData->mNumCommands / 4;
|
||||
PRUint32 shift = 2 * (mPathData->mNumCommands % 4);
|
||||
if (shift == 0) {
|
||||
// make sure we set the byte, to avoid false UMR reports
|
||||
mPathData->mCommands[offset] = aCommand;
|
||||
} else {
|
||||
mPathData->mCommands[offset] |= aCommand << shift;
|
||||
}
|
||||
mPathData->mNumCommands++;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToInternal::PathMoveTo(float x, float y)
|
||||
{
|
||||
nsresult rv = PathEnsureSpace(2);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PathAddCommandCode(nsSVGPathList::MOVETO);
|
||||
mPathData->mArguments[mNumArguments++] = x;
|
||||
mPathData->mArguments[mNumArguments++] = y;
|
||||
|
||||
mPx = mStartX = x;
|
||||
mPy = mStartY = y;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToInternal::PathLineTo(float x, float y)
|
||||
{
|
||||
nsresult rv = PathEnsureSpace(2);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PathAddCommandCode(nsSVGPathList::LINETO);
|
||||
mPathData->mArguments[mNumArguments++] = x;
|
||||
mPathData->mArguments[mNumArguments++] = y;
|
||||
|
||||
mPx = x;
|
||||
mPy = y;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToInternal::PathCurveTo(float x1, float y1,
|
||||
float x2, float y2,
|
||||
float x3, float y3)
|
||||
{
|
||||
nsresult rv = PathEnsureSpace(6);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PathAddCommandCode(nsSVGPathList::CURVETO);
|
||||
mPathData->mArguments[mNumArguments++] = x1;
|
||||
mPathData->mArguments[mNumArguments++] = y1;
|
||||
mPathData->mArguments[mNumArguments++] = x2;
|
||||
mPathData->mArguments[mNumArguments++] = y2;
|
||||
mPathData->mArguments[mNumArguments++] = x3;
|
||||
mPathData->mArguments[mNumArguments++] = y3;
|
||||
|
||||
mPx = x3;
|
||||
mPy = y3;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToInternal::PathClose()
|
||||
{
|
||||
nsresult rv = PathEnsureSpace(0);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PathAddCommandCode(nsSVGPathList::CLOSEPATH);
|
||||
|
||||
mPx = mStartX;
|
||||
mPy = mStartY;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGPathDataParserToInternal::PathFini()
|
||||
{
|
||||
if ((mPathData->mNumCommands + 3) / 4 != mSizeCommandArray / 4) {
|
||||
PRUint8 *tmp8;
|
||||
tmp8 = (PRUint8*)realloc(mPathData->mCommands,
|
||||
(mPathData->mNumCommands + 3) / 4);
|
||||
if (tmp8)
|
||||
mPathData->mCommands = tmp8;
|
||||
}
|
||||
|
||||
if (mNumArguments != mSizeCommandArray) {
|
||||
float *tmp32;
|
||||
tmp32 = (float*)realloc(mPathData->mArguments,
|
||||
mNumArguments * sizeof(float));
|
||||
if (tmp32)
|
||||
mPathData->mArguments = tmp32;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// nsSVGPathDataParserToDOM
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToDOM::AppendSegment(nsIDOMSVGPathSeg* seg)
|
||||
{
|
||||
NS_ADDREF(seg);
|
||||
mData->AppendElement((void*)seg);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToDOM::StoreMoveTo(PRBool absCoords, float x, float y)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMSVGPathSeg> seg;
|
||||
if (absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegMovetoAbs> segAbs;
|
||||
rv = NS_NewSVGPathSegMovetoAbs(getter_AddRefs(segAbs), x, y);
|
||||
seg = segAbs;
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegMovetoRel> segRel;
|
||||
rv = NS_NewSVGPathSegMovetoRel(getter_AddRefs(segRel), x, y);
|
||||
seg = segRel;
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return AppendSegment(seg);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToDOM::StoreClosePath()
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMSVGPathSegClosePath> seg;
|
||||
rv = NS_NewSVGPathSegClosePath(getter_AddRefs(seg));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return AppendSegment(seg);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToDOM::StoreLineTo(PRBool absCoords, float x, float y)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMSVGPathSeg> seg;
|
||||
if (absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegLinetoAbs> segAbs;
|
||||
rv = NS_NewSVGPathSegLinetoAbs(getter_AddRefs(segAbs), x, y);
|
||||
seg = segAbs;
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegLinetoRel> segRel;
|
||||
rv = NS_NewSVGPathSegLinetoRel(getter_AddRefs(segRel), x, y);
|
||||
seg = segRel;
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return AppendSegment(seg);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToDOM::StoreHLineTo(PRBool absCoords, float x)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMSVGPathSeg> seg;
|
||||
if (absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegLinetoHorizontalAbs> segAbs;
|
||||
rv = NS_NewSVGPathSegLinetoHorizontalAbs(getter_AddRefs(segAbs), x);
|
||||
seg = segAbs;
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegLinetoHorizontalRel> segRel;
|
||||
rv = NS_NewSVGPathSegLinetoHorizontalRel(getter_AddRefs(segRel), x);
|
||||
seg = segRel;
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return AppendSegment(seg);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToDOM::StoreVLineTo(PRBool absCoords, float y)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMSVGPathSeg> seg;
|
||||
if (absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegLinetoVerticalAbs> segAbs;
|
||||
rv = NS_NewSVGPathSegLinetoVerticalAbs(getter_AddRefs(segAbs), y);
|
||||
seg = segAbs;
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegLinetoVerticalRel> segRel;
|
||||
rv = NS_NewSVGPathSegLinetoVerticalRel(getter_AddRefs(segRel), y);
|
||||
seg = segRel;
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return AppendSegment(seg);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToDOM::StoreCurveTo(PRBool absCoords,
|
||||
float x, float y,
|
||||
float x1, float y1,
|
||||
float x2, float y2)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMSVGPathSeg> seg;
|
||||
if (absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicAbs> segAbs;
|
||||
rv = NS_NewSVGPathSegCurvetoCubicAbs(getter_AddRefs(segAbs), x, y, x1, y1, x2, y2);
|
||||
seg = segAbs;
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicRel> segRel;
|
||||
rv = NS_NewSVGPathSegCurvetoCubicRel(getter_AddRefs(segRel), x, y, x1, y1, x2, y2);
|
||||
seg = segRel;
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return AppendSegment(seg);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToDOM::StoreSmoothCurveTo(PRBool absCoords,
|
||||
float x, float y,
|
||||
float x2, float y2)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMSVGPathSeg> seg;
|
||||
if (absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicSmoothAbs> segAbs;
|
||||
rv = NS_NewSVGPathSegCurvetoCubicSmoothAbs(getter_AddRefs(segAbs), x, y, x2, y2);
|
||||
seg = segAbs;
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicSmoothRel> segRel;
|
||||
rv = NS_NewSVGPathSegCurvetoCubicSmoothRel(getter_AddRefs(segRel), x, y, x2, y2);
|
||||
seg = segRel;
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return AppendSegment(seg);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToDOM::StoreQuadCurveTo(PRBool absCoords,
|
||||
float x, float y,
|
||||
float x1, float y1)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMSVGPathSeg> seg;
|
||||
if (absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticAbs> segAbs;
|
||||
rv = NS_NewSVGPathSegCurvetoQuadraticAbs(getter_AddRefs(segAbs), x, y, x1, y1);
|
||||
seg = segAbs;
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticRel> segRel;
|
||||
rv = NS_NewSVGPathSegCurvetoQuadraticRel(getter_AddRefs(segRel), x, y, x1, y1);
|
||||
seg = segRel;
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return AppendSegment(seg);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToDOM::StoreSmoothQuadCurveTo(PRBool absCoords,
|
||||
float x, float y)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMSVGPathSeg> seg;
|
||||
if (absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticSmoothAbs> segAbs;
|
||||
rv = NS_NewSVGPathSegCurvetoQuadraticSmoothAbs(getter_AddRefs(segAbs), x, y);
|
||||
seg = segAbs;
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticSmoothRel> segRel;
|
||||
rv = NS_NewSVGPathSegCurvetoQuadraticSmoothRel(getter_AddRefs(segRel), x, y);
|
||||
seg = segRel;
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return AppendSegment(seg);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathDataParserToDOM::StoreEllipticalArc(PRBool absCoords,
|
||||
float x, float y,
|
||||
float r1, float r2,
|
||||
float angle,
|
||||
PRBool largeArcFlag,
|
||||
PRBool sweepFlag)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMSVGPathSeg> seg;
|
||||
if (absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegArcAbs> segAbs;
|
||||
rv = NS_NewSVGPathSegArcAbs(getter_AddRefs(segAbs), x, y, r1, r2, angle,
|
||||
largeArcFlag, sweepFlag);
|
||||
seg = segAbs;
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegArcRel> segRel;
|
||||
rv = NS_NewSVGPathSegArcRel(getter_AddRefs(segRel), x, y, r1, r2, angle,
|
||||
largeArcFlag, sweepFlag);
|
||||
seg = segRel;
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return AppendSegment(seg);
|
||||
}
|
||||
|
@ -42,6 +42,9 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsIDOMSVGPathSeg.h"
|
||||
#include <cairo.h>
|
||||
|
||||
class nsSVGPathList;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// nsSVGPathDataParser: a simple recursive descent parser that builds
|
||||
@ -51,21 +54,34 @@
|
||||
class nsSVGPathDataParser
|
||||
{
|
||||
public:
|
||||
nsSVGPathDataParser(nsVoidArray* data);
|
||||
nsresult Parse(const char* str);
|
||||
virtual nsresult Parse(const nsAString &aValue);
|
||||
|
||||
protected:
|
||||
nsVoidArray *mData;
|
||||
|
||||
const char* inputpos;
|
||||
|
||||
char tokenval;
|
||||
const char* tokenpos;
|
||||
enum { DIGIT, WSP, COMMA, POINT, SIGN, OTHER, END } tokentype;
|
||||
|
||||
|
||||
// Path data storage
|
||||
virtual nsresult StoreMoveTo(PRBool absCoords, float x, float y) = 0;
|
||||
virtual nsresult StoreClosePath() = 0;
|
||||
virtual nsresult StoreLineTo(PRBool absCoords, float x, float y) = 0;
|
||||
virtual nsresult StoreHLineTo(PRBool absCoords, float x) = 0;
|
||||
virtual nsresult StoreVLineTo(PRBool absCoords, float y) = 0;
|
||||
virtual nsresult StoreCurveTo(PRBool absCoords, float x, float y,
|
||||
float x1, float y1, float x2, float y2) = 0;
|
||||
virtual nsresult StoreSmoothCurveTo(PRBool absCoords, float x, float y,
|
||||
float x2, float y2) = 0;
|
||||
virtual nsresult StoreQuadCurveTo(PRBool absCoords, float x, float y,
|
||||
float x1, float y1) = 0;
|
||||
virtual nsresult StoreSmoothQuadCurveTo(PRBool absCoords,
|
||||
float x, float y) = 0;
|
||||
virtual nsresult StoreEllipticalArc(PRBool absCoords, float x, float y,
|
||||
float r1, float r2, float angle,
|
||||
PRBool largeArcFlag, PRBool sweepFlag) = 0;
|
||||
|
||||
// helpers
|
||||
nsresult AppendSegment(nsIDOMSVGPathSeg* seg);
|
||||
void getNextToken();
|
||||
void windBack(const char* pos);
|
||||
nsresult match(char tok);
|
||||
@ -158,7 +174,84 @@ protected:
|
||||
|
||||
nsresult matchWsp();
|
||||
PRBool isTokenWspStarter();
|
||||
|
||||
};
|
||||
|
||||
class nsSVGPathDataParserToInternal : public nsSVGPathDataParser
|
||||
{
|
||||
public:
|
||||
nsSVGPathDataParserToInternal(nsSVGPathList *data) : mPathData(data) {}
|
||||
virtual nsresult Parse(const nsAString &aValue);
|
||||
|
||||
protected:
|
||||
virtual nsresult StoreMoveTo(PRBool absCoords, float x, float y);
|
||||
virtual nsresult StoreClosePath();
|
||||
virtual nsresult StoreLineTo(PRBool absCoords, float x, float y);
|
||||
virtual nsresult StoreHLineTo(PRBool absCoords, float x);
|
||||
virtual nsresult StoreVLineTo(PRBool absCoords, float y);
|
||||
virtual nsresult StoreCurveTo(PRBool absCoords, float x, float y,
|
||||
float x1, float y1, float x2, float y2);
|
||||
virtual nsresult StoreSmoothCurveTo(PRBool absCoords, float x, float y,
|
||||
float x2, float y2);
|
||||
virtual nsresult StoreQuadCurveTo(PRBool absCoords, float x, float y,
|
||||
float x1, float y1);
|
||||
virtual nsresult StoreSmoothQuadCurveTo(PRBool absCoords,
|
||||
float x, float y);
|
||||
virtual nsresult StoreEllipticalArc(PRBool absCoords, float x, float y,
|
||||
float r1, float r2, float angle,
|
||||
PRBool largeArcFlag, PRBool sweepFlag);
|
||||
|
||||
private:
|
||||
nsSVGPathList *mPathData;
|
||||
PRUint16 mPrevSeg; // previous segment type for "smooth" segments"
|
||||
float mPx, mPy; // current point
|
||||
float mCx, mCy; // last control point for "smooth" segments
|
||||
float mStartX, mStartY; // start of current subpath, for closepath
|
||||
|
||||
// information used to construct PathList
|
||||
PRUint32 mNumArguments;
|
||||
PRUint32 mSizeCommandArray;
|
||||
PRUint32 mSizeArgumentArray;
|
||||
|
||||
// Pathdata helpers
|
||||
nsresult ConvertArcToCurves(float x2, float y2, float rx, float ry,
|
||||
float angle, PRBool largeArcFlag, PRBool sweepFlag);
|
||||
|
||||
nsresult PathEnsureSpace(PRUint32 aNumArgs);
|
||||
void PathAddCommandCode(PRUint8 aCommand);
|
||||
nsresult PathMoveTo(float x, float y);
|
||||
nsresult PathLineTo(float x, float y);
|
||||
nsresult PathCurveTo(float x1, float y2, float x2, float y2, float x2, float y3);
|
||||
nsresult PathClose();
|
||||
void PathFini();
|
||||
};
|
||||
|
||||
class nsSVGPathDataParserToDOM : public nsSVGPathDataParser
|
||||
{
|
||||
public:
|
||||
nsSVGPathDataParserToDOM(nsVoidArray *data) : mData(data) {}
|
||||
|
||||
protected:
|
||||
virtual nsresult StoreMoveTo(PRBool absCoords, float x, float y);
|
||||
virtual nsresult StoreClosePath();
|
||||
virtual nsresult StoreLineTo(PRBool absCoords, float x, float y);
|
||||
virtual nsresult StoreHLineTo(PRBool absCoords, float x);
|
||||
virtual nsresult StoreVLineTo(PRBool absCoords, float y);
|
||||
virtual nsresult StoreCurveTo(PRBool absCoords, float x, float y,
|
||||
float x1, float y1, float x2, float y2);
|
||||
virtual nsresult StoreSmoothCurveTo(PRBool absCoords, float x, float y,
|
||||
float x2, float y2);
|
||||
virtual nsresult StoreQuadCurveTo(PRBool absCoords, float x, float y,
|
||||
float x1, float y1);
|
||||
virtual nsresult StoreSmoothQuadCurveTo(PRBool absCoords,
|
||||
float x, float y);
|
||||
virtual nsresult StoreEllipticalArc(PRBool absCoords, float x, float y,
|
||||
float r1, float r2, float angle,
|
||||
PRBool largeArcFlag, PRBool sweepFlag);
|
||||
|
||||
private:
|
||||
nsresult AppendSegment(nsIDOMSVGPathSeg* seg);
|
||||
|
||||
nsVoidArray *mData;
|
||||
};
|
||||
|
||||
#endif // __NS_SVGPATHDATAPARSER_H__
|
||||
|
@ -36,57 +36,20 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsSVGGraphicElement.h"
|
||||
#include "nsSVGAtoms.h"
|
||||
#include "nsSVGPathSegList.h"
|
||||
#include "nsIDOMSVGPathElement.h"
|
||||
#include "nsIDOMSVGAnimatedPathData.h"
|
||||
#include "nsIDOMSVGPathSeg.h"
|
||||
#include "nsSVGPathSeg.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsISVGPathFlatten.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIFrame.h"
|
||||
|
||||
typedef nsSVGGraphicElement nsSVGPathElementBase;
|
||||
|
||||
class nsSVGPathElement : public nsSVGPathElementBase,
|
||||
public nsIDOMSVGPathElement,
|
||||
public nsIDOMSVGAnimatedPathData
|
||||
{
|
||||
protected:
|
||||
friend nsresult NS_NewSVGPathElement(nsIContent **aResult,
|
||||
nsINodeInfo *aNodeInfo);
|
||||
nsSVGPathElement(nsINodeInfo *aNodeInfo);
|
||||
virtual ~nsSVGPathElement();
|
||||
nsresult Init();
|
||||
|
||||
public:
|
||||
// interfaces:
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIDOMSVGPATHELEMENT
|
||||
NS_DECL_NSIDOMSVGANIMATEDPATHDATA
|
||||
|
||||
// xxx I wish we could use virtual inheritance
|
||||
NS_FORWARD_NSIDOMNODE_NO_CLONENODE(nsSVGPathElementBase::)
|
||||
NS_FORWARD_NSIDOMELEMENT(nsSVGPathElementBase::)
|
||||
NS_FORWARD_NSIDOMSVGELEMENT(nsSVGPathElementBase::)
|
||||
|
||||
// nsIContent interface
|
||||
NS_IMETHODIMP_(PRBool) IsAttributeMapped(const nsIAtom* name) const;
|
||||
|
||||
protected:
|
||||
|
||||
already_AddRefed<nsISVGPathFlatten> GetPathFlatten();
|
||||
|
||||
nsCOMPtr<nsIDOMSVGPathSegList> mSegments;
|
||||
};
|
||||
|
||||
#include "nsSVGPathDataParser.h"
|
||||
#include "nsSVGPathElement.h"
|
||||
#include "nsISVGValueUtils.h"
|
||||
|
||||
NS_IMPL_NS_NEW_SVG_ELEMENT(Path)
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsISupports methods
|
||||
|
||||
@ -108,38 +71,19 @@ NS_INTERFACE_MAP_END_INHERITING(nsSVGPathElementBase)
|
||||
nsSVGPathElement::nsSVGPathElement(nsINodeInfo* aNodeInfo)
|
||||
: nsSVGPathElementBase(aNodeInfo)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
nsSVGPathElement::~nsSVGPathElement()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsSVGPathElement::Init()
|
||||
{
|
||||
nsresult rv = nsSVGPathElementBase::Init();
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
// Create mapped properties:
|
||||
|
||||
// d #REQUIRED
|
||||
rv = NS_NewSVGPathSegList(getter_AddRefs(mSegments));
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
rv = AddMappedSVGValue(nsSVGAtoms::d, mSegments);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
return rv;
|
||||
if (mSegments)
|
||||
NS_REMOVE_SVGVALUE_OBSERVER(mSegments);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMNode methods
|
||||
|
||||
|
||||
NS_IMPL_DOM_CLONENODE_WITH_INIT(nsSVGPathElement)
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGPathElement methods:
|
||||
|
||||
@ -316,12 +260,32 @@ nsSVGPathElement::CreateSVGPathSegCurvetoQuadraticSmoothRel(float x, float y, ns
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsSVGPathElement::CreatePathSegList()
|
||||
{
|
||||
nsresult rv = NS_NewSVGPathSegList(getter_AddRefs(mSegments));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsISVGValue> value = do_QueryInterface(mSegments);
|
||||
|
||||
nsAutoString d;
|
||||
if (NS_SUCCEEDED(GetAttr(kNameSpaceID_None, nsGkAtoms::d, d)))
|
||||
value->SetValueString(d);
|
||||
|
||||
NS_ADD_SVGVALUE_OBSERVER(mSegments);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIDOMSVGAnimatedPathData methods:
|
||||
|
||||
/* readonly attribute nsIDOMSVGPathSegList pathSegList; */
|
||||
NS_IMETHODIMP nsSVGPathElement::GetPathSegList(nsIDOMSVGPathSegList * *aPathSegList)
|
||||
{
|
||||
nsresult rv = CreatePathSegList();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
*aPathSegList = mSegments;
|
||||
NS_ADDREF(*aPathSegList);
|
||||
return NS_OK;
|
||||
@ -336,6 +300,9 @@ NS_IMETHODIMP nsSVGPathElement::GetNormalizedPathSegList(nsIDOMSVGPathSegList *
|
||||
/* readonly attribute nsIDOMSVGPathSegList animatedPathSegList; */
|
||||
NS_IMETHODIMP nsSVGPathElement::GetAnimatedPathSegList(nsIDOMSVGPathSegList * *aAnimatedPathSegList)
|
||||
{
|
||||
nsresult rv = CreatePathSegList();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
*aAnimatedPathSegList = mSegments;
|
||||
NS_ADDREF(*aAnimatedPathSegList);
|
||||
return NS_OK;
|
||||
@ -361,6 +328,53 @@ nsSVGPathElement::IsAttributeMapped(const nsIAtom* name) const
|
||||
nsSVGPathElementBase::IsAttributeMapped(name);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGPathElement::BeforeSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
|
||||
const nsAString* aValue, PRBool aNotify)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::d) {
|
||||
if (mSegments) {
|
||||
NS_REMOVE_SVGVALUE_OBSERVER(mSegments);
|
||||
mSegments = nsnull;
|
||||
}
|
||||
|
||||
nsSVGPathDataParserToInternal parser(&mPathData);
|
||||
nsresult rv = parser.Parse(*aValue);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return nsSVGPathElementBase::BeforeSetAttr(aNamespaceID, aName,
|
||||
aValue, aNotify);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGPathElement::DidModifySVGObservable(nsISVGValue* observable,
|
||||
nsISVGValue::modificationType aModType)
|
||||
{
|
||||
nsCOMPtr<nsIDOMSVGPathSegList> list = do_QueryInterface(observable);
|
||||
|
||||
if (list && mSegments == list) {
|
||||
nsCOMPtr<nsISVGValue> value = do_QueryInterface(mSegments);
|
||||
nsAutoString d;
|
||||
nsresult rv = value->GetValueString(d);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Want to keep the seglist alive - SetAttr normally invalidates it
|
||||
nsCOMPtr<nsIDOMSVGPathSegList> deathGrip = mSegments;
|
||||
mSegments = nsnull;
|
||||
|
||||
rv = SetAttr(kNameSpaceID_None, nsGkAtoms::d, d, PR_TRUE);
|
||||
|
||||
// Restore seglist
|
||||
mSegments = deathGrip;
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return nsSVGPathElementBase::DidModifySVGObservable(observable, aModType);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// implementation helpers:
|
||||
|
||||
@ -389,3 +403,49 @@ nsSVGPathElement::GetPathFlatten()
|
||||
CallQueryInterface(frame, &flattener);
|
||||
return flattener;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
// nsSVGPathList
|
||||
|
||||
void
|
||||
nsSVGPathList::Clear()
|
||||
{
|
||||
if (mCommands) {
|
||||
free(mCommands);
|
||||
mCommands = nsnull;
|
||||
}
|
||||
if (mArguments) {
|
||||
free(mArguments);
|
||||
mArguments = nsnull;
|
||||
}
|
||||
mNumCommands = 0;
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGPathList::Playback(cairo_t *aCtx)
|
||||
{
|
||||
float *args = mArguments;
|
||||
for (PRUint32 i = 0; i < mNumCommands; i++) {
|
||||
PRUint8 command = (mCommands[i / 4] >> (2 * (i % 4))) & 0x3;
|
||||
switch (command) {
|
||||
case MOVETO:
|
||||
cairo_move_to(aCtx, args[0], args[1]);
|
||||
args += 2;
|
||||
break;
|
||||
case LINETO:
|
||||
cairo_line_to(aCtx, args[0], args[1]);
|
||||
args += 2;
|
||||
break;
|
||||
case CURVETO:
|
||||
cairo_curve_to(aCtx,
|
||||
args[0], args[1], args[2], args[3], args[4], args[5]);
|
||||
args += 6;
|
||||
break;
|
||||
case CLOSEPATH:
|
||||
cairo_close_path(aCtx);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
112
content/svg/content/src/nsSVGPathElement.h
Normal file
112
content/svg/content/src/nsSVGPathElement.h
Normal file
@ -0,0 +1,112 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the Mozilla SVG project.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Crocodile Clips Ltd..
|
||||
* Portions created by the Initial Developer are Copyright (C) 2001
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef __NS_SVGPATHELEMENT_H__
|
||||
#define __NS_SVGPATHELEMENT_H__
|
||||
|
||||
#include "nsSVGGraphicElement.h"
|
||||
#include "nsIDOMSVGPathElement.h"
|
||||
#include "nsIDOMSVGAnimatedPathData.h"
|
||||
#include "nsISVGPathFlatten.h"
|
||||
|
||||
class nsSVGPathList
|
||||
{
|
||||
friend class nsSVGPathDataParserToInternal;
|
||||
|
||||
public:
|
||||
enum { MOVETO, LINETO, CURVETO, CLOSEPATH };
|
||||
nsSVGPathList() : mCommands(nsnull), mArguments(nsnull), mNumCommands(0) {}
|
||||
~nsSVGPathList() { Clear(); }
|
||||
void Playback(cairo_t *aCtx);
|
||||
|
||||
protected:
|
||||
void Clear();
|
||||
|
||||
PRUint8 *mCommands;
|
||||
float *mArguments;
|
||||
PRUint32 mNumCommands;
|
||||
};
|
||||
|
||||
typedef nsSVGGraphicElement nsSVGPathElementBase;
|
||||
|
||||
class nsSVGPathElement : public nsSVGPathElementBase,
|
||||
public nsIDOMSVGPathElement,
|
||||
public nsIDOMSVGAnimatedPathData
|
||||
{
|
||||
friend class nsSVGPathFrame;
|
||||
|
||||
protected:
|
||||
friend nsresult NS_NewSVGPathElement(nsIContent **aResult,
|
||||
nsINodeInfo *aNodeInfo);
|
||||
nsSVGPathElement(nsINodeInfo *aNodeInfo);
|
||||
virtual ~nsSVGPathElement();
|
||||
|
||||
public:
|
||||
// interfaces:
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIDOMSVGPATHELEMENT
|
||||
NS_DECL_NSIDOMSVGANIMATEDPATHDATA
|
||||
|
||||
// xxx I wish we could use virtual inheritance
|
||||
NS_FORWARD_NSIDOMNODE_NO_CLONENODE(nsSVGPathElementBase::)
|
||||
NS_FORWARD_NSIDOMELEMENT(nsSVGPathElementBase::)
|
||||
NS_FORWARD_NSIDOMSVGELEMENT(nsSVGPathElementBase::)
|
||||
|
||||
// nsIContent interface
|
||||
NS_IMETHODIMP_(PRBool) IsAttributeMapped(const nsIAtom* name) const;
|
||||
|
||||
// nsISVGValueObserver
|
||||
NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
|
||||
nsISVGValue::modificationType aModType);
|
||||
|
||||
protected:
|
||||
|
||||
virtual nsresult BeforeSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
|
||||
const nsAString* aValue, PRBool aNotify);
|
||||
|
||||
already_AddRefed<nsISVGPathFlatten> GetPathFlatten();
|
||||
|
||||
// Helper for lazily creating pathseg list
|
||||
nsresult CreatePathSegList();
|
||||
|
||||
nsCOMPtr<nsIDOMSVGPathSegList> mSegments;
|
||||
nsSVGPathList mPathData;
|
||||
};
|
||||
|
||||
#endif
|
@ -129,11 +129,9 @@ nsSVGPathSegList::SetValueString(const nsAString& aValue)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
char *str = ToNewCString(aValue);
|
||||
|
||||
nsVoidArray data;
|
||||
nsSVGPathDataParser parser(&data);
|
||||
rv = parser.Parse(str);
|
||||
nsSVGPathDataParserToDOM parser(&data);
|
||||
rv = parser.Parse(aValue);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
WillModify();
|
||||
@ -157,7 +155,6 @@ nsSVGPathSegList::SetValueString(const nsAString& aValue)
|
||||
}
|
||||
}
|
||||
|
||||
nsMemory::Free(str);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include "nsSVGUtils.h"
|
||||
#include "nsINameSpaceManager.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsSVGPathElement.h"
|
||||
|
||||
class nsSVGPathFrame : public nsSVGPathGeometryFrame,
|
||||
public nsISVGMarkable,
|
||||
@ -58,8 +59,6 @@ protected:
|
||||
friend nsIFrame*
|
||||
NS_NewSVGPathFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsStyleContext* aContext);
|
||||
|
||||
NS_IMETHOD InitSVG();
|
||||
|
||||
public:
|
||||
nsSVGPathFrame(nsStyleContext* aContext) : nsSVGPathGeometryFrame(aContext) {}
|
||||
|
||||
@ -97,8 +96,6 @@ public:
|
||||
private:
|
||||
NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; }
|
||||
NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; }
|
||||
|
||||
nsCOMPtr<nsIDOMSVGPathSegList> mSegments;
|
||||
};
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsSVGPathFrame)
|
||||
@ -123,21 +120,6 @@ NS_NewSVGPathFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsStyleContex
|
||||
return new (aPresShell) nsSVGPathFrame(aContext);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSVGPathFrame::InitSVG()
|
||||
{
|
||||
nsresult rv = nsSVGPathGeometryFrame::InitSVG();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIDOMSVGAnimatedPathData> anim_data = do_QueryInterface(mContent);
|
||||
NS_ASSERTION(anim_data,"wrong content element");
|
||||
anim_data->GetAnimatedPathSegList(getter_AddRefs(mSegments));
|
||||
NS_ASSERTION(mSegments, "no pathseglist");
|
||||
if (!mSegments) return NS_ERROR_FAILURE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsISVGFrame methods:
|
||||
|
||||
@ -169,480 +151,29 @@ CalcVectorAngle(double ux, double uy, double vx, double vy)
|
||||
return 2 * M_PI - (ta-tb);
|
||||
}
|
||||
|
||||
static void
|
||||
ConvertArcToCairo(cairo_t *aCtx, float x, float y, float x2, float y2,
|
||||
float rx, float ry,
|
||||
float angle, PRBool largeArcFlag, PRBool sweepFlag)
|
||||
{
|
||||
const double radPerDeg = M_PI/180.0;
|
||||
|
||||
double x1=x, y1=y;
|
||||
|
||||
// 1. 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)
|
||||
return;
|
||||
|
||||
// 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) {
|
||||
cairo_line_to(aCtx, x2, y2);
|
||||
return;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// c) draw the cubic bezier:
|
||||
cairo_curve_to(aCtx, x1+dx1, y1+dy1, xe+dxe, ye+dye, xe, ye);
|
||||
|
||||
// do next segment
|
||||
theta1 = theta2;
|
||||
x1 = (float)xe;
|
||||
y1 = (float)ye;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsSVGPathFrame::ConstructPath(cairo_t *aCtx)
|
||||
{
|
||||
PRUint32 count;
|
||||
mSegments->GetNumberOfItems(&count);
|
||||
if (count == 0) return NS_OK;
|
||||
|
||||
float cx = 0.0f; // current point
|
||||
float cy = 0.0f;
|
||||
|
||||
float cx1 = 0.0f; // last controlpoint (for s,S,t,T)
|
||||
float cy1 = 0.0f;
|
||||
|
||||
PRUint16 lastSegmentType = nsIDOMSVGPathSeg::PATHSEG_UNKNOWN;
|
||||
|
||||
PRUint32 i;
|
||||
for (i = 0; i < count; ++i) {
|
||||
nsCOMPtr<nsIDOMSVGPathSeg> segment;
|
||||
mSegments->GetItem(i, getter_AddRefs(segment));
|
||||
|
||||
PRUint16 type = nsIDOMSVGPathSeg::PATHSEG_UNKNOWN;
|
||||
segment->GetPathSegType(&type);
|
||||
|
||||
PRBool absCoords = PR_FALSE;
|
||||
|
||||
switch (type) {
|
||||
case nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH:
|
||||
{
|
||||
cairo_close_path(aCtx);
|
||||
double dx, dy;
|
||||
cairo_get_current_point(aCtx, &dx, &dy);
|
||||
cx = (float)dx;
|
||||
cy = (float)dy;
|
||||
}
|
||||
break;
|
||||
|
||||
case nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS:
|
||||
absCoords = PR_TRUE;
|
||||
case nsIDOMSVGPathSeg::PATHSEG_MOVETO_REL:
|
||||
{
|
||||
float x, y;
|
||||
if (!absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegMovetoRel> moveseg = do_QueryInterface(segment);
|
||||
NS_ASSERTION(moveseg, "interface not implemented");
|
||||
moveseg->GetX(&x);
|
||||
moveseg->GetY(&y);
|
||||
x += cx;
|
||||
y += cy;
|
||||
} else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegMovetoAbs> moveseg = do_QueryInterface(segment);
|
||||
NS_ASSERTION(moveseg, "interface not implemented");
|
||||
moveseg->GetX(&x);
|
||||
moveseg->GetY(&y);
|
||||
}
|
||||
cx = x;
|
||||
cy = y;
|
||||
cairo_move_to(aCtx, x, y);
|
||||
}
|
||||
break;
|
||||
|
||||
case nsIDOMSVGPathSeg::PATHSEG_LINETO_ABS:
|
||||
absCoords = PR_TRUE;
|
||||
case nsIDOMSVGPathSeg::PATHSEG_LINETO_REL:
|
||||
{
|
||||
float x, y;
|
||||
if (!absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegLinetoRel> lineseg = do_QueryInterface(segment);
|
||||
NS_ASSERTION(lineseg, "interface not implemented");
|
||||
lineseg->GetX(&x);
|
||||
lineseg->GetY(&y);
|
||||
x += cx;
|
||||
y += cy;
|
||||
} else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegLinetoAbs> lineseg = do_QueryInterface(segment);
|
||||
NS_ASSERTION(lineseg, "interface not implemented");
|
||||
lineseg->GetX(&x);
|
||||
lineseg->GetY(&y);
|
||||
}
|
||||
cx = x;
|
||||
cy = y;
|
||||
cairo_line_to(aCtx, x, y);
|
||||
}
|
||||
break;
|
||||
|
||||
case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS:
|
||||
absCoords = PR_TRUE;
|
||||
case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL:
|
||||
{
|
||||
float x, y, x1, y1, x2, y2;
|
||||
if (!absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicRel> curveseg = do_QueryInterface(segment);
|
||||
NS_ASSERTION(curveseg, "interface not implemented");
|
||||
curveseg->GetX(&x);
|
||||
curveseg->GetY(&y);
|
||||
curveseg->GetX1(&x1);
|
||||
curveseg->GetY1(&y1);
|
||||
curveseg->GetX2(&x2);
|
||||
curveseg->GetY2(&y2);
|
||||
x += cx;
|
||||
y += cy;
|
||||
x1 += cx;
|
||||
y1 += cy;
|
||||
x2 += cx;
|
||||
y2 += cy;
|
||||
} else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicAbs> curveseg = do_QueryInterface(segment);
|
||||
NS_ASSERTION(curveseg, "interface not implemented");
|
||||
curveseg->GetX(&x);
|
||||
curveseg->GetY(&y);
|
||||
curveseg->GetX1(&x1);
|
||||
curveseg->GetY1(&y1);
|
||||
curveseg->GetX2(&x2);
|
||||
curveseg->GetY2(&y2);
|
||||
}
|
||||
cx = x;
|
||||
cy = y;
|
||||
cx1 = x2;
|
||||
cy1 = y2;
|
||||
cairo_curve_to(aCtx, x1, y1, x2, y2, x, y);
|
||||
}
|
||||
break;
|
||||
|
||||
case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS:
|
||||
absCoords = PR_TRUE;
|
||||
case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL:
|
||||
{
|
||||
float x, y, x1, y1, x31, y31, x32, y32;
|
||||
if (!absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticRel> curveseg = do_QueryInterface(segment);
|
||||
NS_ASSERTION(curveseg, "interface not implemented");
|
||||
curveseg->GetX(&x);
|
||||
curveseg->GetY(&y);
|
||||
curveseg->GetX1(&x1);
|
||||
curveseg->GetY1(&y1);
|
||||
x += cx;
|
||||
y += cy;
|
||||
x1 += cx;
|
||||
y1 += cy;
|
||||
} else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticAbs> curveseg = do_QueryInterface(segment);
|
||||
NS_ASSERTION(curveseg, "interface not implemented");
|
||||
curveseg->GetX(&x);
|
||||
curveseg->GetY(&y);
|
||||
curveseg->GetX1(&x1);
|
||||
curveseg->GetY1(&y1);
|
||||
}
|
||||
|
||||
// conversion of quadratic bezier curve to cubic bezier curve:
|
||||
x31 = cx + (x1 - cx) * 2 / 3;
|
||||
y31 = cy + (y1 - cy) * 2 / 3;
|
||||
x32 = x1 + (x - x1) / 3;
|
||||
y32 = y1 + (y - y1) / 3;
|
||||
|
||||
cx = x;
|
||||
cy = y;
|
||||
cx1 = x1;
|
||||
cy1 = y1;
|
||||
|
||||
cairo_curve_to(aCtx, x31, y31, x32, y32, x, y);
|
||||
}
|
||||
break;
|
||||
|
||||
case nsIDOMSVGPathSeg::PATHSEG_ARC_ABS:
|
||||
absCoords = PR_TRUE;
|
||||
case nsIDOMSVGPathSeg::PATHSEG_ARC_REL:
|
||||
{
|
||||
float x0, y0, x, y, r1, r2, angle;
|
||||
PRBool largeArcFlag, sweepFlag;
|
||||
|
||||
x0 = cx;
|
||||
y0 = cy;
|
||||
|
||||
if (!absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegArcRel> arcseg = do_QueryInterface(segment);
|
||||
NS_ASSERTION(arcseg, "interface not implemented");
|
||||
arcseg->GetX(&x);
|
||||
arcseg->GetY(&y);
|
||||
arcseg->GetR1(&r1);
|
||||
arcseg->GetR2(&r2);
|
||||
arcseg->GetAngle(&angle);
|
||||
arcseg->GetLargeArcFlag(&largeArcFlag);
|
||||
arcseg->GetSweepFlag(&sweepFlag);
|
||||
|
||||
x += cx;
|
||||
y += cy;
|
||||
} else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegArcAbs> arcseg = do_QueryInterface(segment);
|
||||
NS_ASSERTION(arcseg, "interface not implemented");
|
||||
arcseg->GetX(&x);
|
||||
arcseg->GetY(&y);
|
||||
arcseg->GetR1(&r1);
|
||||
arcseg->GetR2(&r2);
|
||||
arcseg->GetAngle(&angle);
|
||||
arcseg->GetLargeArcFlag(&largeArcFlag);
|
||||
arcseg->GetSweepFlag(&sweepFlag);
|
||||
}
|
||||
|
||||
ConvertArcToCairo(aCtx, cx, cy, x, y, r1, r2,
|
||||
angle, largeArcFlag, sweepFlag);
|
||||
cx = x;
|
||||
cy = y;
|
||||
}
|
||||
break;
|
||||
|
||||
case nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_ABS:
|
||||
absCoords = PR_TRUE;
|
||||
case nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_REL:
|
||||
{
|
||||
float x;
|
||||
float y = cy;
|
||||
if (!absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegLinetoHorizontalRel> lineseg = do_QueryInterface(segment);
|
||||
NS_ASSERTION(lineseg, "interface not implemented");
|
||||
lineseg->GetX(&x);
|
||||
x += cx;
|
||||
} else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegLinetoHorizontalAbs> lineseg = do_QueryInterface(segment);
|
||||
NS_ASSERTION(lineseg, "interface not implemented");
|
||||
lineseg->GetX(&x);
|
||||
}
|
||||
cx = x;
|
||||
cairo_line_to(aCtx, x, y);
|
||||
}
|
||||
break;
|
||||
|
||||
case nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_ABS:
|
||||
absCoords = PR_TRUE;
|
||||
case nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_REL:
|
||||
{
|
||||
float x = cx;
|
||||
float y;
|
||||
if (!absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegLinetoVerticalRel> lineseg = do_QueryInterface(segment);
|
||||
NS_ASSERTION(lineseg, "interface not implemented");
|
||||
lineseg->GetY(&y);
|
||||
y += cy;
|
||||
} else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegLinetoVerticalAbs> lineseg = do_QueryInterface(segment);
|
||||
NS_ASSERTION(lineseg, "interface not implemented");
|
||||
lineseg->GetY(&y);
|
||||
}
|
||||
cy = y;
|
||||
cairo_line_to(aCtx, x, y);
|
||||
}
|
||||
break;
|
||||
|
||||
case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
|
||||
absCoords = PR_TRUE;
|
||||
case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
|
||||
{
|
||||
float x, y, x1, y1, x2, y2;
|
||||
|
||||
if (lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL ||
|
||||
lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS ||
|
||||
lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL ||
|
||||
lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS ) {
|
||||
// the first controlpoint is the reflection of the last one about the current point:
|
||||
x1 = 2*cx - cx1;
|
||||
y1 = 2*cy - cy1;
|
||||
}
|
||||
else {
|
||||
// the first controlpoint is equal to the current point:
|
||||
x1 = cx;
|
||||
y1 = cy;
|
||||
}
|
||||
|
||||
if (!absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicSmoothRel> curveseg = do_QueryInterface(segment);
|
||||
NS_ASSERTION(curveseg, "interface not implemented");
|
||||
curveseg->GetX(&x);
|
||||
curveseg->GetY(&y);
|
||||
curveseg->GetX2(&x2);
|
||||
curveseg->GetY2(&y2);
|
||||
x += cx;
|
||||
y += cy;
|
||||
x2 += cx;
|
||||
y2 += cy;
|
||||
} else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicSmoothAbs> curveseg = do_QueryInterface(segment);
|
||||
NS_ASSERTION(curveseg, "interface not implemented");
|
||||
curveseg->GetX(&x);
|
||||
curveseg->GetY(&y);
|
||||
curveseg->GetX2(&x2);
|
||||
curveseg->GetY2(&y2);
|
||||
}
|
||||
cx = x;
|
||||
cy = y;
|
||||
cx1 = x2;
|
||||
cy1 = y2;
|
||||
cairo_curve_to(aCtx, x1, y1, x2, y2, x, y);
|
||||
}
|
||||
break;
|
||||
|
||||
case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
|
||||
absCoords = PR_TRUE;
|
||||
case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
|
||||
{
|
||||
float x, y, x1, y1, x31, y31, x32, y32;
|
||||
|
||||
if (lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL ||
|
||||
lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS ||
|
||||
lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL ||
|
||||
lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS ) {
|
||||
// the first controlpoint is the reflection of the last one about the current point:
|
||||
x1 = 2*cx - cx1;
|
||||
y1 = 2*cy - cy1;
|
||||
}
|
||||
else {
|
||||
// the first controlpoint is equal to the current point:
|
||||
x1 = cx;
|
||||
y1 = cy;
|
||||
}
|
||||
|
||||
if (!absCoords) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticSmoothRel> curveseg = do_QueryInterface(segment);
|
||||
NS_ASSERTION(curveseg, "interface not implemented");
|
||||
curveseg->GetX(&x);
|
||||
curveseg->GetY(&y);
|
||||
x += cx;
|
||||
y += cy;
|
||||
} else {
|
||||
nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticSmoothAbs> curveseg = do_QueryInterface(segment);
|
||||
NS_ASSERTION(curveseg, "interface not implemented");
|
||||
curveseg->GetX(&x);
|
||||
curveseg->GetY(&y);
|
||||
}
|
||||
|
||||
// conversion of quadratic bezier curve to cubic bezier curve:
|
||||
x31 = cx + (x1 - cx) * 2 / 3;
|
||||
y31 = cy + (y1 - cy) * 2 / 3;
|
||||
x32 = x1 + (x - x1) / 3;
|
||||
y32 = y1 + (y - y1) / 3;
|
||||
|
||||
cx = x;
|
||||
cy = y;
|
||||
cx1 = x1;
|
||||
cy1 = y1;
|
||||
|
||||
cairo_curve_to(aCtx, x31, y31, x32, y32, x, y);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
NS_ASSERTION(1==0, "unknown path segment");
|
||||
break;
|
||||
}
|
||||
lastSegmentType = type;
|
||||
}
|
||||
nsSVGPathElement *element = NS_STATIC_CAST(nsSVGPathElement*, mContent);
|
||||
element->mPathData.Playback(aCtx);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static float
|
||||
calcAngle(float ux, float uy, float vx, float vy)
|
||||
{
|
||||
float ta = atan2(uy, ux);
|
||||
float tb = atan2(vy, vx);
|
||||
if (tb >= ta)
|
||||
return tb-ta;
|
||||
return 2*M_PI - (ta-tb);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsISVGMarkable methods:
|
||||
|
||||
void
|
||||
nsSVGPathFrame::GetMarkPoints(nsVoidArray *aMarks) {
|
||||
nsCOMPtr<nsIDOMSVGPathSegList> segmentList;
|
||||
|
||||
nsCOMPtr<nsIDOMSVGAnimatedPathData> anim_data = do_QueryInterface(mContent);
|
||||
NS_ASSERTION(anim_data,"wrong content element");
|
||||
anim_data->GetAnimatedPathSegList(getter_AddRefs(segmentList));
|
||||
NS_ASSERTION(segmentList, "no pathseglist");
|
||||
if (!segmentList) return;
|
||||
|
||||
PRUint32 count;
|
||||
mSegments->GetNumberOfItems(&count);
|
||||
segmentList->GetNumberOfItems(&count);
|
||||
nsCOMPtr<nsIDOMSVGPathSeg> segment;
|
||||
|
||||
float cx = 0.0f; // current point
|
||||
@ -663,7 +194,7 @@ nsSVGPathFrame::GetMarkPoints(nsVoidArray *aMarks) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < count; ++i) {
|
||||
nsCOMPtr<nsIDOMSVGPathSeg> segment;
|
||||
mSegments->GetItem(i, getter_AddRefs(segment));
|
||||
segmentList->GetItem(i, getter_AddRefs(segment));
|
||||
|
||||
PRUint16 type = nsIDOMSVGPathSeg::PATHSEG_UNKNOWN;
|
||||
segment->GetPathSegType(&type);
|
||||
@ -871,8 +402,9 @@ nsSVGPathFrame::GetMarkPoints(nsVoidArray *aMarks) {
|
||||
cyp = -root*r2*xp/r1;
|
||||
|
||||
float theta, delta;
|
||||
theta = calcAngle(1.0, 0.0, (xp-cxp)/r1, (yp-cyp)/r2);
|
||||
delta = calcAngle((xp-cxp)/r1, (yp-cyp)/r2, (-xp-cxp)/r1, (-yp-cyp)/r2);
|
||||
theta = CalcVectorAngle(1.0, 0.0, (xp-cxp)/r1, (yp-cyp)/r2);
|
||||
delta = CalcVectorAngle((xp-cxp)/r1, (yp-cyp)/r2,
|
||||
(-xp-cxp)/r1, (-yp-cyp)/r2);
|
||||
if (!sweepFlag && delta > 0)
|
||||
delta -= 2.0*M_PI;
|
||||
else if (sweepFlag && delta < 0)
|
||||
|
Loading…
Reference in New Issue
Block a user