/layout/svg/base/src/nsSVGPathFrame.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
00006  * Version 1.1 (the "License"); you may not use this file except in
00007  * compliance with 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  *    Daniele Nicolodi <daniele@grinta.net> 
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or 
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the NPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ----- END LICENSE BLOCK ----- */
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   // nsISVGValueObserver interface:
00060   NS_IMETHOD DidModifySVGObservable(nsISVGValue* observable);
00061 
00062   // nsISVGPathGeometrySource interface:
00063   NS_IMETHOD ConstructPath(nsISVGRendererPathBuilder *pathBuilder);
00064 
00065 private:  
00066   nsCOMPtr<nsIDOMSVGPathSegList> mSegments;
00067 };
00068 
00069 //----------------------------------------------------------------------
00070 // Implementation
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 // nsISVGValueObserver methods:
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   // else
00129   return nsSVGPathGeometryFrame::DidModifySVGObservable(observable);
00130 }
00131 
00132 //----------------------------------------------------------------------
00133 // nsISVGPathGeometrySource methods:
00134 
00135 /* void constructPath (in nsISVGRendererPathBuilder pathBuilder); */
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; // current point
00143   float cy = 0.0f;
00144   
00145   float cx1 = 0.0f; // last controlpoint (for s,S,t,T)
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           // conversion of quadratic bezier curve to cubic bezier curve:
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             // the first controlpoint is the reflection of the last one about the current point:
00385             x1 = 2*cx - cx1;
00386             y1 = 2*cy - cy1;
00387           }
00388           else {
00389             // the first controlpoint is equal to the current point:
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             // the first controlpoint is the reflection of the last one about the current point:
00432             x1 = 2*cx - cx1;
00433             y1 = 2*cy - cy1;
00434           }
00435           else {
00436             // the first controlpoint is equal to the current point:
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           // conversion of quadratic bezier curve to cubic bezier curve:
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 }

Generated on Wed Sep 10 22:25:23 2003 for Mozilla SVG Project Rendering Backend by doxygen1.3