Back to index

lightning-sunbird  0.9+nobinonly
nsSVGGDIPlusPathGeometry.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) 2002
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 <windows.h>
00040 
00041 // unknwn.h is needed to build with WIN32_LEAN_AND_MEAN
00042 #include <unknwn.h>
00043 
00044 #include <Gdiplus.h>
00045 using namespace Gdiplus;
00046 
00047 #include "nsCOMPtr.h"
00048 #include "nsSVGGDIPlusPathGeometry.h"
00049 #include "nsISVGRendererPathGeometry.h"
00050 #include "nsISVGGDIPlusCanvas.h"
00051 #include "nsIDOMSVGMatrix.h"
00052 #include "nsSVGGDIPlusRegion.h"
00053 #include "nsISVGRendererRegion.h"
00054 #include "nsSVGGDIPlusPathBuilder.h"
00055 #include "nsISVGPathGeometrySource.h"
00056 #include "nsISVGRendererPathBuilder.h"
00057 #include "nsSVGGDIPlusGradient.h"
00058 #include "nsMemory.h"
00059 #include "nsIDOMSVGRect.h"
00060 #include "nsSVGTypeCIDs.h"
00061 #include "nsIComponentManager.h"
00062 #include "nsISVGPathFlatten.h"
00063 
00068 
00069 
00072 class nsSVGGDIPlusPathGeometry : public nsISVGRendererPathGeometry
00073 {
00074 protected:
00075   friend nsresult NS_NewSVGGDIPlusPathGeometry(nsISVGRendererPathGeometry **result,
00076                                                nsISVGPathGeometrySource *src);
00077   friend void gradCBFill(Graphics *gfx, Brush *brush, void *cbStruct);
00078   friend void gradCBStroke(Graphics *gfx, Brush *brush, void *cbStruct);
00079 
00080   nsSVGGDIPlusPathGeometry();
00081   ~nsSVGGDIPlusPathGeometry();
00082   nsresult Init(nsISVGPathGeometrySource* src);
00083 
00084 public:
00085   // nsISupports interface:
00086   NS_DECL_ISUPPORTS
00087   
00088   // nsISVGRendererPathGeometry interface:
00089   NS_DECL_NSISVGRENDERERPATHGEOMETRY
00090 
00091 protected:
00092   void ClearPath() { if (mPath) { delete mPath; mPath=nsnull; } }
00093   void ClearFill() { if (mFill) { delete mFill; mFill=nsnull; } }
00094   void ClearStroke() { if (mStroke) {delete mStroke; mStroke=nsnull; } }
00095   void ClearCoveredRegion() { mCoveredRegion = nsnull; }
00096   void ClearHitTestRegion() { if (mHitTestRegion) {delete mHitTestRegion; mHitTestRegion=nsnull; } }
00097   GraphicsPath *GetPath();
00098   GraphicsPath *GetFill();
00099   GraphicsPath *GetStroke();
00100   Region *GetHitTestRegion();
00101   
00102   void GetGlobalTransform(Matrix *matrix);
00103   void RenderPath(GraphicsPath *path, nscolor color, float opacity,
00104                   nsISVGGDIPlusCanvas *canvas);
00105 private:
00106   nsCOMPtr<nsISVGPathGeometrySource> mSource;
00107   GraphicsPath *mPath; // untransformed path
00108   GraphicsPath *mFill;
00109   GraphicsPath *mStroke;
00110   Region *mHitTestRegion;
00111   nsCOMPtr<nsISVGRendererRegion> mCoveredRegion;
00112 };
00113 
00117 //----------------------------------------------------------------------
00118 // implementation:
00119 
00120 nsSVGGDIPlusPathGeometry::nsSVGGDIPlusPathGeometry()
00121     : mPath(nsnull), mFill(nsnull), mStroke(nsnull), mHitTestRegion(nsnull)
00122 {
00123 }
00124 
00125 nsSVGGDIPlusPathGeometry::~nsSVGGDIPlusPathGeometry()
00126 {
00127   ClearPath();
00128   ClearFill();
00129   ClearStroke();
00130   ClearCoveredRegion();
00131   ClearHitTestRegion();
00132 }
00133 
00134 nsresult nsSVGGDIPlusPathGeometry::Init(nsISVGPathGeometrySource* src)
00135 {
00136   mSource = src;
00137   return NS_OK;
00138 }
00139 
00140 
00141 nsresult
00142 NS_NewSVGGDIPlusPathGeometry(nsISVGRendererPathGeometry **result,
00143                              nsISVGPathGeometrySource *src)
00144 {
00145   nsSVGGDIPlusPathGeometry* pg = new nsSVGGDIPlusPathGeometry();
00146   if (!pg) return NS_ERROR_OUT_OF_MEMORY;
00147 
00148   NS_ADDREF(pg);
00149 
00150   nsresult rv = pg->Init(src);
00151 
00152   if (NS_FAILED(rv)) {
00153     NS_RELEASE(pg);
00154     return rv;
00155   }
00156   
00157   *result = pg;
00158   return rv;
00159 }
00160 
00161 //----------------------------------------------------------------------
00162 // nsISupports methods:
00163 
00164 NS_IMPL_ADDREF(nsSVGGDIPlusPathGeometry)
00165 NS_IMPL_RELEASE(nsSVGGDIPlusPathGeometry)
00166 
00167 NS_INTERFACE_MAP_BEGIN(nsSVGGDIPlusPathGeometry)
00168   NS_INTERFACE_MAP_ENTRY(nsISVGRendererPathGeometry)
00169   NS_INTERFACE_MAP_ENTRY(nsISupports)
00170 NS_INTERFACE_MAP_END
00171 
00172 //----------------------------------------------------------------------
00173 
00174 GraphicsPath *
00175 nsSVGGDIPlusPathGeometry::GetPath()
00176 {
00177   if (mPath) return mPath;
00178 
00179   mPath = new GraphicsPath();
00180   nsCOMPtr<nsISVGRendererPathBuilder> builder;
00181   NS_NewSVGGDIPlusPathBuilder(getter_AddRefs(builder), mSource, mPath);
00182   mSource->ConstructPath(builder);
00183   return mPath;
00184 }
00185 
00186 GraphicsPath *
00187 nsSVGGDIPlusPathGeometry::GetFill()
00188 {
00189   if (mFill) return mFill;
00190   GraphicsPath *path = GetPath();
00191   if (!path) return nsnull;
00192 
00193   mFill = path->Clone();
00194   Matrix m;
00195   GetGlobalTransform(&m);
00196   mFill->Flatten(&m);
00197 
00198   return mFill;
00199 }
00200 
00201 GraphicsPath *
00202 nsSVGGDIPlusPathGeometry::GetStroke()
00203 {
00204   if (mStroke) return mStroke;
00205   GraphicsPath *path = GetPath();
00206   if (!path) return nsnull;
00207 
00208   float width;
00209   mSource->GetStrokeWidth(&width);
00210   if (width==0.0f) return nsnull;
00211   
00212   mStroke = path->Clone();
00213 
00214   // construct the pen:
00215 
00216   // gdi+ seems to widen paths to >1 width unit. If our pen width is
00217   // smaller, we need to widen an appropriately enlarged path and then
00218   // scale it down after widening:
00219   PRBool scaleToUnitPen = width<1.0f;
00220   
00221   Pen pen(Color(), scaleToUnitPen ? 1.0f : width);
00222 
00223   // set linecap style
00224   PRUint16 capStyle;
00225   LineCap lcap;
00226   DashCap dcap;
00227   mSource->GetStrokeLinecap(&capStyle);
00228   switch (capStyle) {
00229     case nsISVGGeometrySource::STROKE_LINECAP_BUTT:
00230       lcap = LineCapFlat;
00231       dcap = DashCapFlat;
00232       break;
00233     case nsISVGGeometrySource::STROKE_LINECAP_ROUND:
00234       lcap = LineCapRound;
00235       dcap = DashCapRound;
00236       break;
00237     case nsISVGGeometrySource::STROKE_LINECAP_SQUARE:
00238       lcap = LineCapSquare;
00239       dcap = DashCapFlat;
00240       break;
00241   }
00242   pen.SetLineCap(lcap, lcap, dcap);
00243 
00244   // set miterlimit:
00245   float miterlimit;
00246   mSource->GetStrokeMiterlimit(&miterlimit);
00247   pen.SetMiterLimit(miterlimit);
00248 
00249   // set linejoin style:
00250   PRUint16 joinStyle;
00251   LineJoin join;
00252   mSource->GetStrokeLinejoin(&joinStyle);
00253   switch(joinStyle) {
00254     case nsISVGGeometrySource::STROKE_LINEJOIN_MITER:
00255       join = LineJoinMiterClipped;
00256       break;
00257     case nsISVGGeometrySource::STROKE_LINEJOIN_ROUND:
00258       join = LineJoinRound;
00259       break;
00260     case nsISVGGeometrySource::STROKE_LINEJOIN_BEVEL:
00261       join = LineJoinBevel;
00262       break;
00263   }
00264   pen.SetLineJoin(join);
00265   
00266   // set pen dashpattern
00267   float *dashArray;
00268   PRUint32 count;
00269   mSource->GetStrokeDashArray(&dashArray, &count);
00270   if (count>0) {
00271     if (!scaleToUnitPen) {
00272       for (PRUint32 i=0; i<count; ++i)
00273         dashArray[i]/=width;
00274     }
00275     
00276     pen.SetDashPattern(dashArray, count);
00277     nsMemory::Free(dashArray);
00278 
00279     float offset;
00280     mSource->GetStrokeDashoffset(&offset);
00281     if (!scaleToUnitPen)
00282       offset/=width;
00283     pen.SetDashOffset(offset);
00284   }
00285   
00286   Matrix m;
00287   GetGlobalTransform(&m);
00288 
00289   if (scaleToUnitPen) {
00290     Matrix enlarge(1/width, 0, 0, 1/width, 0, 0);
00291     mStroke->Transform(&enlarge);
00292     m.Scale(width,width);
00293   }
00294   
00295   mStroke->Widen(&pen, &m);
00296 
00297   
00298 //  mStroke->Outline();
00299 //  mStroke->Transform(&m);
00300   
00301   return mStroke;
00302 }
00303 
00304 Region *
00305 nsSVGGDIPlusPathGeometry::GetHitTestRegion()
00306 {
00307   if (mHitTestRegion) return mHitTestRegion;
00308 
00309   mHitTestRegion = new Region();
00310   if (!mHitTestRegion) {
00311     NS_ERROR("could not construct region");
00312     return nsnull;
00313   }
00314 
00315   mHitTestRegion->MakeEmpty();
00316 
00317   PRUint16 mask=0;
00318   mSource->GetHittestMask(&mask);
00319   if (mask & nsISVGPathGeometrySource::HITTEST_MASK_FILL) {
00320     GraphicsPath *fill = GetFill();
00321     if (fill)
00322       mHitTestRegion->Union(fill);
00323   }
00324   if (mask & nsISVGPathGeometrySource::HITTEST_MASK_STROKE) {
00325     GraphicsPath *stroke = GetStroke();
00326     if (stroke)
00327       mHitTestRegion->Union(stroke);
00328   }
00329 
00330   return mHitTestRegion;
00331 }
00332 
00333 
00334 void
00335 nsSVGGDIPlusPathGeometry::GetGlobalTransform(Matrix *matrix)
00336 {
00337   nsCOMPtr<nsIDOMSVGMatrix> ctm;
00338   mSource->GetCanvasTM(getter_AddRefs(ctm));
00339   NS_ASSERTION(ctm, "graphic source didn't specify a ctm");
00340   
00341   float m[6];
00342   float val;
00343   ctm->GetA(&val);
00344   m[0] = val;
00345   
00346   ctm->GetB(&val);
00347   m[1] = val;
00348   
00349   ctm->GetC(&val);  
00350   m[2] = val;  
00351   
00352   ctm->GetD(&val);  
00353   m[3] = val;  
00354   
00355   ctm->GetE(&val);
00356   m[4] = val;
00357   
00358   ctm->GetF(&val);
00359   m[5] = val;
00360 
00361   matrix->SetElements(m[0],m[1],m[2],m[3],m[4],m[5]);
00362 }
00363 
00364 void
00365 nsSVGGDIPlusPathGeometry::RenderPath(GraphicsPath *path, nscolor color, float opacity,
00366                                      nsISVGGDIPlusCanvas *canvas)
00367 {
00368   SolidBrush brush(Color((BYTE)(opacity*255),NS_GET_R(color),NS_GET_G(color),NS_GET_B(color)));
00369   canvas->GetGraphics()->FillPath(&brush, path);
00370 }
00371 
00372 //----------------------------------------------------------------------
00373 // nsISVGRendererPathGeometry methods:
00374 
00375 static void gradCBFill(Graphics *gfx, Brush *brush, void *cbStruct)
00376 {
00377   nsSVGGDIPlusPathGeometry *geom = (nsSVGGDIPlusPathGeometry *)cbStruct;
00378   gfx->FillPath(brush, geom->GetFill());
00379 }
00380 
00381 static void gradCBStroke(Graphics *gfx, Brush *brush, void *cbStruct)
00382 {
00383   nsSVGGDIPlusPathGeometry *geom = (nsSVGGDIPlusPathGeometry *)cbStruct;
00384   gfx->FillPath(brush, geom->GetStroke());
00385 }
00386 
00388 NS_IMETHODIMP
00389 nsSVGGDIPlusPathGeometry::Render(nsISVGRendererCanvas *canvas)
00390 {
00391   nsCOMPtr<nsISVGGDIPlusCanvas> gdiplusCanvas = do_QueryInterface(canvas);
00392   NS_ASSERTION(gdiplusCanvas, "wrong svg render context for geometry!");
00393   if (!gdiplusCanvas) return NS_ERROR_FAILURE;
00394 
00395   PRUint16 canvasRenderMode;
00396   canvas->GetRenderMode(&canvasRenderMode);
00397   if (canvasRenderMode == nsISVGRendererCanvas::SVG_RENDER_MODE_CLIP) {
00398     Region *region = gdiplusCanvas->GetClipRegion();
00399     GraphicsPath *path = GetFill();
00400 
00401     PRUint16 rule;
00402     mSource->GetClipRule(&rule);
00403     if (rule == nsISVGGeometrySource::FILL_RULE_EVENODD)
00404       path->SetFillMode(FillModeAlternate);
00405     else
00406       path->SetFillMode(FillModeWinding);
00407 
00408     region->Union(path);
00409     return NS_OK;
00410   }
00411 
00412   PRUint16 renderingMode;
00413   mSource->GetShapeRendering(&renderingMode);
00414   switch (renderingMode) {
00415     case nsISVGPathGeometrySource::SHAPE_RENDERING_OPTIMIZESPEED:
00416     case nsISVGPathGeometrySource::SHAPE_RENDERING_CRISPEDGES:
00417       gdiplusCanvas->GetGraphics()->SetSmoothingMode(SmoothingModeNone);
00418       break;
00419     default:
00420       gdiplusCanvas->GetGraphics()->SetSmoothingMode(SmoothingModeAntiAlias);
00421       break;
00422   }
00423   
00424   gdiplusCanvas->GetGraphics()->SetCompositingQuality(CompositingQualityHighSpeed);
00425 //  gdiplusCanvas->GetGraphics()->SetPixelOffsetMode(PixelOffsetModeHalf);
00426 
00427   nscolor color;
00428   float opacity;
00429   PRUint16 type, serverType = 0;
00430   
00431   // paint fill:
00432   mSource->GetFillPaintType(&type);
00433   if (type == nsISVGGeometrySource::PAINT_TYPE_SERVER) {
00434       if(NS_FAILED(mSource->GetFillPaintServerType(&serverType)))
00435         type = nsISVGGeometrySource::PAINT_TYPE_NONE;
00436   }
00437   if (type != nsISVGGeometrySource::PAINT_TYPE_NONE && GetFill()) {
00438     if (type == nsISVGGeometrySource::PAINT_TYPE_SOLID_COLOR) {
00439       mSource->GetFillPaint(&color);
00440       mSource->GetFillOpacity(&opacity);
00441       RenderPath(GetFill(), color, opacity, gdiplusCanvas);
00442     } else {
00443       if (serverType == nsISVGGeometrySource::PAINT_TYPE_GRADIENT) {
00444         nsCOMPtr<nsISVGGradient> aGrad;
00445         mSource->GetFillGradient(getter_AddRefs(aGrad));
00446 
00447         nsCOMPtr<nsISVGRendererRegion> region;
00448         GetCoveredRegion(getter_AddRefs(region));
00449         nsCOMPtr<nsISVGGDIPlusRegion> aRegion = do_QueryInterface(region);
00450         nsCOMPtr<nsIDOMSVGMatrix> ctm;
00451         mSource->GetCanvasTM(getter_AddRefs(ctm));
00452 
00453         GDIPlusGradient(aRegion, aGrad, ctm, gdiplusCanvas->GetGraphics(),
00454                         mSource, gradCBFill, this);
00455       }
00456     }
00457   }
00458 
00459   // paint stroke:
00460   mSource->GetStrokePaintType(&type);
00461   if (type == nsISVGGeometrySource::PAINT_TYPE_SERVER) {
00462       if(NS_FAILED(mSource->GetStrokePaintServerType(&serverType)))
00463         type = nsISVGGeometrySource::PAINT_TYPE_NONE;
00464   }
00465   if (type != nsISVGGeometrySource::PAINT_TYPE_NONE && GetStroke()) {
00466     if (type == nsISVGGeometrySource::PAINT_TYPE_SOLID_COLOR) {
00467       mSource->GetStrokePaint(&color);
00468       mSource->GetStrokeOpacity(&opacity);
00469       RenderPath(GetStroke(), color, opacity, gdiplusCanvas);
00470     } else {
00471       if (serverType == nsISVGGeometrySource::PAINT_TYPE_GRADIENT) {
00472         nsCOMPtr<nsISVGGradient> aGrad;
00473         mSource->GetStrokeGradient(getter_AddRefs(aGrad));
00474 
00475         nsCOMPtr<nsISVGRendererRegion> region;
00476         GetCoveredRegion(getter_AddRefs(region));
00477         nsCOMPtr<nsISVGGDIPlusRegion> aRegion = do_QueryInterface(region);
00478         nsCOMPtr<nsIDOMSVGMatrix> ctm;
00479         mSource->GetCanvasTM(getter_AddRefs(ctm));
00480 
00481         GDIPlusGradient(aRegion, aGrad, ctm, gdiplusCanvas->GetGraphics(),
00482                         mSource, gradCBStroke, this);
00483       }
00484     }
00485   }
00486   
00487   return NS_OK;
00488 }
00489 
00491 NS_IMETHODIMP
00492 nsSVGGDIPlusPathGeometry::Update(PRUint32 updatemask, nsISVGRendererRegion **_retval)
00493 {
00494   *_retval = nsnull;
00495 
00496   const unsigned long pathmask =
00497     nsISVGGeometrySource::UPDATEMASK_FILL_RULE |
00498     nsISVGPathGeometrySource::UPDATEMASK_PATH;
00499 
00500   const unsigned long fillmask = 
00501     pathmask |
00502     nsISVGGeometrySource::UPDATEMASK_CANVAS_TM;
00503 
00504   const unsigned long strokemask =
00505     pathmask |
00506     nsISVGGeometrySource::UPDATEMASK_STROKE_WIDTH       |
00507     nsISVGGeometrySource::UPDATEMASK_STROKE_LINECAP     |
00508     nsISVGGeometrySource::UPDATEMASK_STROKE_LINEJOIN    |
00509     nsISVGGeometrySource::UPDATEMASK_STROKE_MITERLIMIT  |
00510     nsISVGGeometrySource::UPDATEMASK_STROKE_DASH_ARRAY  |
00511     nsISVGGeometrySource::UPDATEMASK_STROKE_DASHOFFSET  |
00512     nsISVGGeometrySource::UPDATEMASK_CANVAS_TM;
00513 
00514   const unsigned long hittestregionmask =
00515     fillmask                                            |
00516     strokemask                                          |
00517     nsISVGPathGeometrySource::UPDATEMASK_HITTEST_MASK;
00518 
00519   const unsigned long coveredregionmask =
00520     fillmask                                            |
00521     strokemask                                          |
00522     nsISVGGeometrySource::UPDATEMASK_FILL_PAINT_TYPE    |
00523     nsISVGGeometrySource::UPDATEMASK_STROKE_PAINT_TYPE;
00524   
00525   nsCOMPtr<nsISVGRendererRegion> before;
00526   // only obtain the 'before' region if we have built a path before:
00527   if (mFill || mStroke)
00528     GetCoveredRegion(getter_AddRefs(before));
00529 
00530   if ((updatemask & pathmask)!=0)
00531     ClearPath();
00532   if ((updatemask & fillmask)!=0)
00533     ClearFill();
00534   if ((updatemask & strokemask)!=0)
00535     ClearStroke();
00536   if ((updatemask & hittestregionmask)!=0)
00537     ClearHitTestRegion();
00538   if ((updatemask & coveredregionmask)!=0) {
00539     ClearCoveredRegion();
00540     nsCOMPtr<nsISVGRendererRegion> after;
00541     GetCoveredRegion(getter_AddRefs(after));
00542     if (after)
00543       after->Combine(before, _retval);
00544   }
00545 
00546   if (!*_retval) {
00547     *_retval = before;
00548     NS_IF_ADDREF(*_retval);
00549   }
00550   return NS_OK;
00551 }
00552 
00554 NS_IMETHODIMP
00555 nsSVGGDIPlusPathGeometry::GetCoveredRegion(nsISVGRendererRegion **_retval)
00556 {
00557   *_retval = nsnull;
00558   
00559   if (mCoveredRegion) {
00560     *_retval = mCoveredRegion;
00561     NS_ADDREF(*_retval);
00562     return NS_OK;
00563   }
00564   
00565   PRUint16 type;  
00566   mSource->GetFillPaintType(&type);
00567   bool hasCoveredFill = (type!=nsISVGGeometrySource::PAINT_TYPE_NONE) && GetFill();
00568   
00569   mSource->GetStrokePaintType(&type);
00570   bool hasCoveredStroke = (type!=nsISVGGeometrySource::PAINT_TYPE_NONE) && GetStroke();
00571 
00572   if (!hasCoveredFill && !hasCoveredStroke) return NS_OK;
00573 
00574   if (hasCoveredFill) {
00575     nsCOMPtr<nsISVGRendererRegion> reg1;
00576     NS_NewSVGGDIPlusPathRegion(getter_AddRefs(reg1), GetFill());
00577     if (hasCoveredStroke) {
00578       nsCOMPtr<nsISVGRendererRegion> reg2;
00579       NS_NewSVGGDIPlusPathRegion(getter_AddRefs(reg2), GetStroke());
00580       reg1->Combine(reg2, _retval);
00581     }
00582     else {
00583       *_retval = reg1;
00584       NS_ADDREF(*_retval);
00585     }
00586   } // covered stroke only
00587   else
00588     NS_NewSVGGDIPlusPathRegion(_retval, GetStroke());
00589 
00590   mCoveredRegion = *_retval;
00591   return NS_OK;
00592 }
00593 
00595 NS_IMETHODIMP
00596 nsSVGGDIPlusPathGeometry::ContainsPoint(float x, float y, PRBool *_retval)
00597 {
00598   *_retval = PR_FALSE;
00599   
00600    if (GetHitTestRegion()->IsVisible(x,y)) {
00601      *_retval = PR_TRUE;
00602    }
00603   
00604   return NS_OK;
00605 }
00606 
00607 NS_IMETHODIMP
00608 nsSVGGDIPlusPathGeometry::GetBoundingBox(nsIDOMSVGRect * *aBoundingBox)
00609 {
00610   *aBoundingBox = nsnull;
00611 
00612   GraphicsPath *path = GetFill();
00613   if (!path)
00614     return NS_ERROR_FAILURE;
00615 
00616   nsCOMPtr<nsIDOMSVGRect> rect = do_CreateInstance(NS_SVGRECT_CONTRACTID);
00617 
00618   NS_ASSERTION(rect, "could not create rect");
00619   if (!rect)
00620     return NS_ERROR_FAILURE;
00621 
00622   RectF bounds;
00623   path->GetBounds(&bounds);
00624 
00625   rect->SetX(bounds.X);
00626   rect->SetY(bounds.Y);
00627   rect->SetWidth(bounds.Width);
00628   rect->SetHeight(bounds.Height);
00629 
00630   *aBoundingBox = rect;
00631   NS_ADDREF(*aBoundingBox);
00632   
00633   return NS_OK;
00634 }
00635 
00636 NS_IMETHODIMP
00637 nsSVGGDIPlusPathGeometry::Flatten(nsSVGPathData **aData)
00638 {
00639   *aData = nsnull;
00640 
00641   GraphicsPath *path = GetPath();
00642   if (!path)
00643     return NS_ERROR_FAILURE;
00644 
00645   PathData pdata;
00646   path->Flatten();
00647   path->GetPathData(&pdata);
00648 
00649   *aData = new nsSVGPathData;
00650 
00651   for (PRInt32 i = 0; i < pdata.Count; i++) {
00652     switch (pdata.Types[i] & PathPointTypePathTypeMask) {
00653     case PathPointTypeStart:
00654       (*aData)->AddPoint(pdata.Points[i].X,
00655                          pdata.Points[i].Y,
00656                          NS_SVGPATHFLATTEN_MOVE);
00657       break;
00658     case PathPointTypeLine:
00659       (*aData)->AddPoint(pdata.Points[i].X,
00660                          pdata.Points[i].Y,
00661                          NS_SVGPATHFLATTEN_LINE);
00662       break;
00663     default:
00664       /* should never happen with a flattened path */
00665       break;
00666     }
00667     
00668     if ((pdata.Types[i] & PathPointTypeCloseSubpath) &&
00669         (*aData)->count) {
00670       /* find beginning of current subpath */
00671       for (PRUint32 k = (*aData)->count - 1; k >= 0; k--)
00672         if ((*aData)->type[k] == NS_SVGPATHFLATTEN_MOVE) {
00673           (*aData)->AddPoint((*aData)->x[k],
00674                              (*aData)->y[k],
00675                              NS_SVGPATHFLATTEN_LINE);
00676           break;
00677         }
00678     }
00679   }
00680 
00681   return NS_OK;
00682 }