Back to index

lightning-sunbird  0.9+nobinonly
nsSVGPathDataParser.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Mozilla SVG project.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Crocodile Clips Ltd..
00019  * Portions created by the Initial Developer are Copyright (C) 2001
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsSVGPathDataParser.h"
00040 #include "nsSVGPathSeg.h"
00041 #include "prdtoa.h"
00042 
00043 //----------------------------------------------------------------------
00044 // helper macros
00045 #define ENSURE_MATCHED(exp) { nsresult rv = exp; if (NS_FAILED(rv)) return rv; }
00046 
00047 
00048 //----------------------------------------------------------------------
00049 // public interface
00050 
00051 nsSVGPathDataParser::nsSVGPathDataParser(nsVoidArray* data)
00052     : mData(data)
00053 {
00054 }
00055 
00056 nsresult nsSVGPathDataParser::Parse(const char* str)
00057 {
00058   nsresult rv = NS_OK;
00059   inputpos = str;
00060   getNextToken();
00061   rv = matchSvgPath();
00062   if (tokentype != END)
00063     rv = NS_ERROR_FAILURE; // not all tokens were consumed
00064 
00065   return rv;
00066 }
00067 
00068 //----------------------------------------------------------------------
00069 // helpers
00070 nsresult nsSVGPathDataParser::AppendSegment(nsIDOMSVGPathSeg* seg)
00071 {
00072   NS_ADDREF(seg);
00073   mData->AppendElement((void*)seg);
00074   return NS_OK;
00075 }
00076 
00077 
00078 void nsSVGPathDataParser::getNextToken()
00079 {
00080   tokenpos  = inputpos;
00081   tokenval  = *inputpos;
00082   
00083   switch (tokenval) {
00084     case '0': case '1': case '2': case '3': case '4':
00085     case '5': case '6': case '7': case '8': case '9':
00086       tokentype = DIGIT;
00087       break;
00088     case '\x20': case '\x9': case '\xd': case '\xa':
00089       tokentype = WSP;
00090       break;
00091     case ',':
00092       tokentype = COMMA;
00093       break;
00094     case '+': case '-':
00095       tokentype = SIGN;
00096       break;
00097     case '.':
00098       tokentype = POINT;
00099       break;
00100     case '\0':
00101       tokentype = END;
00102       break;
00103     default:
00104       tokentype = OTHER;
00105   }
00106   
00107   if (*inputpos != '\0') {
00108     ++inputpos;
00109   }
00110 }
00111 
00112 void nsSVGPathDataParser::windBack(const char* pos)
00113 {
00114   inputpos = pos;
00115   getNextToken();
00116 }
00117 
00118 nsresult nsSVGPathDataParser::match(char tok)
00119 {
00120   if (tokenval != tok) return NS_ERROR_FAILURE;
00121   getNextToken();
00122   return NS_OK;
00123 }
00124 
00125 //----------------------------------------------------------------------
00126 
00127 nsresult nsSVGPathDataParser::matchSvgPath()
00128 {
00129   while (isTokenWspStarter()) {
00130     ENSURE_MATCHED(matchWsp());
00131   }
00132 
00133   if (isTokenSubPathsStarter()) {
00134     ENSURE_MATCHED(matchSubPaths());
00135   }
00136 
00137   while (isTokenWspStarter()) {
00138     ENSURE_MATCHED(matchWsp());
00139   }
00140   
00141   return NS_OK;
00142 }
00143 
00144 //----------------------------------------------------------------------
00145 
00146 nsresult nsSVGPathDataParser::matchSubPaths()
00147 {
00148   ENSURE_MATCHED(matchSubPath());
00149 
00150   while (1) {
00151     const char* pos = tokenpos;
00152 
00153     while (isTokenWspStarter()) {
00154       ENSURE_MATCHED(matchWsp());
00155     }
00156 
00157     if (isTokenSubPathStarter()) {
00158       ENSURE_MATCHED(matchSubPath());
00159     }
00160     else {
00161       if (pos != tokenpos) windBack(pos);
00162       break;
00163     }
00164   }
00165   
00166   return NS_OK;
00167 }
00168 
00169 PRBool nsSVGPathDataParser::isTokenSubPathsStarter()
00170 {
00171   return isTokenSubPathStarter();
00172 }
00173 
00174 //----------------------------------------------------------------------
00175 
00176 nsresult nsSVGPathDataParser::matchSubPath()
00177 {
00178   ENSURE_MATCHED(matchMoveto());
00179 
00180   while (isTokenWspStarter()) {
00181     ENSURE_MATCHED(matchWsp());
00182   }
00183 
00184   if (isTokenSubPathElementsStarter())
00185     ENSURE_MATCHED(matchSubPathElements());
00186   
00187   return NS_OK;
00188 }
00189 
00190 PRBool nsSVGPathDataParser::isTokenSubPathStarter()
00191 {
00192   return (tolower(tokenval) == 'm');
00193 }
00194 
00195 //----------------------------------------------------------------------
00196 
00197 nsresult nsSVGPathDataParser::matchSubPathElements()
00198 {
00199   ENSURE_MATCHED(matchSubPathElement());
00200 
00201   while (1) {
00202     const char* pos = tokenpos;
00203 
00204     while (isTokenWspStarter()) {
00205       ENSURE_MATCHED(matchWsp());
00206     }
00207 
00208 
00209     if (isTokenSubPathElementStarter()) {
00210         ENSURE_MATCHED(matchSubPathElement());
00211     }
00212     else {
00213       if (pos != tokenpos) windBack(pos);
00214       return NS_OK;
00215     }
00216   }
00217   
00218   return NS_OK;
00219 }
00220 
00221 PRBool nsSVGPathDataParser::isTokenSubPathElementsStarter()
00222 {
00223   return isTokenSubPathElementStarter();
00224 }
00225 
00226 //----------------------------------------------------------------------
00227 
00228 nsresult nsSVGPathDataParser::matchSubPathElement()
00229 {
00230   switch (tolower(tokenval)) {
00231     case 'z':
00232       ENSURE_MATCHED(matchClosePath());
00233       break;
00234     case 'l':
00235       ENSURE_MATCHED(matchLineto());
00236       break;      
00237     case 'h':
00238       ENSURE_MATCHED(matchHorizontalLineto());
00239       break;
00240     case 'v':
00241       ENSURE_MATCHED(matchVerticalLineto());
00242       break;
00243     case 'c':
00244       ENSURE_MATCHED(matchCurveto());
00245       break;      
00246     case 's':
00247       ENSURE_MATCHED(matchSmoothCurveto());
00248       break;
00249     case 'q':
00250       ENSURE_MATCHED(matchQuadBezierCurveto());
00251       break;
00252     case 't':
00253       ENSURE_MATCHED(matchSmoothQuadBezierCurveto());
00254       break;
00255     case 'a':
00256       ENSURE_MATCHED(matchEllipticalArc());
00257       break;
00258     default:
00259       return NS_ERROR_FAILURE;
00260       break;
00261   }
00262   return NS_OK;
00263 }
00264 
00265 PRBool nsSVGPathDataParser::isTokenSubPathElementStarter()
00266 {
00267   switch (tolower(tokenval)) {
00268     case 'z': case 'l': case 'h': case 'v': case 'c':
00269     case 's': case 'q': case 't': case 'a':
00270       return PR_TRUE;
00271       break;
00272     default:
00273       return PR_FALSE;
00274       break;
00275   }
00276   return PR_FALSE;
00277 }  
00278 
00279 //----------------------------------------------------------------------
00280 
00281 nsresult nsSVGPathDataParser::matchMoveto()
00282 {
00283   PRBool absCoords;
00284   
00285   switch (tokenval) {
00286     case 'M':
00287       absCoords = PR_TRUE;
00288       break;
00289     case 'm':
00290       absCoords = PR_FALSE;
00291       break;
00292     default:
00293       return NS_ERROR_FAILURE;
00294   }
00295 
00296   getNextToken();
00297 
00298   while (isTokenWspStarter()) {
00299     ENSURE_MATCHED(matchWsp());
00300   }
00301 
00302   ENSURE_MATCHED(matchMovetoArgSeq(absCoords));
00303   
00304   return NS_OK;
00305 }
00306 
00307 //  typedef nsresult MovetoSegCreationFunc(nsIDOMSVGPathSeg** res, float x, float y);
00308 //  MovetoSegCreationFunc *creationFunc;
00309 
00310 
00311 nsresult nsSVGPathDataParser::matchMovetoArgSeq(PRBool absCoords)
00312 {
00313   
00314   float x, y;
00315   ENSURE_MATCHED(matchCoordPair(&x, &y));
00316 
00317   nsresult rv;
00318   nsCOMPtr<nsIDOMSVGPathSeg> seg;
00319   if (absCoords) {
00320     nsCOMPtr<nsIDOMSVGPathSegMovetoAbs> segAbs;
00321     rv = NS_NewSVGPathSegMovetoAbs(getter_AddRefs(segAbs), x, y);
00322     seg = segAbs;
00323   }
00324   else {
00325     nsCOMPtr<nsIDOMSVGPathSegMovetoRel> segRel;
00326     rv = NS_NewSVGPathSegMovetoRel(getter_AddRefs(segRel), x, y);
00327     seg = segRel;
00328   }
00329   if (NS_FAILED(rv)) return rv;
00330   rv = AppendSegment(seg);
00331   if (NS_FAILED(rv)) return rv;
00332     
00333   const char* pos = tokenpos;
00334 
00335   if (isTokenCommaWspStarter()) {
00336     ENSURE_MATCHED(matchCommaWsp());
00337   }
00338 
00339   if (isTokenLinetoArgSeqStarter()) {
00340     ENSURE_MATCHED(matchLinetoArgSeq(absCoords));
00341   }
00342   else {
00343     if (pos != tokenpos) windBack(pos);
00344   }
00345   
00346   return NS_OK;
00347 }
00348 
00349 //----------------------------------------------------------------------
00350 
00351 nsresult nsSVGPathDataParser::matchClosePath()
00352 {
00353   switch (tokenval) {
00354     case 'Z':
00355     case 'z':
00356       getNextToken();
00357       break;
00358     default:
00359       return NS_ERROR_FAILURE;
00360   }
00361 
00362   nsresult rv;
00363   nsCOMPtr<nsIDOMSVGPathSegClosePath> seg;
00364   rv = NS_NewSVGPathSegClosePath(getter_AddRefs(seg));
00365   if (NS_FAILED(rv)) return rv;
00366   rv = AppendSegment(seg);
00367   if (NS_FAILED(rv)) return rv;
00368   
00369   return NS_OK;
00370 }
00371 
00372 //----------------------------------------------------------------------
00373   
00374 nsresult nsSVGPathDataParser::matchLineto()
00375 {
00376   PRBool absCoords;
00377   
00378   switch (tokenval) {
00379     case 'L':
00380       absCoords = PR_TRUE;
00381       break;
00382     case 'l':
00383       absCoords = PR_FALSE;
00384       break;
00385     default:
00386       return NS_ERROR_FAILURE;
00387   }
00388 
00389   getNextToken();
00390 
00391   while (isTokenWspStarter()) {
00392     ENSURE_MATCHED(matchWsp());
00393   }
00394 
00395   ENSURE_MATCHED(matchLinetoArgSeq(absCoords));
00396   
00397   return NS_OK;
00398 }
00399 
00400 nsresult nsSVGPathDataParser::matchLinetoArgSeq(PRBool absCoords)
00401 {
00402   while(1) {
00403     float x, y;
00404     ENSURE_MATCHED(matchCoordPair(&x, &y));
00405     
00406     nsresult rv;
00407     nsCOMPtr<nsIDOMSVGPathSeg> seg;
00408     if (absCoords) {
00409       nsCOMPtr<nsIDOMSVGPathSegLinetoAbs> segAbs;
00410       rv = NS_NewSVGPathSegLinetoAbs(getter_AddRefs(segAbs), x, y);
00411       seg = segAbs;
00412     }
00413     else {
00414       nsCOMPtr<nsIDOMSVGPathSegLinetoRel> segRel;
00415       rv = NS_NewSVGPathSegLinetoRel(getter_AddRefs(segRel), x, y);
00416       seg = segRel;
00417     }
00418     if (NS_FAILED(rv)) return rv;
00419     rv = AppendSegment(seg);
00420     if (NS_FAILED(rv)) return rv;
00421     
00422     const char* pos = tokenpos;
00423 
00424     if (isTokenCommaWspStarter()) {
00425       ENSURE_MATCHED(matchCommaWsp());
00426     }
00427 
00428     if (!isTokenCoordPairStarter()) {
00429       if (pos != tokenpos) windBack(pos);
00430       return NS_OK;
00431     }
00432   }
00433   
00434   return NS_OK;  
00435 }
00436 
00437 PRBool nsSVGPathDataParser::isTokenLinetoArgSeqStarter()
00438 {
00439   return isTokenCoordPairStarter();
00440 }
00441 
00442 //----------------------------------------------------------------------
00443 
00444 nsresult nsSVGPathDataParser::matchHorizontalLineto()
00445 {
00446   PRBool absCoords;
00447   
00448   switch (tokenval) {
00449     case 'H':
00450       absCoords = PR_TRUE;
00451       break;
00452     case 'h':
00453       absCoords = PR_FALSE;
00454       break;
00455     default:
00456       return NS_ERROR_FAILURE;
00457   }
00458 
00459   getNextToken();
00460 
00461   while (isTokenWspStarter()) {
00462     ENSURE_MATCHED(matchWsp());
00463   }
00464 
00465   ENSURE_MATCHED(matchHorizontalLinetoArgSeq(absCoords));
00466   
00467   return NS_OK;
00468 }
00469   
00470 nsresult nsSVGPathDataParser::matchHorizontalLinetoArgSeq(PRBool absCoords)
00471 {
00472   while(1) {
00473     float x;
00474     ENSURE_MATCHED(matchCoord(&x));
00475     
00476     nsresult rv;
00477     nsCOMPtr<nsIDOMSVGPathSeg> seg;
00478     if (absCoords) {
00479       nsCOMPtr<nsIDOMSVGPathSegLinetoHorizontalAbs> segAbs;
00480       rv = NS_NewSVGPathSegLinetoHorizontalAbs(getter_AddRefs(segAbs), x);
00481       seg = segAbs;
00482     }
00483     else {
00484       nsCOMPtr<nsIDOMSVGPathSegLinetoHorizontalRel> segRel;
00485       rv = NS_NewSVGPathSegLinetoHorizontalRel(getter_AddRefs(segRel), x);
00486       seg = segRel;
00487     }
00488     if (NS_FAILED(rv)) return rv;
00489     rv = AppendSegment(seg);
00490     if (NS_FAILED(rv)) return rv;
00491     
00492     const char* pos = tokenpos;
00493 
00494     if (isTokenCommaWspStarter()) {
00495       ENSURE_MATCHED(matchCommaWsp());
00496     }
00497 
00498     if (!isTokenCoordStarter()) {
00499       if (pos != tokenpos) windBack(pos);
00500       return NS_OK;
00501     }
00502   }
00503   
00504   return NS_OK;    
00505 }
00506 
00507 //----------------------------------------------------------------------
00508 
00509 nsresult nsSVGPathDataParser::matchVerticalLineto()
00510 {
00511   PRBool absCoords;
00512   
00513   switch (tokenval) {
00514     case 'V':
00515       absCoords = PR_TRUE;
00516       break;
00517     case 'v':
00518       absCoords = PR_FALSE;
00519       break;
00520     default:
00521       return NS_ERROR_FAILURE;
00522   }
00523 
00524   getNextToken();
00525 
00526   while (isTokenWspStarter()) {
00527     ENSURE_MATCHED(matchWsp());
00528   }
00529 
00530   ENSURE_MATCHED(matchVerticalLinetoArgSeq(absCoords));
00531   
00532   return NS_OK;
00533 }
00534 
00535 nsresult nsSVGPathDataParser::matchVerticalLinetoArgSeq(PRBool absCoords)
00536 {
00537   while(1) {
00538     float y;
00539     ENSURE_MATCHED(matchCoord(&y));
00540     
00541     nsresult rv;
00542     nsCOMPtr<nsIDOMSVGPathSeg> seg;
00543     if (absCoords) {
00544       nsCOMPtr<nsIDOMSVGPathSegLinetoVerticalAbs> segAbs;
00545       rv = NS_NewSVGPathSegLinetoVerticalAbs(getter_AddRefs(segAbs), y);
00546       seg = segAbs;
00547     }
00548     else {
00549       nsCOMPtr<nsIDOMSVGPathSegLinetoVerticalRel> segRel;
00550       rv = NS_NewSVGPathSegLinetoVerticalRel(getter_AddRefs(segRel), y);
00551       seg = segRel;
00552     }
00553     if (NS_FAILED(rv)) return rv;
00554     rv = AppendSegment(seg);
00555     if (NS_FAILED(rv)) return rv;
00556     
00557     const char* pos = tokenpos;
00558 
00559     if (isTokenCommaWspStarter()) {
00560       ENSURE_MATCHED(matchCommaWsp());
00561     }
00562 
00563     if (!isTokenCoordStarter()) {
00564       if (pos != tokenpos) windBack(pos);
00565       return NS_OK;
00566     }
00567   }
00568   
00569   return NS_OK;      
00570 }
00571 
00572 //----------------------------------------------------------------------
00573 
00574 nsresult nsSVGPathDataParser::matchCurveto()
00575 {
00576   PRBool absCoords;
00577   
00578   switch (tokenval) {
00579     case 'C':
00580       absCoords = PR_TRUE;
00581       break;
00582     case 'c':
00583       absCoords = PR_FALSE;
00584       break;
00585     default:
00586       return NS_ERROR_FAILURE;
00587   }
00588 
00589   getNextToken();
00590 
00591   while (isTokenWspStarter()) {
00592     ENSURE_MATCHED(matchWsp());
00593   }
00594 
00595   ENSURE_MATCHED(matchCurvetoArgSeq(absCoords));
00596   
00597   return NS_OK;
00598 }
00599 
00600 
00601 nsresult nsSVGPathDataParser::matchCurvetoArgSeq(PRBool absCoords)
00602 {
00603   while(1) {
00604     float x, y, x1, y1, x2, y2;
00605     ENSURE_MATCHED(matchCurvetoArg(&x, &y, &x1, &y1, &x2, &y2));
00606     
00607     nsresult rv;
00608     nsCOMPtr<nsIDOMSVGPathSeg> seg;
00609     if (absCoords) {
00610       nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicAbs> segAbs;
00611       rv = NS_NewSVGPathSegCurvetoCubicAbs(getter_AddRefs(segAbs), x, y, x1, y1, x2, y2);
00612       seg = segAbs;
00613     }
00614     else {
00615       nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicRel> segRel;
00616       rv = NS_NewSVGPathSegCurvetoCubicRel(getter_AddRefs(segRel), x, y, x1, y1, x2, y2);
00617       seg = segRel;
00618     }
00619     if (NS_FAILED(rv)) return rv;
00620     rv = AppendSegment(seg);
00621     if (NS_FAILED(rv)) return rv;
00622     
00623     const char* pos = tokenpos;
00624 
00625     if (isTokenCommaWspStarter()) {
00626       ENSURE_MATCHED(matchCommaWsp());
00627     }
00628 
00629     if (!isTokenCurvetoArgStarter()) {
00630       if (pos != tokenpos) windBack(pos);
00631       return NS_OK;
00632     }
00633   }
00634   
00635   return NS_OK;      
00636 }
00637 
00638 nsresult
00639 nsSVGPathDataParser::matchCurvetoArg(float* x, float* y, float* x1,
00640                                      float* y1, float* x2, float* y2)
00641 {
00642   ENSURE_MATCHED(matchCoordPair(x1, y1));
00643 
00644   if (isTokenCommaWspStarter()) {
00645     ENSURE_MATCHED(matchCommaWsp());
00646   }
00647 
00648   ENSURE_MATCHED(matchCoordPair(x2, y2));
00649 
00650   if (isTokenCommaWspStarter()) {
00651     ENSURE_MATCHED(matchCommaWsp());
00652   }
00653 
00654   ENSURE_MATCHED(matchCoordPair(x, y));
00655 
00656   return NS_OK;
00657 }
00658 
00659 PRBool nsSVGPathDataParser::isTokenCurvetoArgStarter()
00660 {
00661   return isTokenCoordPairStarter();
00662 }
00663 
00664 //----------------------------------------------------------------------
00665 
00666 nsresult nsSVGPathDataParser::matchSmoothCurveto()
00667 {
00668   PRBool absCoords;
00669   
00670   switch (tokenval) {
00671     case 'S':
00672       absCoords = PR_TRUE;
00673       break;
00674     case 's':
00675       absCoords = PR_FALSE;
00676       break;
00677     default:
00678       return NS_ERROR_FAILURE;
00679   }
00680 
00681   getNextToken();
00682 
00683   while (isTokenWspStarter()) {
00684     ENSURE_MATCHED(matchWsp());
00685   }
00686 
00687   ENSURE_MATCHED(matchSmoothCurvetoArgSeq(absCoords));
00688   
00689   return NS_OK;
00690 }
00691 
00692 nsresult nsSVGPathDataParser::matchSmoothCurvetoArgSeq(PRBool absCoords)
00693 {
00694   while(1) {
00695     float x, y, x2, y2;
00696     ENSURE_MATCHED(matchSmoothCurvetoArg(&x, &y, &x2, &y2));
00697     
00698     nsresult rv;
00699     nsCOMPtr<nsIDOMSVGPathSeg> seg;
00700     if (absCoords) {
00701       nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicSmoothAbs> segAbs;
00702       rv = NS_NewSVGPathSegCurvetoCubicSmoothAbs(getter_AddRefs(segAbs), x, y, x2, y2);
00703       seg = segAbs;
00704     }
00705     else {
00706       nsCOMPtr<nsIDOMSVGPathSegCurvetoCubicSmoothRel> segRel;
00707       rv = NS_NewSVGPathSegCurvetoCubicSmoothRel(getter_AddRefs(segRel), x, y, x2, y2);
00708       seg = segRel;
00709     }
00710     if (NS_FAILED(rv)) return rv;
00711     rv = AppendSegment(seg);
00712     if (NS_FAILED(rv)) return rv;
00713     
00714     const char* pos = tokenpos;
00715 
00716     if (isTokenCommaWspStarter()) {
00717       ENSURE_MATCHED(matchCommaWsp());
00718     }
00719 
00720     if (!isTokenSmoothCurvetoArgStarter()) {
00721       if (pos != tokenpos) windBack(pos);
00722       return NS_OK;
00723     }
00724   }
00725   
00726   return NS_OK;        
00727 }
00728 
00729 nsresult nsSVGPathDataParser::matchSmoothCurvetoArg(float* x, float* y, float* x2, float* y2)
00730 {
00731   ENSURE_MATCHED(matchCoordPair(x2, y2));
00732 
00733   if (isTokenCommaWspStarter()) {
00734     ENSURE_MATCHED(matchCommaWsp());
00735   }
00736 
00737   ENSURE_MATCHED(matchCoordPair(x, y));
00738 
00739   return NS_OK;
00740 }
00741 
00742 PRBool nsSVGPathDataParser::isTokenSmoothCurvetoArgStarter()
00743 {
00744   return isTokenCoordPairStarter();
00745 }
00746 
00747 //----------------------------------------------------------------------
00748 
00749 nsresult nsSVGPathDataParser::matchQuadBezierCurveto()
00750 {
00751   PRBool absCoords;
00752   
00753   switch (tokenval) {
00754     case 'Q':
00755       absCoords = PR_TRUE;
00756       break;
00757     case 'q':
00758       absCoords = PR_FALSE;
00759       break;
00760     default:
00761       return NS_ERROR_FAILURE;
00762   }
00763 
00764   getNextToken();
00765 
00766   while (isTokenWspStarter()) {
00767     ENSURE_MATCHED(matchWsp());
00768   }
00769 
00770   ENSURE_MATCHED(matchQuadBezierCurvetoArgSeq(absCoords));
00771   
00772   return NS_OK;
00773 }
00774 
00775 nsresult nsSVGPathDataParser::matchQuadBezierCurvetoArgSeq(PRBool absCoords)
00776 {
00777   while(1) {
00778     float x, y, x1, y1;
00779     ENSURE_MATCHED(matchQuadBezierCurvetoArg(&x, &y, &x1, &y1));
00780     
00781     nsresult rv;
00782     nsCOMPtr<nsIDOMSVGPathSeg> seg;
00783     if (absCoords) {
00784       nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticAbs> segAbs;
00785       rv = NS_NewSVGPathSegCurvetoQuadraticAbs(getter_AddRefs(segAbs), x, y, x1, y1);
00786       seg = segAbs;
00787     }
00788     else {
00789       nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticRel> segRel;
00790       rv = NS_NewSVGPathSegCurvetoQuadraticRel(getter_AddRefs(segRel), x, y, x1, y1);
00791       seg = segRel;
00792     }
00793     if (NS_FAILED(rv)) return rv;
00794     rv = AppendSegment(seg);
00795     if (NS_FAILED(rv)) return rv;
00796     
00797     const char* pos = tokenpos;
00798 
00799     if (isTokenCommaWspStarter()) {
00800       ENSURE_MATCHED(matchCommaWsp());
00801     }
00802 
00803     if (!isTokenQuadBezierCurvetoArgStarter()) {
00804       if (pos != tokenpos) windBack(pos);
00805       return NS_OK;
00806     }
00807   }
00808   
00809   return NS_OK;        
00810 }
00811 
00812 nsresult nsSVGPathDataParser::matchQuadBezierCurvetoArg(float* x, float* y, float* x1, float* y1)
00813 {
00814   ENSURE_MATCHED(matchCoordPair(x1, y1));
00815 
00816   if (isTokenCommaWspStarter()) {
00817     ENSURE_MATCHED(matchCommaWsp());
00818   }
00819 
00820   ENSURE_MATCHED(matchCoordPair(x, y));
00821 
00822   return NS_OK;  
00823 }
00824 
00825 PRBool nsSVGPathDataParser::isTokenQuadBezierCurvetoArgStarter()
00826 {
00827   return isTokenCoordPairStarter();
00828 }
00829 
00830 //----------------------------------------------------------------------
00831 
00832 nsresult nsSVGPathDataParser::matchSmoothQuadBezierCurveto()
00833 {
00834   PRBool absCoords;
00835   
00836   switch (tokenval) {
00837     case 'T':
00838       absCoords = PR_TRUE;
00839       break;
00840     case 't':
00841       absCoords = PR_FALSE;
00842       break;
00843     default:
00844       return NS_ERROR_FAILURE;
00845   }
00846 
00847   getNextToken();
00848 
00849   while (isTokenWspStarter()) {
00850     ENSURE_MATCHED(matchWsp());
00851   }
00852 
00853   ENSURE_MATCHED(matchSmoothQuadBezierCurvetoArgSeq(absCoords));
00854   
00855   return NS_OK;
00856 }
00857 
00858 nsresult nsSVGPathDataParser::matchSmoothQuadBezierCurvetoArgSeq(PRBool absCoords)
00859 {
00860   while(1) {
00861     float x, y;
00862     ENSURE_MATCHED(matchCoordPair(&x, &y));
00863     
00864     nsresult rv;
00865     nsCOMPtr<nsIDOMSVGPathSeg> seg;
00866     if (absCoords) {
00867       nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticSmoothAbs> segAbs;
00868       rv = NS_NewSVGPathSegCurvetoQuadraticSmoothAbs(getter_AddRefs(segAbs), x, y);
00869       seg = segAbs;
00870     }
00871     else {
00872       nsCOMPtr<nsIDOMSVGPathSegCurvetoQuadraticSmoothRel> segRel;
00873       rv = NS_NewSVGPathSegCurvetoQuadraticSmoothRel(getter_AddRefs(segRel), x, y);
00874       seg = segRel;
00875     }
00876     if (NS_FAILED(rv)) return rv;
00877     rv = AppendSegment(seg);
00878     if (NS_FAILED(rv)) return rv;
00879     
00880     const char* pos = tokenpos;
00881 
00882     if (isTokenCommaWspStarter()) {
00883       ENSURE_MATCHED(matchCommaWsp());
00884     }
00885 
00886     if (!isTokenCoordPairStarter()) {
00887       if (pos != tokenpos) windBack(pos);
00888       return NS_OK;
00889     }
00890   }
00891   
00892   return NS_OK;        
00893 }
00894 
00895 //----------------------------------------------------------------------
00896 
00897 nsresult nsSVGPathDataParser::matchEllipticalArc()
00898 {
00899   PRBool absCoords;
00900   
00901   switch (tokenval) {
00902     case 'A':
00903       absCoords = PR_TRUE;
00904       break;
00905     case 'a':
00906       absCoords = PR_FALSE;
00907       break;
00908     default:
00909       return NS_ERROR_FAILURE;
00910   }
00911 
00912   getNextToken();
00913 
00914   while (isTokenWspStarter()) {
00915     ENSURE_MATCHED(matchWsp());
00916   }
00917 
00918   ENSURE_MATCHED(matchEllipticalArcArgSeq(absCoords));
00919   
00920   return NS_OK;
00921 }
00922 
00923 nsresult nsSVGPathDataParser::matchEllipticalArcArgSeq(PRBool absCoords)
00924 {
00925   while(1) {
00926     float x, y, r1, r2, angle;
00927     PRBool largeArcFlag, sweepFlag;
00928     
00929     ENSURE_MATCHED(matchEllipticalArcArg(&x, &y, &r1, &r2, &angle, &largeArcFlag, &sweepFlag));
00930     
00931     nsresult rv;
00932     nsCOMPtr<nsIDOMSVGPathSeg> seg;
00933     if (absCoords) {
00934       nsCOMPtr<nsIDOMSVGPathSegArcAbs> segAbs;
00935       rv = NS_NewSVGPathSegArcAbs(getter_AddRefs(segAbs), x, y, r1, r2, angle,
00936                                   largeArcFlag, sweepFlag);
00937       seg = segAbs;
00938     }
00939     else {
00940       nsCOMPtr<nsIDOMSVGPathSegArcRel> segRel;
00941       rv = NS_NewSVGPathSegArcRel(getter_AddRefs(segRel), x, y, r1, r2, angle,
00942                                   largeArcFlag, sweepFlag);
00943       seg = segRel;
00944     }
00945     if (NS_FAILED(rv)) return rv;
00946     rv = AppendSegment(seg);
00947     if (NS_FAILED(rv)) return rv;
00948     
00949     const char* pos = tokenpos;
00950 
00951     if (isTokenCommaWspStarter()) {
00952       ENSURE_MATCHED(matchCommaWsp());
00953     }
00954 
00955     if (!isTokenEllipticalArcArgStarter()) {
00956       if (pos != tokenpos) windBack(pos);
00957       return NS_OK;
00958     }
00959   }
00960   
00961   return NS_OK;        
00962 }
00963 
00964 nsresult nsSVGPathDataParser::matchEllipticalArcArg(float* x, float* y,
00965                                                     float* r1, float* r2, float* angle,
00966                                                     PRBool* largeArcFlag, PRBool* sweepFlag)
00967 {
00968   ENSURE_MATCHED(matchNonNegativeNumber(r1));
00969 
00970   if (isTokenCommaWspStarter()) {
00971     ENSURE_MATCHED(matchCommaWsp());
00972   }
00973 
00974   ENSURE_MATCHED(matchNonNegativeNumber(r2));
00975 
00976   if (isTokenCommaWspStarter()) {
00977     ENSURE_MATCHED(matchCommaWsp());
00978   }
00979 
00980   ENSURE_MATCHED(matchNumber(angle));
00981 
00982   if (isTokenCommaWspStarter()) {
00983     ENSURE_MATCHED(matchCommaWsp());
00984   }
00985   
00986   ENSURE_MATCHED(matchFlag(largeArcFlag));
00987 
00988   if (isTokenCommaWspStarter()) {
00989     ENSURE_MATCHED(matchCommaWsp());
00990   }
00991 
00992   ENSURE_MATCHED(matchFlag(sweepFlag));
00993 
00994   if (isTokenCommaWspStarter()) {
00995     ENSURE_MATCHED(matchCommaWsp());
00996   }
00997 
00998   ENSURE_MATCHED(matchCoordPair(x, y));
00999   
01000   return NS_OK;  
01001   
01002 }
01003 
01004 PRBool nsSVGPathDataParser::isTokenEllipticalArcArgStarter()
01005 {
01006   return isTokenNonNegativeNumberStarter();
01007 }
01008 
01009 //----------------------------------------------------------------------
01010 
01011 nsresult nsSVGPathDataParser::matchCoordPair(float* x, float* y)
01012 {
01013   ENSURE_MATCHED(matchCoord(x));
01014 
01015   if (isTokenCommaWspStarter()) {
01016     ENSURE_MATCHED(matchCommaWsp());
01017   }
01018 
01019   ENSURE_MATCHED(matchCoord(y));
01020 
01021   return NS_OK;
01022 }
01023 
01024 PRBool nsSVGPathDataParser::isTokenCoordPairStarter()
01025 {
01026   return isTokenCoordStarter();
01027 }
01028 
01029 //----------------------------------------------------------------------
01030 
01031 nsresult nsSVGPathDataParser::matchCoord(float* x)
01032 {
01033   ENSURE_MATCHED(matchNumber(x));
01034 
01035   return NS_OK;
01036 }
01037 
01038 PRBool nsSVGPathDataParser::isTokenCoordStarter()
01039 {
01040   return isTokenNumberStarter();
01041 }
01042 
01043 //----------------------------------------------------------------------
01044 
01045 nsresult nsSVGPathDataParser::matchNonNegativeNumber(float* x)
01046 {
01047   // XXX inefficient implementation. We probably hit the windback case
01048   // often.
01049   
01050   const char* pos = tokenpos;
01051 
01052   nsresult rv = matchFloatingPointConst();
01053 
01054   if (NS_FAILED(rv)) {
01055     windBack(pos);
01056     ENSURE_MATCHED(matchIntegerConst());
01057   }
01058 
01059   char* end;
01060   *x = (float) PR_strtod(pos, &end);
01061   NS_ASSERTION(end == tokenpos, "number parse error");
01062                
01063   return NS_OK;
01064 }
01065 
01066 PRBool nsSVGPathDataParser::isTokenNonNegativeNumberStarter()
01067 {
01068   return (tokentype == DIGIT || tokentype == POINT);
01069 }
01070 
01071 //----------------------------------------------------------------------
01072 
01073 nsresult nsSVGPathDataParser::matchNumber(float* x)
01074 {
01075   const char* pos = tokenpos;
01076   
01077   if (tokentype == SIGN)
01078     getNextToken();
01079 
01080   const char* pos2 = tokenpos;
01081 
01082   nsresult rv = matchFloatingPointConst();
01083 
01084   if (NS_FAILED(rv)) {
01085     windBack(pos);
01086     ENSURE_MATCHED(matchIntegerConst());
01087   }
01088 
01089   char* end;
01090   *x = (float) PR_strtod(pos, &end);
01091   NS_ASSERTION(end == tokenpos, "number parse error");
01092                
01093   return NS_OK;
01094 }
01095 
01096 PRBool nsSVGPathDataParser::isTokenNumberStarter()
01097 {
01098   return (tokentype == DIGIT || tokentype == POINT || tokentype == SIGN);
01099 }
01100 
01101 //----------------------------------------------------------------------
01102 
01103 nsresult nsSVGPathDataParser::matchFlag(PRBool* f)
01104 {
01105   switch (tokenval) {
01106     case '0':
01107       *f = PR_FALSE;
01108       break;
01109     case '1':
01110       *f = PR_TRUE;
01111       break;
01112     default:
01113       return NS_ERROR_FAILURE;
01114   }
01115   getNextToken();
01116   return NS_OK;
01117 }
01118 
01119 //----------------------------------------------------------------------
01120 
01121 nsresult nsSVGPathDataParser::matchCommaWsp()
01122 {
01123   switch (tokentype) {
01124     case WSP:
01125       ENSURE_MATCHED(matchWsp());
01126       if (tokentype == COMMA)
01127         getNextToken();
01128       break;
01129     case COMMA:
01130       getNextToken();
01131       break;
01132     default:
01133       return NS_ERROR_FAILURE;
01134   }
01135 
01136   while (isTokenWspStarter()) {
01137     ENSURE_MATCHED(matchWsp());
01138   }
01139   return NS_OK;
01140 }
01141   
01142 PRBool nsSVGPathDataParser::isTokenCommaWspStarter()
01143 {
01144   return (isTokenWspStarter() || tokentype == COMMA);
01145 }
01146 
01147 //----------------------------------------------------------------------
01148 
01149 nsresult nsSVGPathDataParser::matchIntegerConst()
01150 {
01151   ENSURE_MATCHED(matchDigitSeq());
01152   return NS_OK;
01153 }
01154 
01155 //----------------------------------------------------------------------
01156 
01157 nsresult nsSVGPathDataParser::matchFloatingPointConst()
01158 {
01159   // XXX inefficient implementation. It would be nice if we could make
01160   // this predictive and wouldn't have to backtrack...
01161   
01162   const char* pos = tokenpos;
01163 
01164   nsresult rv = matchFractConst();
01165   if (NS_SUCCEEDED(rv)) {
01166     if (isTokenExponentStarter())
01167       ENSURE_MATCHED(matchExponent());
01168   }
01169   else {
01170     windBack(pos);
01171     ENSURE_MATCHED(matchDigitSeq());
01172     ENSURE_MATCHED(matchExponent());    
01173   }
01174 
01175   return NS_OK;  
01176 }
01177 
01178 //----------------------------------------------------------------------
01179 
01180 nsresult nsSVGPathDataParser::matchFractConst()
01181 {
01182   if (tokentype == POINT) {
01183     getNextToken();
01184     ENSURE_MATCHED(matchDigitSeq());
01185   }
01186   else {
01187     ENSURE_MATCHED(matchDigitSeq());
01188     if (tokentype == POINT) {
01189       getNextToken();
01190       if (isTokenDigitSeqStarter()) {
01191         ENSURE_MATCHED(matchDigitSeq());
01192       }
01193     }
01194   }
01195   return NS_OK;
01196 }
01197 
01198 //----------------------------------------------------------------------
01199 
01200 nsresult nsSVGPathDataParser::matchExponent()
01201 {
01202   if (!(tolower(tokenval) == 'e')) return NS_ERROR_FAILURE;
01203 
01204   getNextToken();
01205 
01206   if (tokentype == SIGN)
01207     getNextToken();
01208 
01209   ENSURE_MATCHED(matchDigitSeq());
01210 
01211   return NS_OK;  
01212 }
01213 
01214 PRBool nsSVGPathDataParser::isTokenExponentStarter()
01215 {
01216   return (tolower(tokenval) == 'e');
01217 }
01218 
01219 //----------------------------------------------------------------------
01220 
01221 nsresult nsSVGPathDataParser::matchDigitSeq()
01222 {
01223   if (!(tokentype == DIGIT)) return NS_ERROR_FAILURE;
01224 
01225   do {
01226     getNextToken();
01227   } while (tokentype == DIGIT);
01228 
01229   return NS_OK;
01230 }
01231 
01232 PRBool nsSVGPathDataParser::isTokenDigitSeqStarter()
01233 {
01234   return (tokentype == DIGIT);
01235 }
01236 
01237 //----------------------------------------------------------------------
01238 
01239 nsresult nsSVGPathDataParser::matchWsp()
01240 {
01241   if (!(tokentype == WSP)) return NS_ERROR_FAILURE;
01242 
01243   do {
01244     getNextToken();
01245   } while (tokentype == WSP);
01246 
01247   return NS_OK;  
01248 }
01249 
01250 PRBool nsSVGPathDataParser::isTokenWspStarter()
01251 {
01252   return (tokentype == WSP);
01253 }  
01254