Back to index

lightning-sunbird  0.9+nobinonly
nsSVGPathGeometryFrame.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 "nsSVGPathGeometryFrame.h"
00040 #include "nsIDOMSVGDocument.h"
00041 #include "nsIDOMElement.h"
00042 #include "nsIDocument.h"
00043 #include "nsISVGRenderer.h"
00044 #include "nsISVGRendererRegion.h"
00045 #include "nsISVGValueUtils.h"
00046 #include "nsISVGGeometrySource.h"
00047 #include "nsIDOMSVGTransformable.h"
00048 #include "nsIDOMSVGAnimTransformList.h"
00049 #include "nsIDOMSVGTransformList.h"
00050 #include "nsISVGContainerFrame.h"
00051 #include "nsReadableUtils.h"
00052 #include "nsUnicharUtils.h"
00053 #include "nsSVGAtoms.h"
00054 #include "nsCRT.h"
00055 #include "prdtoa.h"
00056 #include "nsSVGMarkerFrame.h"
00057 #include "nsISVGMarkable.h"
00058 #include "nsIViewManager.h"
00059 #include "nsSVGMatrix.h"
00060 #include "nsSVGClipPathFrame.h"
00061 #include "nsISVGRendererCanvas.h"
00062 #include "nsIViewManager.h"
00063 #include "nsSVGUtils.h"
00064 
00066 // nsSVGPathGeometryFrame
00067 
00068 nsSVGPathGeometryFrame::nsSVGPathGeometryFrame()
00069   : mUpdateFlags(0), mPropagateTransform(PR_TRUE),
00070     mFillGradient(nsnull), mStrokeGradient(nsnull)
00071 {
00072 #ifdef DEBUG
00073 //  printf("nsSVGPathGeometryFrame %p CTOR\n", this);
00074 #endif
00075 }
00076 
00077 nsSVGPathGeometryFrame::~nsSVGPathGeometryFrame()
00078 {
00079 #ifdef DEBUG
00080 //  printf("~nsSVGPathGeometryFrame %p\n", this);
00081 #endif
00082   
00083   nsCOMPtr<nsIDOMSVGTransformable> transformable = do_QueryInterface(mContent);
00084   NS_ASSERTION(transformable, "wrong content element");
00085   nsCOMPtr<nsIDOMSVGAnimatedTransformList> transforms;
00086   transformable->GetTransform(getter_AddRefs(transforms));
00087   NS_REMOVE_SVGVALUE_OBSERVER(transforms);
00088   if (mFillGradient) {
00089     NS_REMOVE_SVGVALUE_OBSERVER(mFillGradient);
00090   }
00091   if (mStrokeGradient) {
00092     NS_REMOVE_SVGVALUE_OBSERVER(mStrokeGradient);
00093   }
00094 }
00095 
00096 //----------------------------------------------------------------------
00097 // nsISupports methods
00098 
00099 NS_INTERFACE_MAP_BEGIN(nsSVGPathGeometryFrame)
00100   NS_INTERFACE_MAP_ENTRY(nsISVGGeometrySource)
00101   NS_INTERFACE_MAP_ENTRY(nsISVGPathGeometrySource)
00102   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00103   NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
00104   NS_INTERFACE_MAP_ENTRY(nsISVGChildFrame)
00105 NS_INTERFACE_MAP_END_INHERITING(nsSVGPathGeometryFrameBase)
00106 
00107 //----------------------------------------------------------------------
00108 // nsIFrame methods
00109   
00110 NS_IMETHODIMP
00111 nsSVGPathGeometryFrame::Init(nsPresContext*  aPresContext,
00112                              nsIContent*      aContent,
00113                              nsIFrame*        aParent,
00114                              nsStyleContext*  aContext,
00115                              nsIFrame*        aPrevInFlow)
00116 {
00117   mContent = aContent;
00118   NS_IF_ADDREF(mContent);
00119   mParent = aParent;
00120 
00121   if (mContent) {
00122     mContent->SetMayHaveFrame(PR_TRUE);
00123   }
00124   
00125   InitSVG();
00126   
00127   SetStyleContext(aPresContext, aContext);
00128     
00129   return NS_OK;
00130 }
00131 
00132 NS_IMETHODIMP
00133 nsSVGPathGeometryFrame::AttributeChanged(nsIContent*     aChild,
00134                                          PRInt32         aNameSpaceID,
00135                                          nsIAtom*        aAttribute,
00136                                          PRInt32         aModType)
00137 {
00138   // we don't use this notification mechanism
00139   
00140 #ifdef DEBUG
00141 //  printf("** nsSVGPathGeometryFrame::AttributeChanged(");
00142 //  nsAutoString str;
00143 //  aAttribute->ToString(str);
00144 //  nsCAutoString cstr;
00145 //  cstr.AssignWithConversion(str);
00146 //  printf(cstr.get());
00147 //  printf(")\n");
00148 #endif
00149   
00150   return NS_OK;
00151 }
00152 
00153 NS_IMETHODIMP
00154 nsSVGPathGeometryFrame::DidSetStyleContext(nsPresContext* aPresContext)
00155 {
00156   // One of the styles that might have been changed are the urls that
00157   // point to gradients, etc.  Drop our cached values to those
00158   if (mFillGradient) {
00159     NS_REMOVE_SVGVALUE_OBSERVER(mFillGradient);
00160     mFillGradient = nsnull;
00161   }
00162   if (mStrokeGradient) {
00163     NS_REMOVE_SVGVALUE_OBSERVER(mStrokeGradient);
00164     mStrokeGradient = nsnull;
00165   }
00166 
00167   // XXX: we'd like to use the style_hint mechanism and the
00168   // ContentStateChanged/AttributeChanged functions for style changes
00169   // to get slightly finer granularity, but unfortunately the
00170   // style_hints don't map very well onto svg. Here seems to be the
00171   // best place to deal with style changes:
00172 
00173   UpdateGraphic(nsISVGGeometrySource::UPDATEMASK_ALL);
00174 
00175   return NS_OK;
00176 }
00177 
00178 nsIAtom *
00179 nsSVGPathGeometryFrame::GetType() const
00180 {
00181   return nsLayoutAtoms::svgPathGeometryFrame;
00182 }
00183 
00184 PRBool
00185 nsSVGPathGeometryFrame::IsFrameOfType(PRUint32 aFlags) const
00186 {
00187   return !(aFlags & ~nsIFrame::eSVG);
00188 }
00189 
00190 //----------------------------------------------------------------------
00191 // nsISVGChildFrame methods
00192 
00193 // marker helper
00194 void
00195 nsSVGPathGeometryFrame::GetMarkerFrames(nsSVGMarkerFrame **markerStart,
00196                                         nsSVGMarkerFrame **markerMid,
00197                                         nsSVGMarkerFrame **markerEnd)
00198 {
00199   nsIURI *aURI;
00200 
00201   *markerStart = *markerMid = *markerEnd = NULL;
00202   
00203   aURI = GetStyleSVG()->mMarkerEnd;
00204   if (aURI)
00205     NS_GetSVGMarkerFrame(markerEnd, aURI, mContent);
00206     
00207   aURI = GetStyleSVG()->mMarkerMid;
00208   if (aURI)
00209     NS_GetSVGMarkerFrame(markerMid, aURI, mContent);
00210   
00211   aURI = GetStyleSVG()->mMarkerStart;
00212   if (aURI)
00213     NS_GetSVGMarkerFrame(markerStart, aURI, mContent);
00214 }
00215 
00216 NS_IMETHODIMP
00217 nsSVGPathGeometryFrame::PaintSVG(nsISVGRendererCanvas* canvas, const nsRect& dirtyRectTwips)
00218 {
00219   if (!GetStyleVisibility()->IsVisible())
00220     return NS_OK;
00221 
00222   /* check for a clip path */
00223 
00224   nsIURI *aURI;
00225   nsSVGClipPathFrame *clip = NULL;
00226   aURI = GetStyleSVGReset()->mClipPath;
00227   if (aURI) {
00228     NS_GetSVGClipPathFrame(&clip, aURI, mContent);
00229 
00230     if (clip) {
00231       nsCOMPtr<nsIDOMSVGMatrix> matrix;
00232       GetCanvasTM(getter_AddRefs(matrix));
00233       canvas->PushClip();
00234       clip->ClipPaint(canvas, this, matrix);
00235     }
00236 
00237 #ifdef DEBUG_tor    
00238     nsCAutoString spec;
00239     aURI->GetAsciiSpec(spec);
00240     fprintf(stderr, "CLIPPATH %s %p\n", spec.get(), clip);
00241 #endif
00242   }
00243 
00244   /* render */
00245   GetGeometry()->Render(canvas);
00246   
00247   nsISVGMarkable *markable;
00248   CallQueryInterface(this, &markable);
00249 
00250   if (markable) {
00251     nsSVGMarkerFrame *markerEnd, *markerMid, *markerStart;
00252     GetMarkerFrames(&markerStart, &markerMid, &markerEnd);
00253 
00254     if (markerEnd || markerMid || markerStart) {
00255       // need to set this up with the first draw
00256       if (!mMarkerRegion)
00257         mMarkerRegion = GetCoveredRegion();
00258 
00259       float strokeWidth;
00260       GetStrokeWidth(&strokeWidth);
00261       
00262       nsVoidArray marks;
00263       markable->GetMarkPoints(&marks);
00264     
00265       PRUint32 num = marks.Count();
00266       
00267       if (num && markerStart)
00268         markerStart->PaintMark(canvas, this, (nsSVGMark *)marks[0], strokeWidth);
00269       
00270       if (num && markerMid)
00271         for (PRUint32 i = 1; i < num - 1; i++)
00272           markerMid->PaintMark(canvas, this, (nsSVGMark *)marks[i], strokeWidth);
00273 
00274       if (num && markerEnd)
00275         markerEnd->PaintMark(canvas, this, (nsSVGMark *)marks[num-1], strokeWidth);
00276     }
00277   }
00278 
00279   if (clip)
00280     canvas->PopClip();
00281 
00282   return NS_OK;
00283 }
00284 
00285 NS_IMETHODIMP
00286 nsSVGPathGeometryFrame::GetFrameForPointSVG(float x, float y, nsIFrame** hit)
00287 {
00288 #ifdef DEBUG
00289   //printf("nsSVGPathGeometryFrame(%p)::GetFrameForPoint\n", this);
00290 #endif
00291 
00292   // test for hit:
00293   *hit = nsnull;
00294   PRBool isHit;
00295   GetGeometry()->ContainsPoint(x, y, &isHit);
00296 
00297   if (isHit) {
00298     PRBool clipHit = PR_TRUE;;
00299 
00300     nsIURI *aURI;
00301     nsSVGClipPathFrame *clip = NULL;
00302     aURI = GetStyleSVGReset()->mClipPath;
00303     if (aURI)
00304       NS_GetSVGClipPathFrame(&clip, aURI, mContent);
00305 
00306     if (clip) {
00307       nsCOMPtr<nsIDOMSVGMatrix> matrix;
00308       GetCanvasTM(getter_AddRefs(matrix));
00309       clip->ClipHitTest(this, matrix, x, y, &clipHit);
00310     }
00311 
00312     if (clipHit)
00313       *hit = this;
00314   }
00315   
00316   return NS_OK;
00317 }
00318 
00319 NS_IMETHODIMP_(already_AddRefed<nsISVGRendererRegion>)
00320 nsSVGPathGeometryFrame::GetCoveredRegion()
00321 {
00322   if (!GetGeometry())
00323     return nsnull;
00324 
00325   nsCOMPtr<nsISVGRendererRegion> region;
00326   GetGeometry()->GetCoveredRegion(getter_AddRefs(region));
00327 
00328   nsISVGMarkable *markable;
00329   CallQueryInterface(this, &markable);
00330 
00331   if (markable) {
00332     nsSVGMarkerFrame *markerEnd, *markerMid, *markerStart;
00333     GetMarkerFrames(&markerStart, &markerMid, &markerEnd);
00334 
00335     if (markerEnd || markerMid || markerStart) {
00336       float strokeWidth;
00337       GetStrokeWidth(&strokeWidth);
00338 
00339       nsVoidArray marks;
00340       markable->GetMarkPoints(&marks);
00341 
00342       PRUint32 num = marks.Count();
00343 
00344       if (num && markerStart) {
00345         nsCOMPtr<nsISVGRendererRegion> mark;
00346         mark = markerStart->RegionMark(this, (nsSVGMark *)marks[0], strokeWidth);
00347 
00348         if (!region) {
00349           region = mark;
00350         } else if (mark) {
00351           nsCOMPtr<nsISVGRendererRegion> tmp = region;
00352           mark->Combine(tmp, getter_AddRefs(region));
00353         }
00354       }
00355 
00356       if (num && markerMid)
00357         for (PRUint32 i = 1; i < num - 1; i++) {
00358           nsCOMPtr<nsISVGRendererRegion> mark;
00359           mark = markerMid->RegionMark(this, (nsSVGMark *)marks[i], strokeWidth);
00360 
00361           if (!region) {
00362             region = mark;
00363           } else if (mark) {
00364             nsCOMPtr<nsISVGRendererRegion> tmp = region;
00365             mark->Combine(tmp, getter_AddRefs(region));
00366           }
00367         }
00368 
00369       if (num && markerEnd) {
00370         nsCOMPtr<nsISVGRendererRegion> mark;
00371         mark = markerEnd->RegionMark(this, (nsSVGMark *)marks[num-1], strokeWidth);
00372 
00373         if (!region) {
00374           region = mark;
00375         } else if (mark) {
00376           nsCOMPtr<nsISVGRendererRegion> tmp = region;
00377           mark->Combine(tmp, getter_AddRefs(region));
00378         }
00379       }
00380     }
00381   }
00382 
00383   nsISVGRendererRegion *retval = nsnull;
00384   region.swap(retval);
00385   return retval;
00386 }
00387 
00388 NS_IMETHODIMP
00389 nsSVGPathGeometryFrame::InitialUpdate()
00390 {
00391   UpdateGraphic(nsISVGGeometrySource::UPDATEMASK_ALL);
00392 
00393   return NS_OK;
00394 }
00395 
00396 NS_IMETHODIMP
00397 nsSVGPathGeometryFrame::NotifyCanvasTMChanged()
00398 {
00399   UpdateGraphic(nsISVGGeometrySource::UPDATEMASK_CANVAS_TM);
00400   
00401   return NS_OK;
00402 }
00403 
00404 NS_IMETHODIMP
00405 nsSVGPathGeometryFrame::NotifyRedrawSuspended()
00406 {
00407   // XXX should we cache the fact that redraw is suspended?
00408   return NS_OK;
00409 }
00410 
00411 NS_IMETHODIMP
00412 nsSVGPathGeometryFrame::NotifyRedrawUnsuspended()
00413 {
00414   if (mUpdateFlags != 0)
00415     UpdateGraphic(0);
00416 
00417   return NS_OK;
00418 }
00419 
00420 NS_IMETHODIMP
00421 nsSVGPathGeometryFrame::SetMatrixPropagation(PRBool aPropagate)
00422 {
00423   mPropagateTransform = aPropagate;
00424   return NS_OK;
00425 }
00426 
00427 NS_IMETHODIMP
00428 nsSVGPathGeometryFrame::GetBBox(nsIDOMSVGRect **_retval)
00429 {
00430   if (GetGeometry())
00431     return GetGeometry()->GetBoundingBox(_retval);
00432   return NS_ERROR_FAILURE;
00433 }
00434 
00435 //----------------------------------------------------------------------
00436 // nsISVGValueObserver methods:
00437 
00438 NS_IMETHODIMP
00439 nsSVGPathGeometryFrame::WillModifySVGObservable(nsISVGValue* observable,
00440                                                 nsISVGValue::modificationType aModType)
00441 {
00442   return NS_OK;
00443 }
00444 
00445 
00446 NS_IMETHODIMP
00447 nsSVGPathGeometryFrame::DidModifySVGObservable (nsISVGValue* observable,
00448                                                 nsISVGValue::modificationType aModType)
00449 {
00450   // Is this a gradient?
00451   nsCOMPtr<nsISVGGradient>val = do_QueryInterface(observable);
00452   if (val) {
00453     // Yes, we need to handle this differently
00454     nsCOMPtr<nsISVGGradient>fill = do_QueryInterface(mFillGradient);
00455     if (fill == val) {
00456       if (aModType == nsISVGValue::mod_die) {
00457         mFillGradient = nsnull;
00458       }
00459       UpdateGraphic(nsISVGGeometrySource::UPDATEMASK_FILL_PAINT);
00460     } else {
00461       // No real harm in assuming a stroke gradient at this point
00462       if (aModType == nsISVGValue::mod_die) {
00463         mStrokeGradient = nsnull;
00464       }
00465       UpdateGraphic(nsISVGGeometrySource::UPDATEMASK_STROKE_PAINT);
00466     }
00467   } else {
00468     // No, all of our other observables update the canvastm by default
00469     UpdateGraphic(nsISVGGeometrySource::UPDATEMASK_CANVAS_TM);
00470   }
00471   return NS_OK;
00472 }
00473 
00474 //----------------------------------------------------------------------
00475 // nsISVGGeometrySource methods:
00476 
00477 /* [noscript] readonly attribute nsPresContext presContext; */
00478 NS_IMETHODIMP
00479 nsSVGPathGeometryFrame::GetPresContext(nsPresContext * *aPresContext)
00480 {
00481   // XXX gcc 3.2.2 requires the explicit 'nsSVGPathGeometryFrameBase::' qualification
00482   *aPresContext = nsSVGPathGeometryFrameBase::GetPresContext();
00483   NS_ADDREF(*aPresContext);
00484   return NS_OK;
00485 }
00486 
00487 /* readonly attribute nsIDOMSVGMatrix canvasTM; */
00488 NS_IMETHODIMP
00489 nsSVGPathGeometryFrame::GetCanvasTM(nsIDOMSVGMatrix * *aCTM)
00490 {
00491   *aCTM = nsnull;
00492 
00493   if (!mPropagateTransform)
00494     return NS_NewSVGMatrix(aCTM);
00495 
00496   nsISVGContainerFrame *containerFrame;
00497   mParent->QueryInterface(NS_GET_IID(nsISVGContainerFrame), (void**)&containerFrame);
00498   if (!containerFrame) {
00499     NS_ERROR("invalid container");
00500     return NS_ERROR_FAILURE;
00501   }
00502 
00503   nsCOMPtr<nsIDOMSVGMatrix> parentTM = containerFrame->GetCanvasTM();
00504   NS_ASSERTION(parentTM, "null TM");
00505 
00506   // append our local transformations if we have any:
00507   nsCOMPtr<nsIDOMSVGMatrix> localTM;
00508   {
00509     nsCOMPtr<nsIDOMSVGTransformable> transformable = do_QueryInterface(mContent);
00510     NS_ASSERTION(transformable, "wrong content element");
00511     nsCOMPtr<nsIDOMSVGAnimatedTransformList> atl;
00512     transformable->GetTransform(getter_AddRefs(atl));
00513     NS_ASSERTION(atl, "null animated transform list");
00514     nsCOMPtr<nsIDOMSVGTransformList> transforms;
00515     atl->GetAnimVal(getter_AddRefs(transforms));
00516     NS_ASSERTION(transforms, "null transform list");
00517     PRUint32 numberOfItems;
00518     transforms->GetNumberOfItems(&numberOfItems);
00519     if (numberOfItems>0)
00520       transforms->GetConsolidationMatrix(getter_AddRefs(localTM));
00521   }  
00522   if (localTM) {
00523     return parentTM->Multiply(localTM, aCTM);
00524   }
00525   *aCTM = parentTM;
00526   NS_ADDREF(*aCTM);
00527   return NS_OK;
00528 }
00529 
00530 /* readonly attribute float strokeOpacity; */
00531 NS_IMETHODIMP
00532 nsSVGPathGeometryFrame::GetStrokeOpacity(float *aStrokeOpacity)
00533 {
00534   *aStrokeOpacity =
00535     GetStyleSVG()->mStrokeOpacity * GetStyleDisplay()->mOpacity;
00536   return NS_OK;
00537 }
00538 
00539 /* readonly attribute float strokeWidth; */
00540 NS_IMETHODIMP
00541 nsSVGPathGeometryFrame::GetStrokeWidth(float *aStrokeWidth)
00542 {
00543   *aStrokeWidth =
00544     nsSVGUtils::CoordToFloat(nsSVGPathGeometryFrameBase::GetPresContext(),
00545                              mContent, GetStyleSVG()->mStrokeWidth);
00546   return NS_OK;
00547 }
00548 
00549 /* void getStrokeDashArray ([array, size_is (count)] out float arr, out unsigned long count); */
00550 NS_IMETHODIMP
00551 nsSVGPathGeometryFrame::GetStrokeDashArray(float **arr, PRUint32 *count)
00552 {
00553   const nsStyleCoord *dasharray = GetStyleSVG()->mStrokeDasharray;
00554   nsPresContext *presContext = nsSVGPathGeometryFrameBase::GetPresContext();
00555   float totalLength = 0.0f;
00556 
00557   *count = GetStyleSVG()->mStrokeDasharrayLength;
00558   *arr = nsnull;
00559 
00560   if (*count) {
00561     *arr = (float *) nsMemory::Alloc(*count * sizeof(float));
00562     if (*arr) {
00563       for (PRUint32 i = 0; i < *count; i++) {
00564         (*arr)[i] = nsSVGUtils::CoordToFloat(presContext, mContent, dasharray[i]);
00565         if ((*arr)[i] < 0.0f) {
00566           nsMemory::Free(*arr);
00567           *count = 0;
00568           *arr = nsnull;
00569           return NS_OK;
00570         }
00571         totalLength += (*arr)[i];
00572       }
00573     } else {
00574       *count = 0;
00575       *arr = nsnull;
00576       return NS_ERROR_OUT_OF_MEMORY;
00577     }
00578 
00579     if (totalLength == 0.0f) {
00580       nsMemory::Free(*arr);
00581       *count = 0;
00582     }
00583   }
00584 
00585   return NS_OK;
00586 }
00587 
00588 /* readonly attribute float strokeDashoffset; */
00589 NS_IMETHODIMP
00590 nsSVGPathGeometryFrame::GetStrokeDashoffset(float *aStrokeDashoffset)
00591 {
00592   *aStrokeDashoffset = 
00593     nsSVGUtils::CoordToFloat(nsSVGPathGeometryFrameBase::GetPresContext(),
00594                              mContent, GetStyleSVG()->mStrokeDashoffset);
00595   return NS_OK;
00596 }
00597 
00598 /* readonly attribute unsigned short strokeLinecap; */
00599 NS_IMETHODIMP
00600 nsSVGPathGeometryFrame::GetStrokeLinecap(PRUint16 *aStrokeLinecap)
00601 {
00602   *aStrokeLinecap = GetStyleSVG()->mStrokeLinecap;
00603   return NS_OK;
00604 }
00605 
00606 /* readonly attribute unsigned short strokeLinejoin; */
00607 NS_IMETHODIMP
00608 nsSVGPathGeometryFrame::GetStrokeLinejoin(PRUint16 *aStrokeLinejoin)
00609 {
00610   *aStrokeLinejoin = GetStyleSVG()->mStrokeLinejoin;
00611   return NS_OK;
00612 }
00613 
00614 /* readonly attribute float strokeMiterlimit; */
00615 NS_IMETHODIMP
00616 nsSVGPathGeometryFrame::GetStrokeMiterlimit(float *aStrokeMiterlimit)
00617 {
00618   *aStrokeMiterlimit = GetStyleSVG()->mStrokeMiterlimit;
00619   return NS_OK;
00620 }
00621 
00622 /* readonly attribute float fillOpacity; */
00623 NS_IMETHODIMP
00624 nsSVGPathGeometryFrame::GetFillOpacity(float *aFillOpacity)
00625 {
00626   *aFillOpacity =
00627     GetStyleSVG()->mFillOpacity * GetStyleDisplay()->mOpacity;
00628   return NS_OK;
00629 }
00630 
00631 /* readonly attribute unsigned short fillRule; */
00632 NS_IMETHODIMP
00633 nsSVGPathGeometryFrame::GetFillRule(PRUint16 *aFillRule)
00634 {
00635   *aFillRule = GetStyleSVG()->mFillRule;
00636   return NS_OK;
00637 }
00638 
00639 /* readonly attribute unsigned short clipRule; */
00640 NS_IMETHODIMP
00641 nsSVGPathGeometryFrame::GetClipRule(PRUint16 *aClipRule)
00642 {
00643   *aClipRule = GetStyleSVG()->mClipRule;
00644   return NS_OK;
00645 }
00646 
00647 /* readonly attribute unsigned short strokePaintType; */
00648 NS_IMETHODIMP
00649 nsSVGPathGeometryFrame::GetStrokePaintType(PRUint16 *aStrokePaintType)
00650 {
00651   float strokeWidth;
00652   GetStrokeWidth(&strokeWidth);
00653 
00654   // cairo will stop rendering if stroke-width is less than or equal to zero
00655   *aStrokePaintType = strokeWidth <= 0 ?
00656                       nsISVGGeometrySource::PAINT_TYPE_NONE :
00657                       GetStyleSVG()->mStroke.mType;
00658   return NS_OK;
00659 }
00660 
00661 /* readonly attribute unsigned short strokePaintServerType; */
00662 NS_IMETHODIMP
00663 nsSVGPathGeometryFrame::GetStrokePaintServerType(PRUint16 *aStrokePaintServerType) {
00664   return nsSVGUtils::GetPaintType(aStrokePaintServerType, GetStyleSVG()->mStroke, mContent,
00665                                   nsSVGPathGeometryFrameBase::GetPresContext()->PresShell());
00666 }
00667 
00668 /* [noscript] readonly attribute nscolor strokePaint; */
00669 NS_IMETHODIMP
00670 nsSVGPathGeometryFrame::GetStrokePaint(nscolor *aStrokePaint)
00671 {
00672   *aStrokePaint = GetStyleSVG()->mStroke.mPaint.mColor;
00673   return NS_OK;
00674 }
00675 
00676 /* [noscript] void GetStrokeGradient(nsISVGGradient **aGrad); */
00677 NS_IMETHODIMP
00678 nsSVGPathGeometryFrame::GetStrokeGradient(nsISVGGradient **aGrad)
00679 {
00680   nsresult rv = NS_OK;
00681   if (!mStrokeGradient) {
00682     nsIURI *aServer;
00683     aServer = GetStyleSVG()->mStroke.mPaint.mPaintServer;
00684     if (aServer == nsnull)
00685       return NS_ERROR_FAILURE;
00686     // Now have the URI.  Get the gradient 
00687     rv = NS_GetSVGGradient(getter_AddRefs(mStrokeGradient), aServer, mContent, 
00688                            nsSVGPathGeometryFrameBase::GetPresContext()->PresShell());
00689     NS_ADD_SVGVALUE_OBSERVER(mStrokeGradient);
00690   }
00691   *aGrad = mStrokeGradient;
00692   return rv;
00693 }
00694 
00695 /* readonly attribute unsigned short fillPaintType; */
00696 NS_IMETHODIMP
00697 nsSVGPathGeometryFrame::GetFillPaintType(PRUint16 *aFillPaintType)
00698 {
00699   *aFillPaintType = GetStyleSVG()->mFill.mType;
00700   return NS_OK;
00701 }
00702 
00703 /* readonly attribute unsigned short fillPaintServerType; */
00704 NS_IMETHODIMP
00705 nsSVGPathGeometryFrame::GetFillPaintServerType(PRUint16 *aFillPaintServerType)
00706 {
00707   return nsSVGUtils::GetPaintType(aFillPaintServerType, GetStyleSVG()->mFill, mContent,
00708                                   nsSVGPathGeometryFrameBase::GetPresContext()->PresShell());
00709 }
00710 
00711 /* [noscript] readonly attribute nscolor fillPaint; */
00712 NS_IMETHODIMP
00713 nsSVGPathGeometryFrame::GetFillPaint(nscolor *aFillPaint)
00714 {
00715   *aFillPaint = GetStyleSVG()->mFill.mPaint.mColor;
00716   return NS_OK;
00717 }
00718 
00719 /* [noscript] void GetFillGradient(nsISVGGradient **aGrad); */
00720 NS_IMETHODIMP
00721 nsSVGPathGeometryFrame::GetFillGradient(nsISVGGradient **aGrad)
00722 {
00723   nsresult rv = NS_OK;
00724   if (!mFillGradient) {
00725     nsIURI *aServer;
00726     aServer = GetStyleSVG()->mFill.mPaint.mPaintServer;
00727     if (aServer == nsnull)
00728       return NS_ERROR_FAILURE;
00729     // Now have the URI.  Get the gradient 
00730     rv = NS_GetSVGGradient(getter_AddRefs(mFillGradient), aServer, mContent, 
00731                            nsSVGPathGeometryFrameBase::GetPresContext()->PresShell());
00732     NS_ADD_SVGVALUE_OBSERVER(mFillGradient);
00733   }
00734   *aGrad = mFillGradient;
00735   return rv;
00736 }
00737 
00738 /* [noscript] boolean isClipChild; */
00739 NS_IMETHODIMP
00740 nsSVGPathGeometryFrame::IsClipChild(PRBool *_retval)
00741 {
00742   *_retval = PR_FALSE;
00743   nsCOMPtr<nsIContent> node(mContent);
00744 
00745   do {
00746     if (node->Tag() == nsSVGAtoms::clipPath) {
00747       *_retval = PR_TRUE;
00748       break;
00749     }
00750     node = node->GetParent();
00751   } while (node);
00752     
00753   return NS_OK;
00754 }
00755 
00756 //----------------------------------------------------------------------
00757 // nsISVGPathGeometrySource methods:
00758 
00759 NS_IMETHODIMP
00760 nsSVGPathGeometryFrame::GetHittestMask(PRUint16 *aHittestMask)
00761 {
00762   *aHittestMask=0;
00763 
00764   switch(GetStyleSVG()->mPointerEvents) {
00765     case NS_STYLE_POINTER_EVENTS_NONE:
00766       break;
00767     case NS_STYLE_POINTER_EVENTS_VISIBLEPAINTED:
00768       if (GetStyleVisibility()->IsVisible()) {
00769         if (GetStyleSVG()->mFill.mType != eStyleSVGPaintType_None)
00770           *aHittestMask |= HITTEST_MASK_FILL;
00771         if (GetStyleSVG()->mStroke.mType != eStyleSVGPaintType_None)
00772           *aHittestMask |= HITTEST_MASK_STROKE;
00773       }
00774       break;
00775     case NS_STYLE_POINTER_EVENTS_VISIBLEFILL:
00776       if (GetStyleVisibility()->IsVisible()) {
00777         *aHittestMask |= HITTEST_MASK_FILL;
00778       }
00779       break;
00780     case NS_STYLE_POINTER_EVENTS_VISIBLESTROKE:
00781       if (GetStyleVisibility()->IsVisible()) {
00782         *aHittestMask |= HITTEST_MASK_STROKE;
00783       }
00784       break;
00785     case NS_STYLE_POINTER_EVENTS_VISIBLE:
00786       if (GetStyleVisibility()->IsVisible()) {
00787         *aHittestMask |= HITTEST_MASK_FILL;
00788         *aHittestMask |= HITTEST_MASK_STROKE;
00789       }
00790       break;
00791     case NS_STYLE_POINTER_EVENTS_PAINTED:
00792       if (GetStyleSVG()->mFill.mType != eStyleSVGPaintType_None)
00793         *aHittestMask |= HITTEST_MASK_FILL;
00794       if (GetStyleSVG()->mStroke.mType != eStyleSVGPaintType_None)
00795         *aHittestMask |= HITTEST_MASK_STROKE;
00796       break;
00797     case NS_STYLE_POINTER_EVENTS_FILL:
00798       *aHittestMask |= HITTEST_MASK_FILL;
00799       break;
00800     case NS_STYLE_POINTER_EVENTS_STROKE:
00801       *aHittestMask |= HITTEST_MASK_STROKE;
00802       break;
00803     case NS_STYLE_POINTER_EVENTS_ALL:
00804       *aHittestMask |= HITTEST_MASK_FILL;
00805       *aHittestMask |= HITTEST_MASK_STROKE;
00806       break;
00807     default:
00808       NS_ERROR("not reached");
00809       break;
00810   }
00811   
00812   return NS_OK;
00813 }
00814 
00815 /* readonly attribute unsigned short shapeRendering; */
00816 NS_IMETHODIMP
00817 nsSVGPathGeometryFrame::GetShapeRendering(PRUint16 *aShapeRendering)
00818 {
00819   *aShapeRendering = GetStyleSVG()->mShapeRendering;
00820   return NS_OK;
00821 }
00822 
00823 //---------------------------------------------------------------------- 
00824 
00825 NS_IMETHODIMP
00826 nsSVGPathGeometryFrame::InitSVG()
00827 {
00828   // all path geometry frames listen in on changes to their
00829   // corresponding content element's transform attribute:
00830   nsCOMPtr<nsIDOMSVGTransformable> transformable = do_QueryInterface(mContent);
00831   NS_ASSERTION(transformable, "wrong content element");
00832   nsCOMPtr<nsIDOMSVGAnimatedTransformList> transforms;
00833   transformable->GetTransform(getter_AddRefs(transforms));
00834   NS_ADD_SVGVALUE_OBSERVER(transforms);
00835   
00836   // construct a pathgeometry object:
00837   nsISVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame();
00838   if (!outerSVGFrame) {
00839     NS_ERROR("Null outerSVGFrame");
00840     return NS_ERROR_FAILURE;
00841   }
00842   nsCOMPtr<nsISVGRenderer> renderer;
00843   outerSVGFrame->GetRenderer(getter_AddRefs(renderer));
00844   if (!renderer) return NS_ERROR_FAILURE;
00845 
00846   renderer->CreatePathGeometry(this, getter_AddRefs(mGeometry));
00847   
00848   if (!mGeometry) return NS_ERROR_FAILURE;
00849 
00850   return NS_OK;
00851 }
00852 
00853 nsISVGRendererPathGeometry *
00854 nsSVGPathGeometryFrame::GetGeometry()
00855 {
00856 #ifdef DEBUG
00857   NS_ASSERTION(mGeometry, "invalid geometry object");
00858 #endif
00859   return mGeometry;
00860 }
00861 
00862 void nsSVGPathGeometryFrame::UpdateGraphic(PRUint32 flags)
00863 {
00864   mUpdateFlags |= flags;
00865   
00866   nsISVGOuterSVGFrame *outerSVGFrame = GetOuterSVGFrame();
00867   if (!outerSVGFrame) {
00868     NS_ERROR("null outerSVGFrame");
00869     return;
00870   }
00871 
00872   PRBool suspended;
00873   outerSVGFrame->IsRedrawSuspended(&suspended);
00874   if (!suspended) {
00875     nsCOMPtr<nsISVGRendererRegion> dirty_region;
00876     if (GetGeometry())
00877       GetGeometry()->Update(mUpdateFlags, getter_AddRefs(dirty_region));
00878     if (dirty_region) {
00879       // if we're painting a marker, this will get called during paint
00880       // when the region already be invalidated as needed
00881 
00882       nsIView *view = GetClosestView();
00883       if (!view) return;
00884       nsIViewManager *vm = view->GetViewManager();
00885       PRBool painting;
00886       vm->IsPainting(painting);
00887 
00888       if (!painting) {
00889         if (mMarkerRegion) {
00890           outerSVGFrame->InvalidateRegion(mMarkerRegion, PR_TRUE);
00891           mMarkerRegion = nsnull;
00892         }
00893         
00894         nsISVGMarkable *markable;
00895         CallQueryInterface(this, &markable);
00896         
00897         if (markable) {
00898           nsSVGMarkerFrame *markerEnd, *markerMid, *markerStart;
00899           GetMarkerFrames(&markerStart, &markerMid, &markerEnd);
00900           
00901           if (markerEnd || markerMid || markerStart) {
00902             mMarkerRegion = GetCoveredRegion();
00903             if (mMarkerRegion) {
00904               outerSVGFrame->InvalidateRegion(mMarkerRegion, PR_TRUE);
00905               mUpdateFlags = 0;
00906             }
00907             return;
00908           }
00909         }
00910 
00911         outerSVGFrame->InvalidateRegion(dirty_region, PR_TRUE);
00912       }
00913     }
00914     mUpdateFlags = 0;
00915   }
00916 }
00917 
00918 nsISVGOuterSVGFrame *
00919 nsSVGPathGeometryFrame::GetOuterSVGFrame()
00920 {
00921   NS_ASSERTION(mParent, "null parent");
00922   
00923   nsISVGContainerFrame *containerFrame;
00924   mParent->QueryInterface(NS_GET_IID(nsISVGContainerFrame), (void**)&containerFrame);
00925   if (!containerFrame) {
00926     NS_ERROR("invalid container");
00927     return nsnull;
00928   }
00929 
00930   return containerFrame->GetOuterSVGFrame();  
00931 }
00932