Back to index

lightning-sunbird  0.9+nobinonly
nsSVGPolygonFrame.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) 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 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 "nsIDOMSVGAnimatedPoints.h"
00041 #include "nsIDOMSVGPointList.h"
00042 #include "nsIDOMSVGPoint.h"
00043 //#include "nsASVGPathBuilder.h"
00044 #include "nsISVGRendererPathBuilder.h"
00045 #include "nsISVGMarkable.h"
00046 #include "nsSVGMarkerFrame.h"
00047 #include "nsLayoutAtoms.h"
00048 
00049 class nsSVGPolygonFrame : public nsSVGPathGeometryFrame,
00050                           public nsISVGMarkable
00051 {
00052 protected:
00053   friend nsresult
00054   NS_NewSVGPolygonFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame** aNewFrame);
00055 
00056   ~nsSVGPolygonFrame();
00057 
00058   NS_IMETHOD InitSVG();
00059   
00060 public:
00061   // nsISVGValueObserver interface:
00062   NS_IMETHOD DidModifySVGObservable(nsISVGValue* observable,
00063                                     nsISVGValue::modificationType aModType);
00064 
00065   // nsISVGPathGeometrySource interface:
00066   NS_IMETHOD ConstructPath(nsISVGRendererPathBuilder *pathBuilder);
00067   
00068   nsCOMPtr<nsIDOMSVGPointList> mPoints;
00069 
00070   // nsISVGMarkable interface
00071   void GetMarkPoints(nsVoidArray *aMarks);
00072 
00073    // nsISupports interface:
00074   NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
00075 
00081   virtual nsIAtom* GetType() const;
00082 
00083 #ifdef DEBUG
00084   NS_IMETHOD GetFrameName(nsAString& aResult) const
00085   {
00086     return MakeFrameName(NS_LITERAL_STRING("SVGPolygon"), aResult);
00087   }
00088 #endif
00089 
00090 private:
00091   NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; }
00092   NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; }  
00093 };
00094 
00095 
00096 NS_INTERFACE_MAP_BEGIN(nsSVGPolygonFrame)
00097   NS_INTERFACE_MAP_ENTRY(nsISVGMarkable)
00098 NS_INTERFACE_MAP_END_INHERITING(nsSVGPathGeometryFrame)
00099 
00100 //----------------------------------------------------------------------
00101 // Implementation
00102 
00103 nsresult
00104 NS_NewSVGPolygonFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame** aNewFrame)
00105 {
00106   nsCOMPtr<nsIDOMSVGAnimatedPoints> anim_points = do_QueryInterface(aContent);
00107   if (!anim_points) {
00108 #ifdef DEBUG
00109     printf("warning: trying to construct an SVGPolygonFrame for a content element that doesn't support the right interfaces\n");
00110 #endif
00111     return NS_ERROR_FAILURE;
00112   }
00113   
00114   nsSVGPolygonFrame* it = new (aPresShell) nsSVGPolygonFrame;
00115   if (nsnull == it)
00116     return NS_ERROR_OUT_OF_MEMORY;
00117 
00118   *aNewFrame = it;
00119   return NS_OK;
00120 }
00121 
00122 nsSVGPolygonFrame::~nsSVGPolygonFrame()
00123 {
00124   nsCOMPtr<nsISVGValue> value;
00125   if (mPoints && (value = do_QueryInterface(mPoints)))
00126       value->RemoveObserver(this);
00127 }
00128 
00129 NS_IMETHODIMP
00130 nsSVGPolygonFrame::InitSVG()
00131 {
00132   nsresult rv = nsSVGPathGeometryFrame::InitSVG();
00133   if (NS_FAILED(rv)) return rv;
00134   
00135   nsCOMPtr<nsIDOMSVGAnimatedPoints> anim_points = do_QueryInterface(mContent);
00136   NS_ASSERTION(anim_points,"wrong content element");
00137   anim_points->GetPoints(getter_AddRefs(mPoints));
00138   NS_ASSERTION(mPoints, "no points");
00139   if (!mPoints) return NS_ERROR_FAILURE;
00140   nsCOMPtr<nsISVGValue> value = do_QueryInterface(mPoints);
00141   if (value)
00142     value->AddObserver(this);
00143   return NS_OK; 
00144 }  
00145 
00146 //----------------------------------------------------------------------
00147 // nsISVGValueObserver methods:
00148 
00149 NS_IMETHODIMP
00150 nsSVGPolygonFrame::DidModifySVGObservable(nsISVGValue* observable,
00151                                           nsISVGValue::modificationType aModType)
00152 {
00153   nsCOMPtr<nsIDOMSVGPointList> l = do_QueryInterface(observable);
00154   if (l && mPoints==l) {
00155     UpdateGraphic(nsISVGPathGeometrySource::UPDATEMASK_PATH);
00156     return NS_OK;
00157   }
00158   // else
00159   return nsSVGPathGeometryFrame::DidModifySVGObservable(observable, aModType);
00160 }
00161 
00162 //----------------------------------------------------------------------
00163 // nsISVGPathGeometrySource methods:
00164 
00165 /* void constructPath (in nsISVGRendererPathBuilder pathBuilder); */
00166 NS_IMETHODIMP nsSVGPolygonFrame::ConstructPath(nsISVGRendererPathBuilder* pathBuilder)
00167 {
00168   if (!mPoints) return NS_OK;
00169 
00170   PRUint32 count;
00171   mPoints->GetNumberOfItems(&count);
00172   if (count == 0) return NS_OK;
00173   
00174   PRUint32 i;
00175   for (i = 0; i < count; ++i) {
00176     nsCOMPtr<nsIDOMSVGPoint> point;
00177     mPoints->GetItem(i, getter_AddRefs(point));
00178 
00179     float x, y;
00180     point->GetX(&x);
00181     point->GetY(&y);
00182     if (i == 0)
00183       pathBuilder->Moveto(x, y);
00184     else
00185       pathBuilder->Lineto(x, y);
00186   }
00187   // the difference between a polyline and a polygon is that the
00188   // polygon is closed:
00189   float x,y;
00190   pathBuilder->ClosePath(&x,&y);
00191 
00192   return NS_OK;
00193 }
00194 
00195 //----------------------------------------------------------------------
00196 // nsISVGMarkable methods:
00197 
00198 void
00199 nsSVGPolygonFrame::GetMarkPoints(nsVoidArray *aMarks) {
00200 
00201   if (!mPoints)
00202     return;
00203 
00204   PRUint32 count;
00205   mPoints->GetNumberOfItems(&count);
00206   if (count == 0)
00207     return;
00208   
00209   float px = 0.0, py = 0.0, prevAngle, startAngle;
00210 
00211   nsCOMPtr<nsIDOMSVGPoint> point;
00212   for (PRUint32 i = 0; i < count; ++i) {
00213     mPoints->GetItem(i, getter_AddRefs(point));
00214 
00215     float x, y;
00216     point->GetX(&x);
00217     point->GetY(&y);
00218 
00219     float angle = atan2(y-py, x-px);
00220     if (i == 1)
00221       startAngle = angle;
00222     else if (i > 1)
00223       ((nsSVGMark *)aMarks->ElementAt(aMarks->Count()-1))->angle = 
00224         nsSVGMarkerFrame::bisect(prevAngle, angle);
00225 
00226     nsSVGMark *mark;
00227     mark = new nsSVGMark;
00228     mark->x = x;
00229     mark->y = y;
00230     aMarks->AppendElement(mark);
00231 
00232     prevAngle = angle;
00233     px = x;
00234     py = y;
00235   }
00236 
00237   float nx, ny, angle;
00238   mPoints->GetItem(0, getter_AddRefs(point));
00239   point->GetX(&nx);
00240   point->GetY(&ny);
00241   angle = atan2(ny - py, nx - px);
00242 
00243   ((nsSVGMark *)aMarks->ElementAt(aMarks->Count()-1))->angle = 
00244     nsSVGMarkerFrame::bisect(prevAngle, angle);
00245   ((nsSVGMark *)aMarks->ElementAt(0))->angle =
00246     nsSVGMarkerFrame::bisect(angle, startAngle);
00247 }
00248 
00249 nsIAtom *
00250 nsSVGPolygonFrame::GetType() const
00251 {
00252   return nsLayoutAtoms::svgPolygonFrame;
00253 }