00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include "nsCOMPtr.h"
00040 #include "nsISVGRendererPathBuilder.h"
00041 #include "nsSVGLibartBPathBuilder.h"
00042 #include <math.h>
00043
00044
00049
00050
00053 class nsSVGLibartBPathBuilder : public nsISVGRendererPathBuilder
00054 {
00055 protected:
00056 friend nsresult NS_NewSVGLibartBPathBuilder(nsISVGRendererPathBuilder **result,
00057 ArtBpath** dest);
00058
00059 nsSVGLibartBPathBuilder(ArtBpath** dest);
00060
00061 public:
00062
00063 NS_DECL_ISUPPORTS
00064
00065
00066 NS_DECL_NSISVGRENDERERPATHBUILDER
00067
00068 private:
00069
00070 void EnsureBPathSpace(PRUint32 space=1);
00071 void EnsureBPathTerminated();
00072 PRInt32 GetLastOpenBPath();
00073
00074 ArtBpath** mBPath;
00075 PRUint32 mBPathSize;
00076 PRUint32 mBPathEnd;
00077 };
00078
00081
00082
00083
00084 nsSVGLibartBPathBuilder::nsSVGLibartBPathBuilder(ArtBpath** dest)
00085 : mBPath(dest),
00086 mBPathSize(0),
00087 mBPathEnd(0)
00088 {
00089 }
00090
00091 nsresult
00092 NS_NewSVGLibartBPathBuilder(nsISVGRendererPathBuilder **result,
00093 ArtBpath** dest)
00094 {
00095 *result = new nsSVGLibartBPathBuilder(dest);
00096 if (!result) return NS_ERROR_OUT_OF_MEMORY;
00097
00098 NS_ADDREF(*result);
00099
00100 return NS_OK;
00101 }
00102
00103
00104
00105
00106 NS_IMPL_ADDREF(nsSVGLibartBPathBuilder)
00107 NS_IMPL_RELEASE(nsSVGLibartBPathBuilder)
00108
00109 NS_INTERFACE_MAP_BEGIN(nsSVGLibartBPathBuilder)
00110 NS_INTERFACE_MAP_ENTRY(nsISVGRendererPathBuilder)
00111 NS_INTERFACE_MAP_ENTRY(nsISupports)
00112 NS_INTERFACE_MAP_END
00113
00114
00115
00116
00118 NS_IMETHODIMP
00119 nsSVGLibartBPathBuilder::Moveto(float x, float y)
00120 {
00121 EnsureBPathSpace();
00122
00123 (*mBPath)[mBPathEnd].code = ART_MOVETO_OPEN;
00124 (*mBPath)[mBPathEnd].x3 = x;
00125 (*mBPath)[mBPathEnd].y3 = y;
00126
00127 ++mBPathEnd;
00128
00129 return NS_OK;
00130 }
00131
00133 NS_IMETHODIMP
00134 nsSVGLibartBPathBuilder::Lineto(float x, float y)
00135 {
00136 EnsureBPathSpace();
00137
00138 (*mBPath)[mBPathEnd].code = ART_LINETO;
00139 (*mBPath)[mBPathEnd].x3 = x;
00140 (*mBPath)[mBPathEnd].y3 = y;
00141
00142 ++mBPathEnd;
00143
00144 return NS_OK;
00145 }
00146
00148 NS_IMETHODIMP
00149 nsSVGLibartBPathBuilder::Curveto(float x, float y, float x1, float y1, float x2, float y2)
00150 {
00151 EnsureBPathSpace();
00152
00153 (*mBPath)[mBPathEnd].code = ART_CURVETO;
00154 (*mBPath)[mBPathEnd].x1 = x1;
00155 (*mBPath)[mBPathEnd].y1 = y1;
00156 (*mBPath)[mBPathEnd].x2 = x2;
00157 (*mBPath)[mBPathEnd].y2 = y2;
00158 (*mBPath)[mBPathEnd].x3 = x;
00159 (*mBPath)[mBPathEnd].y3 = y;
00160
00161 ++mBPathEnd;
00162
00163 return NS_OK;
00164 }
00165
00166
00167 static inline double CalcVectorAngle(double ux, double uy, double vx, double vy)
00168 {
00169 double ta = atan2(uy, ux);
00170 double tb = atan2(vy, vx);
00171 if (tb >= ta)
00172 return tb-ta;
00173 return 6.28318530718 - (ta-tb);
00174 }
00175
00176
00178 NS_IMETHODIMP
00179 nsSVGLibartBPathBuilder::Arcto(float x2, float y2, float rx, float ry, float angle, PRBool largeArcFlag, PRBool sweepFlag)
00180 {
00181 const double pi = 3.14159265359;
00182 const double radPerDeg = pi/180.0;
00183
00184 float x1=0.0f, y1=0.0f;
00185 NS_ASSERTION(mBPathEnd > 0, "Arcto needs a start position");
00186 if (mBPathEnd > 0) {
00187 x1 = (float)((*mBPath)[mBPathEnd-1].x3);
00188 y1 = (float)((*mBPath)[mBPathEnd-1].y3);
00189 }
00190
00191
00192
00193
00194
00195
00196 if (x1 == x2 && y1 == y2) return NS_OK;
00197
00198
00199
00200 if (rx == 0.0f || ry == 0.0f) {
00201 Lineto(x2, y2);
00202 return NS_OK;
00203 }
00204
00205
00206
00207 if (rx<0.0) rx = -rx;
00208 if (ry<0.0) ry = -ry;
00209
00210
00211
00212 double sinPhi = sin(angle*radPerDeg);
00213 double cosPhi = cos(angle*radPerDeg);
00214
00215 double x1dash = cosPhi * (x1-x2)/2.0 + sinPhi * (y1-y2)/2.0;
00216 double y1dash = -sinPhi * (x1-x2)/2.0 + cosPhi * (y1-y2)/2.0;
00217
00218 double root;
00219 double numerator = rx*rx*ry*ry - rx*rx*y1dash*y1dash - ry*ry*x1dash*x1dash;
00220
00221 if (numerator < 0.0) {
00222
00223
00224
00225
00226
00227
00228
00229 float s = (float)sqrt(1.0 - numerator/(rx*rx*ry*ry));
00230
00231 rx *= s;
00232 ry *= s;
00233 root = 0.0;
00234
00235 }
00236 else {
00237 root = (largeArcFlag == sweepFlag ? -1.0 : 1.0) *
00238 sqrt( numerator/(rx*rx*y1dash*y1dash+ry*ry*x1dash*x1dash) );
00239 }
00240
00241 double cxdash = root*rx*y1dash/ry;
00242 double cydash = -root*ry*x1dash/rx;
00243
00244 double cx = cosPhi * cxdash - sinPhi * cydash + (x1+x2)/2.0;
00245 double cy = sinPhi * cxdash + cosPhi * cydash + (y1+y2)/2.0;
00246 double theta1 = CalcVectorAngle(1.0, 0.0, (x1dash-cxdash)/rx, (y1dash-cydash)/ry);
00247 double dtheta = CalcVectorAngle((x1dash-cxdash)/rx, (y1dash-cydash)/ry,
00248 (-x1dash-cxdash)/rx, (-y1dash-cydash)/ry);
00249 if (!sweepFlag && dtheta>0)
00250 dtheta -= 2.0*pi;
00251 else if (sweepFlag && dtheta<0)
00252 dtheta += 2.0*pi;
00253
00254
00255 int segments = (int)ceil(fabs(dtheta/(pi/2.0)));
00256 double delta = dtheta/segments;
00257 double t = 8.0/3.0 * sin(delta/4.0) * sin(delta/4.0) / sin(delta/2.0);
00258
00259 for (int i = 0; i < segments; ++i) {
00260 double cosTheta1 = cos(theta1);
00261 double sinTheta1 = sin(theta1);
00262 double theta2 = theta1 + delta;
00263 double cosTheta2 = cos(theta2);
00264 double sinTheta2 = sin(theta2);
00265
00266
00267 double xe = cosPhi * rx*cosTheta2 - sinPhi * ry*sinTheta2 + cx;
00268 double ye = sinPhi * rx*cosTheta2 + cosPhi * ry*sinTheta2 + cy;
00269
00270
00271 double dx1 = t * ( - cosPhi * rx*sinTheta1 - sinPhi * ry*cosTheta1);
00272 double dy1 = t * ( - sinPhi * rx*sinTheta1 + cosPhi * ry*cosTheta1);
00273
00274 double dxe = t * ( cosPhi * rx*sinTheta2 + sinPhi * ry*cosTheta2);
00275 double dye = t * ( sinPhi * rx*sinTheta2 - cosPhi * ry*cosTheta2);
00276
00277
00278 Curveto((float)xe, (float)ye, (float)(x1+dx1), (float)(y1+dy1),
00279 (float)(xe+dxe), (float)(ye+dye));
00280
00281
00282 theta1 = theta2;
00283 x1 = (float)xe;
00284 y1 = (float)ye;
00285 }
00286
00287 return NS_OK;
00288 }
00289
00291 NS_IMETHODIMP
00292 nsSVGLibartBPathBuilder::ClosePath(float *newX, float *newY)
00293 {
00294 PRInt32 subpath = GetLastOpenBPath();
00295 NS_ASSERTION(subpath>=0, "no open subpath");
00296 if (subpath<0) return NS_OK;
00297
00298
00299 if ((*mBPath)[subpath].x3 != (*mBPath)[mBPathEnd-1].x3 ||
00300 (*mBPath)[subpath].y3 != (*mBPath)[mBPathEnd-1].y3) {
00301 Lineto((float)(*mBPath)[subpath].x3, (float)(*mBPath)[subpath].y3);
00302 }
00303
00304 (*mBPath)[subpath].code = ART_MOVETO;
00305
00306 *newX = (float)((*mBPath)[subpath].x3);
00307 *newY = (float)((*mBPath)[subpath].y3);
00308
00309 return NS_OK;
00310 }
00311
00313 NS_IMETHODIMP
00314 nsSVGLibartBPathBuilder::EndPath()
00315 {
00316 EnsureBPathTerminated();
00317 return NS_OK;
00318 }
00319
00320
00321
00322
00323 void
00324 nsSVGLibartBPathBuilder::EnsureBPathSpace(PRUint32 space)
00325 {
00326 const PRInt32 minGrowSize = 10;
00327
00328 if (mBPathSize - mBPathEnd >= space)
00329 return;
00330
00331 if (space < minGrowSize)
00332 space = minGrowSize;
00333
00334 mBPathSize += space;
00335
00336 if (!*mBPath) {
00337 *mBPath = art_new(ArtBpath, mBPathSize);
00338 }
00339 else {
00340 *mBPath = art_renew(*mBPath, ArtBpath, mBPathSize);
00341 }
00342 }
00343
00344 void
00345 nsSVGLibartBPathBuilder::EnsureBPathTerminated()
00346 {
00347 NS_ASSERTION (*mBPath, "no bpath");
00348 NS_ASSERTION (mBPathEnd>0, "trying to terminate empty bpath");
00349
00350 if (mBPathEnd>0 && (*mBPath)[mBPathEnd-1].code == ART_END) return;
00351
00352 EnsureBPathSpace(1);
00353 (*mBPath)[mBPathEnd++].code = ART_END;
00354 }
00355
00356 PRInt32
00357 nsSVGLibartBPathBuilder::GetLastOpenBPath()
00358 {
00359 if (!*mBPath) return -1;
00360
00361 PRInt32 i = mBPathEnd;
00362 while (--i >= 0) {
00363 if ((*mBPath)[i].code == ART_MOVETO_OPEN)
00364 return i;
00365 }
00366 return -1;
00367 }
00368