Back to index

lightning-sunbird  0.9+nobinonly
nsSVGPathSegList.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 "nsSVGPathSegList.h"
00040 #include "nsSVGPathSeg.h"
00041 #include "nsSVGValue.h"
00042 #include "nsWeakReference.h"
00043 #include "nsVoidArray.h"
00044 #include "nsDOMError.h"
00045 #include "nsSVGPathDataParser.h"
00046 #include "nsReadableUtils.h"
00047 #include "nsContentUtils.h"
00048 
00050 // nsSVGPathSegList
00051 
00052 class nsSVGPathSegList : public nsIDOMSVGPathSegList,
00053                          public nsSVGValue,
00054                          public nsISVGValueObserver,
00055                          public nsSupportsWeakReference
00056 {  
00057 protected:
00058   friend nsresult NS_NewSVGPathSegList(nsIDOMSVGPathSegList** result);
00059 
00060   nsSVGPathSegList();
00061   ~nsSVGPathSegList();
00062 //  void Init();
00063   
00064 public:
00065   // nsISupports interface:
00066   NS_DECL_ISUPPORTS
00067 
00068   // nsIDOMSVGPathSegList interface:
00069   NS_DECL_NSIDOMSVGPATHSEGLIST
00070 
00071   // remainder of nsISVGValue interface:
00072   NS_IMETHOD SetValueString(const nsAString& aValue);
00073   NS_IMETHOD GetValueString(nsAString& aValue);
00074 
00075   // nsISVGValueObserver
00076   NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
00077                                      modificationType aModType);
00078   NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
00079                                      modificationType aModType);
00080   
00081   // nsISupportsWeakReference
00082   // implementation inherited from nsSupportsWeakReference
00083 
00084 protected:
00085   // implementation helpers:
00086   nsIDOMSVGPathSeg* ElementAt(PRInt32 index);
00087   void AppendElement(nsIDOMSVGPathSeg* aElement);
00088   void RemoveElementAt(PRInt32 index);
00089   void InsertElementAt(nsIDOMSVGPathSeg* aElement, PRInt32 index);
00090   
00091   void ReleaseSegments();
00092   
00093   nsVoidArray mSegments;
00094 };
00095 
00096 
00097 //----------------------------------------------------------------------
00098 // Implementation
00099 
00100 nsSVGPathSegList::nsSVGPathSegList()
00101 {
00102 }
00103 
00104 nsSVGPathSegList::~nsSVGPathSegList()
00105 {
00106   ReleaseSegments();
00107 }
00108 
00109 //----------------------------------------------------------------------
00110 // nsISupports methods:
00111 
00112 NS_IMPL_ADDREF(nsSVGPathSegList)
00113 NS_IMPL_RELEASE(nsSVGPathSegList)
00114 
00115 NS_INTERFACE_MAP_BEGIN(nsSVGPathSegList)
00116   NS_INTERFACE_MAP_ENTRY(nsISVGValue)
00117   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGPathSegList)
00118   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00119   NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
00120   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGPathSegList)
00121   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGValue)
00122 NS_INTERFACE_MAP_END
00123 
00124 //----------------------------------------------------------------------
00125 // nsISVGValue methods:
00126 
00127 NS_IMETHODIMP
00128 nsSVGPathSegList::SetValueString(const nsAString& aValue)
00129 {
00130   nsresult rv;
00131 
00132   char *str = ToNewCString(aValue);
00133 
00134   nsVoidArray data;
00135   nsSVGPathDataParser parser(&data);
00136   rv = parser.Parse(str);
00137   
00138   if (NS_SUCCEEDED(rv)) {
00139     WillModify();
00140     ReleaseSegments();
00141     mSegments = data;
00142     PRInt32 count = mSegments.Count();
00143     for (PRInt32 i=0; i<count; ++i) {
00144       nsIDOMSVGPathSeg* seg = ElementAt(i);
00145       nsCOMPtr<nsISVGValue> val = do_QueryInterface(seg);
00146       if (val)
00147         val->AddObserver(this);
00148     }
00149     DidModify();
00150   }
00151   else {
00152     NS_ERROR("path data parse error!");    
00153     PRInt32 count = data.Count();
00154     for (PRInt32 i=0; i<count; ++i) {
00155       nsIDOMSVGPathSeg* seg = (nsIDOMSVGPathSeg*)data.ElementAt(i);
00156       NS_RELEASE(seg);
00157     }
00158   }
00159   
00160   nsMemory::Free(str);
00161   return rv;
00162 }
00163 
00164 NS_IMETHODIMP
00165 nsSVGPathSegList::GetValueString(nsAString& aValue)
00166 {
00167   aValue.Truncate();
00168 
00169   PRInt32 count = mSegments.Count();
00170 
00171   if (count<=0) return NS_OK;
00172 
00173   PRInt32 i = 0;
00174   
00175   while (1) {
00176     nsIDOMSVGPathSeg* seg = ElementAt(i);
00177     nsCOMPtr<nsISVGValue> val = do_QueryInterface(seg);
00178     NS_ASSERTION(val, "path segment doesn't implement required interface");
00179     if (!val) continue;
00180     nsAutoString str;
00181     val->GetValueString(str);
00182     aValue.Append(str);
00183 
00184     if (++i >= count) break;
00185 
00186     aValue.AppendLiteral(" ");
00187   }
00188   
00189   return NS_OK;
00190 }
00191 
00192 //----------------------------------------------------------------------
00193 // nsIDOMSVGPathSegList methods:
00194 
00195 /* readonly attribute unsigned long numberOfItems; */
00196 NS_IMETHODIMP nsSVGPathSegList::GetNumberOfItems(PRUint32 *aNumberOfItems)
00197 {
00198   *aNumberOfItems = mSegments.Count();
00199   return NS_OK;
00200 }
00201 
00202 /* void clear (); */
00203 NS_IMETHODIMP nsSVGPathSegList::Clear()
00204 {
00205   WillModify();
00206   ReleaseSegments();
00207   DidModify();
00208   return NS_OK;
00209 }
00210 
00211 /* nsIDOMSVGPathSeg initialize (in nsIDOMSVGPathSeg newItem); */
00212 NS_IMETHODIMP nsSVGPathSegList::Initialize(nsIDOMSVGPathSeg *newItem,
00213                                            nsIDOMSVGPathSeg **_retval)
00214 {
00215   if (!newItem) {
00216     *_retval = nsnull;
00217     return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
00218   }
00219   Clear();
00220   return AppendItem(newItem, _retval);
00221 }
00222 
00223 /* nsIDOMSVGPathSeg getItem (in unsigned long index); */
00224 NS_IMETHODIMP nsSVGPathSegList::GetItem(PRUint32 index, nsIDOMSVGPathSeg **_retval)
00225 {
00226   if (index >= NS_STATIC_CAST(PRUint32, mSegments.Count())) {
00227     *_retval = nsnull;
00228     return NS_ERROR_DOM_INDEX_SIZE_ERR;
00229   }
00230 
00231   *_retval  = ElementAt(index);
00232   NS_ADDREF(*_retval);
00233   return NS_OK;
00234 }
00235 
00236 /* nsIDOMSVGPathSeg insertItemBefore (in nsIDOMSVGPathSeg newItem, in unsigned long index); */
00237 NS_IMETHODIMP nsSVGPathSegList::InsertItemBefore(nsIDOMSVGPathSeg *newItem,
00238                                                  PRUint32 index,
00239                                                  nsIDOMSVGPathSeg **_retval)
00240 {
00241   // null check when implementing - this method can be used by scripts!
00242   // if (!newItem)
00243   //   return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
00244 
00245   NS_NOTYETIMPLEMENTED("nsSVGPathSegList::InsertItemBefore");
00246   return NS_ERROR_NOT_IMPLEMENTED;
00247 }
00248 
00249 /* nsIDOMSVGPathSeg replaceItem (in nsIDOMSVGPathSeg newItem, in unsigned long index); */
00250 NS_IMETHODIMP nsSVGPathSegList::ReplaceItem(nsIDOMSVGPathSeg *newItem,
00251                                             PRUint32 index,
00252                                             nsIDOMSVGPathSeg **_retval)
00253 {
00254   // null check when implementing - this method can be used by scripts!
00255   // if (!newItem)
00256   //   return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
00257 
00258   NS_NOTYETIMPLEMENTED("nsSVGPathSegList::ReplaceItem");
00259   return NS_ERROR_NOT_IMPLEMENTED;
00260 }
00261 
00262 /* nsIDOMSVGPathSeg removeItem (in unsigned long index); */
00263 NS_IMETHODIMP nsSVGPathSegList::RemoveItem(PRUint32 index, nsIDOMSVGPathSeg **_retval)
00264 {
00265   if (index >= NS_STATIC_CAST(PRUint32, mSegments.Count())) {
00266     *_retval = nsnull;
00267     return NS_ERROR_DOM_INDEX_SIZE_ERR;
00268   }
00269 
00270   *_retval = ElementAt(index);
00271   NS_ADDREF(*_retval);
00272   WillModify();
00273   RemoveElementAt(index);
00274   DidModify();
00275   return NS_OK;
00276 }
00277 
00278 /* nsIDOMSVGPathSeg appendItem (in nsIDOMSVGPathSeg newItem); */
00279 NS_IMETHODIMP nsSVGPathSegList::AppendItem(nsIDOMSVGPathSeg *newItem,
00280                                            nsIDOMSVGPathSeg **_retval)
00281 {
00282   // XXX The SVG specs state that 'if newItem is already in a list, it
00283   // is removed from its previous list before it is inserted into this
00284   // list'. We don't do that. Should we?
00285 
00286   *_retval = newItem;
00287   if (!newItem)
00288     return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
00289   AppendElement(newItem);
00290   NS_ADDREF(*_retval);
00291   return NS_OK;
00292 }
00293 
00294 
00295 //----------------------------------------------------------------------
00296 // nsISVGValueObserver methods
00297 
00298 NS_IMETHODIMP
00299 nsSVGPathSegList::WillModifySVGObservable(nsISVGValue* observable,
00300                                           modificationType aModType)
00301 {
00302   WillModify(aModType);
00303   return NS_OK;
00304 }
00305 
00306 NS_IMETHODIMP
00307 nsSVGPathSegList::DidModifySVGObservable (nsISVGValue* observable,
00308                                           modificationType aModType)
00309 {
00310   DidModify(aModType);
00311   return NS_OK;
00312 }
00313 
00314 //----------------------------------------------------------------------
00315 // Implementation helpers
00316 
00317 void
00318 nsSVGPathSegList::ReleaseSegments()
00319 {
00320   WillModify();
00321   PRInt32 count = mSegments.Count();
00322   for (PRInt32 i = 0; i < count; ++i) {
00323     nsIDOMSVGPathSeg* seg = ElementAt(i);
00324     nsCOMPtr<nsISVGValue> val = do_QueryInterface(seg);
00325     if (val)
00326       val->RemoveObserver(this);
00327     NS_RELEASE(seg);
00328   }
00329   mSegments.Clear();
00330   DidModify();
00331 }
00332 
00333 nsIDOMSVGPathSeg*
00334 nsSVGPathSegList::ElementAt(PRInt32 index)
00335 {
00336   return (nsIDOMSVGPathSeg*)mSegments.ElementAt(index);
00337 }
00338 
00339 void
00340 nsSVGPathSegList::AppendElement(nsIDOMSVGPathSeg* aElement)
00341 {
00342   WillModify();
00343   NS_ADDREF(aElement);
00344   mSegments.AppendElement((void*)aElement);
00345   nsCOMPtr<nsISVGValue> val = do_QueryInterface(aElement);
00346   if (val)
00347     val->AddObserver(this);
00348   DidModify();
00349 }
00350 
00351 void
00352 nsSVGPathSegList::RemoveElementAt(PRInt32 index)
00353 {
00354   WillModify();
00355   nsIDOMSVGPathSeg* seg = ElementAt(index);
00356   NS_ASSERTION(seg, "null pathsegment");
00357   nsCOMPtr<nsISVGValue> val = do_QueryInterface(seg);
00358   if (val)
00359     val->RemoveObserver(this);
00360   mSegments.RemoveElementAt(index);
00361   NS_RELEASE(seg);
00362   DidModify();
00363 }
00364 
00365 void
00366 nsSVGPathSegList::InsertElementAt(nsIDOMSVGPathSeg* aElement, PRInt32 index)
00367 {
00368   WillModify();
00369   NS_ADDREF(aElement);
00370   mSegments.InsertElementAt((void*)aElement, index);
00371   nsCOMPtr<nsISVGValue> val = do_QueryInterface(aElement);
00372   if (val)
00373     val->AddObserver(this);
00374   DidModify();
00375 }
00376 
00377 
00379 // Exported creation functions:
00380 
00381 nsresult
00382 NS_NewSVGPathSegList(nsIDOMSVGPathSegList** result)
00383 {
00384   *result = nsnull;
00385   
00386   nsSVGPathSegList* pathSegList = new nsSVGPathSegList();
00387   if (!pathSegList) return NS_ERROR_OUT_OF_MEMORY;
00388   NS_ADDREF(pathSegList);
00389 
00390   // pathSegList->Init();
00391   
00392   *result = (nsIDOMSVGPathSegList*) pathSegList;
00393   
00394   return NS_OK;
00395 }
00396