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
00040 #include <math.h>
00041
00042 #include "nsSVGPathGeometryFrame.h"
00043 #include "nsIDOMSVGAnimatedPathData.h"
00044 #include "nsIDOMSVGPathSegList.h"
00045 #include "nsIDOMSVGPathSeg.h"
00046 #include "nsIDOMSVGMatrix.h"
00047 #include "nsISVGRendererPathBuilder.h"
00048
00049 class nsSVGPathFrame : public nsSVGPathGeometryFrame
00050 {
00051 protected:
00052 friend nsresult
00053 NS_NewSVGPathFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame** aNewFrame);
00054
00055 ~nsSVGPathFrame();
00056 virtual nsresult Init();
00057
00058 public:
00059
00060 NS_IMETHOD DidModifySVGObservable(nsISVGValue* observable);
00061
00062
00063 NS_IMETHOD ConstructPath(nsISVGRendererPathBuilder *pathBuilder);
00064
00065 private:
00066 nsCOMPtr<nsIDOMSVGPathSegList> mSegments;
00067 };
00068
00069
00070
00071
00072 nsresult
00073 NS_NewSVGPathFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame** aNewFrame)
00074 {
00075 *aNewFrame = nsnull;
00076
00077 nsCOMPtr<nsIDOMSVGAnimatedPathData> anim_data = do_QueryInterface(aContent);
00078 if (!anim_data) {
00079 #ifdef DEBUG
00080 printf("warning: trying to construct an SVGPathFrame for a content element that doesn't support the right interfaces\n");
00081 #endif
00082 return NS_ERROR_FAILURE;
00083 }
00084
00085 nsSVGPathFrame* it = new (aPresShell) nsSVGPathFrame;
00086 if (nsnull == it)
00087 return NS_ERROR_OUT_OF_MEMORY;
00088
00089 *aNewFrame = it;
00090 return NS_OK;
00091 }
00092
00093 nsSVGPathFrame::~nsSVGPathFrame()
00094 {
00095 nsCOMPtr<nsISVGValue> value;
00096 if (mSegments && (value = do_QueryInterface(mSegments)))
00097 value->RemoveObserver(this);
00098 }
00099
00100 nsresult nsSVGPathFrame::Init()
00101 {
00102 nsresult rv = nsSVGPathGeometryFrame::Init();
00103 if (NS_FAILED(rv)) return rv;
00104
00105 nsCOMPtr<nsIDOMSVGAnimatedPathData> anim_data = do_QueryInterface(mContent);
00106 NS_ASSERTION(anim_data,"wrong content element");
00107 anim_data->GetAnimatedPathSegList(getter_AddRefs(mSegments));
00108 NS_ASSERTION(mSegments, "no pathseglist");
00109 if (!mSegments) return NS_ERROR_FAILURE;
00110 nsCOMPtr<nsISVGValue> value = do_QueryInterface(mSegments);
00111 if (value)
00112 value->AddObserver(this);
00113
00114 return NS_OK;
00115 }
00116
00117
00118
00119
00120 NS_IMETHODIMP
00121 nsSVGPathFrame::DidModifySVGObservable(nsISVGValue* observable)
00122 {
00123 nsCOMPtr<nsIDOMSVGPathSegList> l = do_QueryInterface(observable);
00124 if (l && mSegments==l) {
00125 UpdateGraphic(nsISVGPathGeometrySource::UPDATEMASK_PATH);
00126 return NS_OK;
00127 }
00128
00129 return nsSVGPathGeometryFrame::DidModifySVGObservable(observable);
00130 }
00131
00132
00133
00134
00135
00136 NS_IMETHODIMP nsSVGPathFrame::ConstructPath(nsISVGRendererPathBuilder* pathBuilder)
00137 {
00138 PRUint32 count;
00139 mSegments->GetNumberOfItems(&count);
00140 if (count == 0) return NS_OK;
00141
00142 float cx = 0.0f;
00143 float cy = 0.0f;
00144
00145 float cx1 = 0.0f;
00146 float cy1 = 0.0f;
00147
00148 PRUint16 lastSegmentType = nsIDOMSVGPathSeg::PATHSEG_UNKNOWN;
00149
00150 PRUint32 i;
00151 for (i = 0; i < count; ++i) {
00152 nsCOMPtr<nsIDOMSVGPathSeg> segment;
00153 mSegments->GetItem(i, getter_AddRefs(segment));
00154
00155 PRUint16 type = nsIDOMSVGPathSeg::PATHSEG_UNKNOWN;
00156 segment->GetPathSegType(&type);
00157
00158 PRBool absCoords = PR_FALSE;
00159
00160 switch (type) {
00161 case nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH:
00162 pathBuilder->ClosePath(&cx,&cy);
00163 break;
00164
00165 case nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS:
00166 absCoords = PR_TRUE;
00167 case nsIDOMSVGPathSeg::PATHSEG_MOVETO_REL:
00168 {
00169 float x, y;
00170 if (!absCoords) {
00171 nsCOMPtr<nsIDOMSVGPathSegMovetoRel> moveseg = do_QueryInterface(segment);
00172 NS_ASSERTION(moveseg, "interface not implemented");
00173 moveseg->GetX(&x);
00174 moveseg->GetY(&y);
00175 x += cx;
00176 y += cy;
00177 } else {
00178 nsCOMPtr<nsIDOMSVGPathSegMovetoAbs> moveseg = do_QueryInterface(segment);
00179 NS_ASSERTION(moveseg, "interface not implemented");
00180 moveseg->GetX(&x);
00181 moveseg->GetY(&y);
00182 }
00183 cx = x;
00184 cy = y;
00185 pathBuilder->Moveto(x,y);
00186 }
00187 break;
00188
00189 case nsIDOMSVGPathSeg::PATHSEG_LINETO_ABS:
00190 absCoords = PR_TRUE;
00191 case nsIDOMSVGPathSeg::PATHSEG_LINETO_REL:
00192 {
00193 float x, y;
00194 if (!absCoords) {
00195 nsCOMPtr<nsIDOMSVGPathSegLinetoRel> lineseg = do_QueryInterface(segment);
00196 NS_ASSERTION(lineseg, "interface not implemented");
00197 lineseg->GetX(&x);
00198 lineseg->GetY(&y);
00199 x += cx;
00200 y += cy;
00201 } else {
00202 nsCOMPtr<nsIDOMSVGPathSegLinetoAbs> lineseg = do_QueryInterface(segment);
00203 NS_ASSERTION(lineseg, "interface not implemented");
00204 lineseg->GetX(&x);
00205 lineseg->GetY(&y);
00206 }
00207 cx = x;
00208 cy = y;
00209 pathBuilder->Lineto(x,y);
00210 }
00211 break;
00212
00213 case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS:
00214 absCoords = PR_TRUE;
00215 case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL:
00216 {
00217 float x, y, x1, y1, x2, y2;
00218 if (!absCoords) {
00219 nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicRel> curveseg = do_QueryInterface(segment);
00220 NS_ASSERTION(curveseg, "interface not implemented");
00221 curveseg->GetX(&x);
00222 curveseg->GetY(&y);
00223 curveseg->GetX1(&x1);
00224 curveseg->GetY1(&y1);
00225 curveseg->GetX2(&x2);
00226 curveseg->GetY2(&y2);
00227 x += cx;
00228 y += cy;
00229 x1 += cx;
00230 y1 += cy;
00231 x2 += cx;
00232 y2 += cy;
00233 } else {
00234 nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicAbs> curveseg = do_QueryInterface(segment);
00235 NS_ASSERTION(curveseg, "interface not implemented");
00236 curveseg->GetX(&x);
00237 curveseg->GetY(&y);
00238 curveseg->GetX1(&x1);
00239 curveseg->GetY1(&y1);
00240 curveseg->GetX2(&x2);
00241 curveseg->GetY2(&y2);
00242 }
00243 cx = x;
00244 cy = y;
00245 cx1 = x2;
00246 cy1 = y2;
00247 pathBuilder->Curveto(x, y, x1, y1, x2, y2);
00248 }
00249 break;
00250
00251 case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS:
00252 absCoords = PR_TRUE;
00253 case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL:
00254 {
00255 float x, y, x1, y1, x31, y31, x32, y32;
00256 if (!absCoords) {
00257 nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticRel> curveseg = do_QueryInterface(segment);
00258 NS_ASSERTION(curveseg, "interface not implemented");
00259 curveseg->GetX(&x);
00260 curveseg->GetY(&y);
00261 curveseg->GetX1(&x1);
00262 curveseg->GetY1(&y1);
00263 x += cx;
00264 y += cy;
00265 x1 += cx;
00266 y1 += cy;
00267 } else {
00268 nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticAbs> curveseg = do_QueryInterface(segment);
00269 NS_ASSERTION(curveseg, "interface not implemented");
00270 curveseg->GetX(&x);
00271 curveseg->GetY(&y);
00272 curveseg->GetX1(&x1);
00273 curveseg->GetY1(&y1);
00274 }
00275
00276
00277 x31 = cx + (x1 - cx) * 2 / 3;
00278 y31 = cy + (y1 - cy) * 2 / 3;
00279 x32 = x1 + (x - x1) / 3;
00280 y32 = y1 + (y - y1) / 3;
00281
00282 cx = x;
00283 cy = y;
00284 cx1 = x1;
00285 cy1 = y1;
00286
00287 pathBuilder->Curveto(x, y, x31, y31, x32, y32);
00288 }
00289 break;
00290
00291 case nsIDOMSVGPathSeg::PATHSEG_ARC_ABS:
00292 absCoords = PR_TRUE;
00293 case nsIDOMSVGPathSeg::PATHSEG_ARC_REL:
00294 {
00295 float x0, y0, x, y, r1, r2, angle;
00296 PRBool largeArcFlag, sweepFlag;
00297
00298 x0 = cx;
00299 y0 = cy;
00300
00301 if (!absCoords) {
00302 nsCOMPtr<nsIDOMSVGPathSegArcRel> arcseg = do_QueryInterface(segment);
00303 NS_ASSERTION(arcseg, "interface not implemented");
00304 arcseg->GetX(&x);
00305 arcseg->GetY(&y);
00306 arcseg->GetR1(&r1);
00307 arcseg->GetR2(&r2);
00308 arcseg->GetAngle(&angle);
00309 arcseg->GetLargeArcFlag(&largeArcFlag);
00310 arcseg->GetSweepFlag(&sweepFlag);
00311
00312 x += cx;
00313 y += cy;
00314 } else {
00315 nsCOMPtr<nsIDOMSVGPathSegArcAbs> arcseg = do_QueryInterface(segment);
00316 NS_ASSERTION(arcseg, "interface not implemented");
00317 arcseg->GetX(&x);
00318 arcseg->GetY(&y);
00319 arcseg->GetR1(&r1);
00320 arcseg->GetR2(&r2);
00321 arcseg->GetAngle(&angle);
00322 arcseg->GetLargeArcFlag(&largeArcFlag);
00323 arcseg->GetSweepFlag(&sweepFlag);
00324 }
00325 cx = x;
00326 cy = y;
00327
00328 pathBuilder->Arcto(x, y, r1, r2, angle, largeArcFlag, sweepFlag);
00329 }
00330 break;
00331
00332 case nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_ABS:
00333 absCoords = PR_TRUE;
00334 case nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_REL:
00335 {
00336 float x;
00337 float y = cy;
00338 if (!absCoords) {
00339 nsCOMPtr<nsIDOMSVGPathSegLinetoHorizontalRel> lineseg = do_QueryInterface(segment);
00340 NS_ASSERTION(lineseg, "interface not implemented");
00341 lineseg->GetX(&x);
00342 x += cx;
00343 } else {
00344 nsCOMPtr<nsIDOMSVGPathSegLinetoHorizontalAbs> lineseg = do_QueryInterface(segment);
00345 NS_ASSERTION(lineseg, "interface not implemented");
00346 lineseg->GetX(&x);
00347 }
00348 cx = x;
00349 pathBuilder->Lineto(x,y);
00350 }
00351 break;
00352
00353 case nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_ABS:
00354 absCoords = PR_TRUE;
00355 case nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_REL:
00356 {
00357 float x = cx;
00358 float y;
00359 if (!absCoords) {
00360 nsCOMPtr<nsIDOMSVGPathSegLinetoVerticalRel> lineseg = do_QueryInterface(segment);
00361 NS_ASSERTION(lineseg, "interface not implemented");
00362 lineseg->GetY(&y);
00363 y += cy;
00364 } else {
00365 nsCOMPtr<nsIDOMSVGPathSegLinetoVerticalAbs> lineseg = do_QueryInterface(segment);
00366 NS_ASSERTION(lineseg, "interface not implemented");
00367 lineseg->GetY(&y);
00368 }
00369 cy = y;
00370 pathBuilder->Lineto(x,y);
00371 }
00372 break;
00373
00374 case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
00375 absCoords = PR_TRUE;
00376 case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
00377 {
00378 float x, y, x1, y1, x2, y2;
00379
00380 if (lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL ||
00381 lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS ||
00382 lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL ||
00383 lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS ) {
00384
00385 x1 = 2*cx - cx1;
00386 y1 = 2*cy - cy1;
00387 }
00388 else {
00389
00390 x1 = cx;
00391 y1 = cy;
00392 }
00393
00394 if (!absCoords) {
00395 nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicSmoothRel> curveseg = do_QueryInterface(segment);
00396 NS_ASSERTION(curveseg, "interface not implemented");
00397 curveseg->GetX(&x);
00398 curveseg->GetY(&y);
00399 curveseg->GetX2(&x2);
00400 curveseg->GetY2(&y2);
00401 x += cx;
00402 y += cy;
00403 x2 += cx;
00404 y2 += cy;
00405 } else {
00406 nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicSmoothAbs> curveseg = do_QueryInterface(segment);
00407 NS_ASSERTION(curveseg, "interface not implemented");
00408 curveseg->GetX(&x);
00409 curveseg->GetY(&y);
00410 curveseg->GetX2(&x2);
00411 curveseg->GetY2(&y2);
00412 }
00413 cx = x;
00414 cy = y;
00415 cx1 = x2;
00416 cy1 = y2;
00417 pathBuilder->Curveto(x, y, x1, y1, x2, y2);
00418 }
00419 break;
00420
00421 case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
00422 absCoords = PR_TRUE;
00423 case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
00424 {
00425 float x, y, x1, y1, x31, y31, x32, y32;
00426
00427 if (lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL ||
00428 lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS ||
00429 lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL ||
00430 lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS ) {
00431
00432 x1 = 2*cx - cx1;
00433 y1 = 2*cy - cy1;
00434 }
00435 else {
00436
00437 x1 = cx;
00438 y1 = cy;
00439 }
00440
00441 if (!absCoords) {
00442 nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticSmoothRel> curveseg = do_QueryInterface(segment);
00443 NS_ASSERTION(curveseg, "interface not implemented");
00444 curveseg->GetX(&x);
00445 curveseg->GetY(&y);
00446 x += cx;
00447 y += cy;
00448 } else {
00449 nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticSmoothAbs> curveseg = do_QueryInterface(segment);
00450 NS_ASSERTION(curveseg, "interface not implemented");
00451 curveseg->GetX(&x);
00452 curveseg->GetY(&y);
00453 }
00454
00455
00456 x31 = cx + (x1 - cx) * 2 / 3;
00457 y31 = cy + (y1 - cy) * 2 / 3;
00458 x32 = x1 + (x - x1) / 3;
00459 y32 = y1 + (y - y1) / 3;
00460
00461 cx = x;
00462 cy = y;
00463 cx1 = x1;
00464 cy1 = y1;
00465
00466 pathBuilder->Curveto(x, y, x31, y31, x32, y32);
00467 }
00468 break;
00469
00470 default:
00471 NS_ASSERTION(1==0, "unknown path segment");
00472 break;
00473 }
00474 lastSegmentType = type;
00475 }
00476
00477 return NS_OK;
00478 }