/layout/svg/renderer/src/libart/nsSVGLibartPathGeometry.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 Crocodile Clips Ltd.
00018  * 
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 the GNU General Public License Version 2 or later (the "GPL"), or 
00027  * 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 NPL, 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 "nsCOMPtr.h"
00040 #include "nsSVGLibartPathGeometry.h"
00041 #include "nsISVGRendererPathGeometry.h"
00042 #include "nsISVGLibartCanvas.h"
00043 #include "nsIDOMSVGMatrix.h"
00044 #include "nsSVGLibartRegion.h"
00045 #include "nsISVGRendererRegion.h"
00046 #include "nsSVGLibartBPathBuilder.h"
00047 #include "nsISVGRendererPathBuilder.h"
00048 #include "nsISVGPathGeometrySource.h"
00049 #include "nsSVGFill.h"
00050 #include "nsSVGStroke.h"
00051 #include "nsIServiceManager.h"
00052 #include "nsIPref.h"
00053 #include "nsMemory.h"
00054 #include "prdtoa.h"
00055 
00060 
00061 
00064 class nsSVGLibartPathGeometry : public nsISVGRendererPathGeometry
00065 {
00066 protected:
00067   friend nsresult NS_NewSVGLibartPathGeometry(nsISVGRendererPathGeometry **result,
00068                                               nsISVGPathGeometrySource *src);
00069 
00070   nsSVGLibartPathGeometry();
00071   ~nsSVGLibartPathGeometry();
00072   nsresult Init(nsISVGPathGeometrySource* src);
00073 
00074 public:
00075   // nsISupports interface:
00076   NS_DECL_ISUPPORTS
00077   
00078   // nsISVGRendererPathGeometry interface:
00079   NS_DECL_NSISVGRENDERERPATHGEOMETRY
00080   
00081 protected:
00082   void ClearPath() { if (mVPath) { art_free(mVPath); mVPath=nsnull; } }
00083   void ClearFill() { mFill.Clear(); }
00084   void ClearStroke() { mStroke.Clear(); }
00085   void ClearCoveredRegion() { mCoveredRegion = nsnull; }
00086   ArtVpath *GetPath();
00087   ArtSVP *GetFill();
00088   ArtSVP *GetStroke();
00089   
00090   double GetBezierFlatness();
00091   
00092   private:
00093   nsCOMPtr<nsISVGPathGeometrySource> mSource;
00094   nsCOMPtr<nsISVGRendererRegion> mCoveredRegion;
00095 
00096   ArtVpath* mVPath;
00097   nsSVGFill mFill;
00098   nsSVGStroke mStroke;
00099 };
00100 
00103 //----------------------------------------------------------------------
00104 // implementation:
00105 
00106 nsSVGLibartPathGeometry::nsSVGLibartPathGeometry()
00107     : mVPath(nsnull)
00108 {
00109 }
00110 
00111 nsSVGLibartPathGeometry::~nsSVGLibartPathGeometry()
00112 {
00113   ClearPath();
00114 }
00115 
00116 nsresult nsSVGLibartPathGeometry::Init(nsISVGPathGeometrySource* src)
00117 {
00118   mSource = src;
00119   return NS_OK;
00120 }
00121 
00122 
00123 nsresult
00124 NS_NewSVGLibartPathGeometry(nsISVGRendererPathGeometry **result,
00125                             nsISVGPathGeometrySource *src)
00126 {
00127   nsSVGLibartPathGeometry* pg = new nsSVGLibartPathGeometry();
00128   if (!pg) return NS_ERROR_OUT_OF_MEMORY;
00129 
00130   NS_ADDREF(pg);
00131 
00132   nsresult rv = pg->Init(src);
00133 
00134   if (NS_FAILED(rv)) {
00135     NS_RELEASE(pg);
00136     return rv;
00137   }
00138   
00139   *result = pg;
00140   return rv;
00141 }
00142 
00143 //----------------------------------------------------------------------
00144 // nsISupports methods:
00145 
00146 NS_IMPL_ADDREF(nsSVGLibartPathGeometry)
00147 NS_IMPL_RELEASE(nsSVGLibartPathGeometry)
00148 
00149 NS_INTERFACE_MAP_BEGIN(nsSVGLibartPathGeometry)
00150   NS_INTERFACE_MAP_ENTRY(nsISVGRendererPathGeometry)
00151   NS_INTERFACE_MAP_ENTRY(nsISupports)
00152 NS_INTERFACE_MAP_END
00153 
00154 //----------------------------------------------------------------------
00155 
00156 ArtVpath*
00157 nsSVGLibartPathGeometry::GetPath()
00158 {
00159   if (mVPath) return mVPath;
00160 
00161   // 1. construct a bezier path:
00162   ArtBpath*bpath = nsnull;
00163   
00164   nsCOMPtr<nsISVGRendererPathBuilder> builder;
00165   NS_NewSVGLibartBPathBuilder(getter_AddRefs(builder), &bpath);
00166   mSource->ConstructPath(builder);
00167   builder->EndPath();
00168 
00169   // 2. transform the bpath into global coords:
00170   double matrix[6];
00171   {
00172     nsCOMPtr<nsIDOMSVGMatrix> ctm;
00173     mSource->GetCTM(getter_AddRefs(ctm));
00174     NS_ASSERTION(ctm, "graphic source didn't have a ctm");
00175     
00176     float val;
00177     ctm->GetA(&val);
00178     matrix[0] = val;
00179     
00180     ctm->GetB(&val);
00181     matrix[1] = val;
00182     
00183     ctm->GetC(&val);  
00184     matrix[2] = val;  
00185     
00186     ctm->GetD(&val);  
00187     matrix[3] = val;  
00188     
00189     ctm->GetE(&val);
00190     matrix[4] = val;
00191     
00192     ctm->GetF(&val);
00193     matrix[5] = val;
00194   }
00195   
00196   if ( bpath &&
00197        ( matrix[0] != 1.0 || matrix[2] != 0.0 || matrix[4] != 0.0 ||
00198          matrix[1] != 0.0 || matrix[3] != 1.0 || matrix[5] != 0.0 ))
00199   {
00200     ArtBpath* temp = bpath;
00201     bpath = art_bpath_affine_transform(bpath, matrix);
00202     art_free(temp);
00203   }
00204 
00205   // 3. convert the bpath into a vpath:
00206   if (bpath)
00207     mVPath = art_bez_path_to_vec(bpath, GetBezierFlatness());
00208 
00209   return mVPath;
00210 }
00211 
00212 ArtSVP *
00213 nsSVGLibartPathGeometry::GetFill()
00214 {
00215   if (!mFill.IsEmpty() || !GetPath()) return mFill.GetSvp();
00216   
00217   mFill.Build(GetPath(), mSource);
00218   
00219   return mFill.GetSvp();
00220 }
00221 
00222 ArtSVP *
00223 nsSVGLibartPathGeometry::GetStroke()
00224 {
00225   if (!mStroke.IsEmpty() || !GetPath()) return mStroke.GetSvp();
00226 
00227   mStroke.Build(GetPath(), mSource);
00228   
00229   return mStroke.GetSvp();
00230 }
00231 
00232 double
00233 nsSVGLibartPathGeometry::GetBezierFlatness()
00234 {
00235 // comment from art_vpath_path.c: The Adobe PostScript reference
00236 // manual defines flatness as the maximum deviation between any
00237 // point on the vpath approximation and the corresponding point on the
00238 // "true" curve, and we follow this definition here. A value of 0.25
00239 // should ensure high quality for aa rendering.
00240 
00241   double flatness = 0.5;
00242   
00243   nsCOMPtr<nsIPref> prefs(do_GetService(NS_PREF_CONTRACTID));
00244     if (!prefs) return flatness;
00245 
00246   // XXX: wouldn't it be great if nsIPref had a 'GetFloatPref()'-function?
00247   char  *valuestr = nsnull;
00248   if (NS_SUCCEEDED(prefs->CopyCharPref("svg.bezier_flatness",&valuestr)) && (valuestr)) {
00249     flatness = PR_strtod(valuestr, nsnull);
00250     nsMemory::Free(valuestr);
00251   }
00252 
00253   return flatness;
00254 }
00255 
00256 //----------------------------------------------------------------------
00257 // nsISVGRendererPathGeometry methods:
00258 
00260 NS_IMETHODIMP
00261 nsSVGLibartPathGeometry::Render(nsISVGRendererCanvas *canvas)
00262 {
00263   nsCOMPtr<nsISVGLibartCanvas> libartCanvas = do_QueryInterface(canvas);
00264   NS_ASSERTION(libartCanvas, "wrong svg render context for geometry!");
00265   if (!libartCanvas) return NS_ERROR_FAILURE;
00266 
00267   PRUint16 type;
00268   
00269   // paint fill:
00270   mSource->GetFillPaintType(&type);
00271   if (type == nsISVGGeometrySource::PAINT_TYPE_SOLID_COLOR && GetFill()) {
00272     nscolor rgb;
00273     mSource->GetFillPaint(&rgb);
00274     float opacity;
00275     mSource->GetFillOpacity(&opacity);
00276 
00277     ArtColor col;
00278     libartCanvas->GetArtColor(rgb, col);
00279     
00280     ArtRender* render = libartCanvas->NewRender();
00281     NS_ASSERTION(render, "could not create render");
00282 
00283     art_render_mask_solid(render, (int)(0x10000 * opacity));
00284     art_render_svp(render, GetFill());
00285     art_render_image_solid(render, col);
00286     libartCanvas->InvokeRender(render);
00287   }
00288 
00289   // paint stroke:
00290   mSource->GetStrokePaintType(&type);
00291   if (type == nsISVGGeometrySource::PAINT_TYPE_SOLID_COLOR && GetStroke()) {
00292     nscolor rgb;
00293     mSource->GetStrokePaint(&rgb);
00294     float opacity;
00295     mSource->GetStrokeOpacity(&opacity);
00296 
00297     ArtColor col;
00298     libartCanvas->GetArtColor(rgb, col);
00299     
00300     ArtRender* render = libartCanvas->NewRender();
00301     NS_ASSERTION(render, "could not create render");
00302 
00303     art_render_mask_solid(render, (int)(0x10000 * opacity));
00304     art_render_svp(render, GetStroke());
00305     art_render_image_solid(render, col);
00306     libartCanvas->InvokeRender(render);
00307   }
00308   
00309   return NS_OK;
00310 }
00311 
00313 NS_IMETHODIMP
00314 nsSVGLibartPathGeometry::Update(PRUint32 updatemask, nsISVGRendererRegion **_retval)
00315 {
00316   *_retval = nsnull;
00317 
00318   const unsigned long pathmask =
00319     nsISVGPathGeometrySource::UPDATEMASK_PATH |
00320     nsISVGGeometrySource::UPDATEMASK_CTM;
00321 
00322   const unsigned long fillmask = 
00323     pathmask |
00324     nsISVGGeometrySource::UPDATEMASK_FILL_RULE;
00325 
00326   const unsigned long strokemask =
00327     pathmask |
00328     nsISVGGeometrySource::UPDATEMASK_STROKE_WIDTH       |
00329     nsISVGGeometrySource::UPDATEMASK_STROKE_LINECAP     |
00330     nsISVGGeometrySource::UPDATEMASK_STROKE_LINEJOIN    |
00331     nsISVGGeometrySource::UPDATEMASK_STROKE_MITERLIMIT  |
00332     nsISVGGeometrySource::UPDATEMASK_STROKE_DASH_ARRAY  |
00333     nsISVGGeometrySource::UPDATEMASK_STROKE_DASHOFFSET;
00334 
00335   const unsigned long coveredregionmask =
00336     fillmask                                            |
00337     strokemask                                          |
00338     nsISVGGeometrySource::UPDATEMASK_FILL_PAINT_TYPE    |
00339     nsISVGGeometrySource::UPDATEMASK_STROKE_PAINT_TYPE;
00340   
00341   nsCOMPtr<nsISVGRendererRegion> before;
00342   GetCoveredRegion(getter_AddRefs(before));
00343 
00344   if ((updatemask & pathmask)!=0){
00345     ClearPath();
00346   }
00347   if ((updatemask & fillmask)!=0)
00348     ClearFill();
00349   if ((updatemask & strokemask)!=0)
00350     ClearStroke();
00351   if ((updatemask & coveredregionmask)!=0) {
00352     ClearCoveredRegion();
00353     nsCOMPtr<nsISVGRendererRegion> after;
00354     GetCoveredRegion(getter_AddRefs(after));
00355     if (after)
00356       after->Combine(before, _retval);
00357   }
00358   else if (updatemask != nsISVGGeometrySource::UPDATEMASK_NOTHING) {
00359     *_retval = before;
00360     NS_IF_ADDREF(*_retval);
00361   }
00362 
00363   return NS_OK;
00364 }
00365 
00367 NS_IMETHODIMP
00368 nsSVGLibartPathGeometry::GetCoveredRegion(nsISVGRendererRegion **_retval)
00369 {
00370   *_retval = nsnull;
00371   
00372   if (mCoveredRegion) {
00373     *_retval = mCoveredRegion;
00374     NS_ADDREF(*_retval);
00375     return NS_OK;
00376   }
00377   
00378   PRUint16 type;  
00379   mSource->GetFillPaintType(&type);
00380   bool hasCoveredFill = (type!=nsISVGGeometrySource::PAINT_TYPE_NONE) && GetFill();
00381   
00382   mSource->GetStrokePaintType(&type);
00383   bool hasCoveredStroke = (type!=nsISVGGeometrySource::PAINT_TYPE_NONE) && GetStroke();
00384 
00385   if (!hasCoveredFill && !hasCoveredStroke) return NS_OK;
00386 
00387   if (hasCoveredFill) {
00388     nsCOMPtr<nsISVGRendererRegion> reg1;
00389     NS_NewSVGLibartSVPRegion(getter_AddRefs(reg1), GetFill());
00390     if (hasCoveredStroke) {
00391       nsCOMPtr<nsISVGRendererRegion> reg2;
00392       NS_NewSVGLibartSVPRegion(getter_AddRefs(reg2), GetStroke());
00393       reg1->Combine(reg2, _retval);
00394     }
00395     else {
00396       *_retval = reg1;
00397       NS_ADDREF(*_retval);
00398     }
00399   } // covered stroke only
00400   else
00401     NS_NewSVGLibartSVPRegion(_retval, GetStroke());
00402 
00403   mCoveredRegion = *_retval;
00404   return NS_OK;
00405 }
00406 
00408 NS_IMETHODIMP
00409 nsSVGLibartPathGeometry::ContainsPoint(float x, float y, PRBool *_retval)
00410 {
00411   *_retval = PR_FALSE;
00412 
00413   PRUint16 mask;
00414   mSource->GetHittestMask(&mask);
00415 
00416   if (mask & nsISVGPathGeometrySource::HITTEST_MASK_FILL &&
00417       mFill.Contains(x,y)) {
00418     *_retval = PR_TRUE;
00419     return NS_OK;
00420   }
00421   if (mask & nsISVGPathGeometrySource::HITTEST_MASK_STROKE &&
00422       mStroke.Contains(x,y)) {
00423     *_retval = PR_TRUE;
00424   }
00425   
00426   return NS_OK;
00427 }

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