00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #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
00076 NS_DECL_ISUPPORTS
00077
00078
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
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
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
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
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
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
00236
00237
00238
00239
00240
00241 double flatness = 0.5;
00242
00243 nsCOMPtr<nsIPref> prefs(do_GetService(NS_PREF_CONTRACTID));
00244 if (!prefs) return flatness;
00245
00246
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
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
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
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 }
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 }