Back to index

lightning-sunbird  0.9+nobinonly
nsSVGNumberList.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  * Scooter Morris.
00019  * Portions created by the Initial Developer are Copyright (C) 2004
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Scooter Morris <scootermorris@comcast.net>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * 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 "nsSVGNumberList.h"
00040 #include "nsSVGNumber.h"
00041 #include "nsSVGValue.h"
00042 #include "nsWeakReference.h"
00043 #include "nsVoidArray.h"
00044 #include "nsDOMError.h"
00045 #include "nsReadableUtils.h"
00046 #include "nsCRT.h"
00047 #include "nsISVGValueUtils.h"
00048 #include "prdtoa.h"
00049 #include "nsContentUtils.h"
00050 
00052 // nsSVGNumberList
00053 
00054 class nsSVGNumberList : public nsIDOMSVGNumberList,
00055                         public nsSVGValue,
00056                         public nsISVGValueObserver,
00057                         public nsSupportsWeakReference
00058 {  
00059 protected:
00060   friend nsresult NS_NewSVGNumberList(nsIDOMSVGNumberList** result);
00061 
00062   nsSVGNumberList();
00063   ~nsSVGNumberList();
00064 //  void Init();
00065   
00066 public:
00067   // nsISupports interface:
00068   NS_DECL_ISUPPORTS
00069 
00070   // nsIDOMSVGNumberList interface:
00071   NS_DECL_NSIDOMSVGNUMBERLIST
00072 
00073   // remainder of nsISVGValue interface:
00074   NS_IMETHOD SetValueString(const nsAString& aValue);
00075   NS_IMETHOD GetValueString(nsAString& aValue);
00076 
00077   // nsISVGValueObserver interface:
00078   NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
00079                                      modificationType aModType);
00080   NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
00081                                      modificationType aModType);
00082 
00083   // nsISupportsWeakReference
00084   // implementation inherited from nsSupportsWeakReference
00085   
00086 protected:
00087   // implementation helpers:
00088   nsIDOMSVGNumber* ElementAt(PRInt32 index);
00089   void AppendElement(nsIDOMSVGNumber* aElement);
00090   void RemoveElementAt(PRInt32 index);
00091   nsresult InsertElementAt(nsIDOMSVGNumber* aElement, PRInt32 index);
00092   
00093   void ReleaseNumbers();
00094   
00095   nsAutoVoidArray mNumbers;
00096 };
00097 
00098 
00099 //----------------------------------------------------------------------
00100 // Implementation
00101 
00102 nsSVGNumberList::nsSVGNumberList()
00103 {
00104 }
00105 
00106 nsSVGNumberList::~nsSVGNumberList()
00107 {
00108   ReleaseNumbers();
00109 }
00110 
00111 //----------------------------------------------------------------------
00112 // nsISupports methods:
00113 
00114 NS_IMPL_ADDREF(nsSVGNumberList)
00115 NS_IMPL_RELEASE(nsSVGNumberList)
00116 
00117 NS_INTERFACE_MAP_BEGIN(nsSVGNumberList)
00118   NS_INTERFACE_MAP_ENTRY(nsISVGValue)
00119   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGNumberList)
00120   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00121   NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
00122   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGNumberList)
00123   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGValue)
00124 NS_INTERFACE_MAP_END
00125 
00126 //----------------------------------------------------------------------
00127 // nsISVGValue methods:
00128 
00129 NS_IMETHODIMP
00130 nsSVGNumberList::SetValueString(const nsAString& aValue)
00131 {
00132   WillModify();
00133   ReleaseNumbers();
00134 
00135   nsresult rv = NS_OK;
00136 
00137   char* str;
00138   str = ToNewCString(aValue);
00139 
00140   char* rest = str;
00141   char* token;
00142   const char* delimiters = ", \t\r\n";
00143 
00144   while ((token = nsCRT::strtok(rest, delimiters, &rest))) {
00145     char *left;
00146     double value = PR_strtod(token, &left);
00147     if (token!=left) {
00148       nsCOMPtr<nsIDOMSVGNumber> number;
00149       NS_NewSVGNumber(getter_AddRefs(number), float(value));
00150       if (!number) {
00151         rv = NS_ERROR_FAILURE;
00152         break;
00153       }
00154       AppendElement(number);
00155     }
00156   }
00157   
00158   nsMemory::Free(str);
00159   
00160   DidModify();
00161   return rv;
00162 }
00163 
00164 NS_IMETHODIMP
00165 nsSVGNumberList::GetValueString(nsAString& aValue)
00166 {
00167   aValue.Truncate();
00168 
00169   PRInt32 count = mNumbers.Count();
00170 
00171   if (count<=0) return NS_OK;
00172 
00173   PRInt32 i = 0;
00174   
00175   while (1) {
00176     nsIDOMSVGNumber* number = ElementAt(i);
00177     nsCOMPtr<nsISVGValue> val = do_QueryInterface(number);
00178     NS_ASSERTION(val, "number 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.Append(NS_LITERAL_STRING(" "));
00187   }
00188   
00189   return NS_OK;
00190 }
00191 
00192 //----------------------------------------------------------------------
00193 // nsIDOMSVGNumberList methods:
00194 
00195 /* readonly attribute unsigned long numberOfItems; */
00196 NS_IMETHODIMP nsSVGNumberList::GetNumberOfItems(PRUint32 *aNumberOfItems)
00197 {
00198   *aNumberOfItems = mNumbers.Count();
00199   return NS_OK;
00200 }
00201 
00202 /* void clear (); */
00203 NS_IMETHODIMP nsSVGNumberList::Clear()
00204 {
00205   WillModify();
00206   ReleaseNumbers();
00207   DidModify();
00208   return NS_OK;
00209 }
00210 
00211 /* nsIDOMSVGNumber initialize (in nsIDOMSVGNumber newItem); */
00212 NS_IMETHODIMP nsSVGNumberList::Initialize(nsIDOMSVGNumber *newItem,
00213                                           nsIDOMSVGNumber **_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 /* nsIDOMSVGNumber getItem (in unsigned long index); */
00224 NS_IMETHODIMP nsSVGNumberList::GetItem(PRUint32 index, nsIDOMSVGNumber **_retval)
00225 {
00226   if (index >= NS_STATIC_CAST(PRUint32, mNumbers.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 /* nsIDOMSVGNumber insertItemBefore (in nsIDOMSVGNumber newItem, in unsigned long index); */
00237 NS_IMETHODIMP
00238 nsSVGNumberList::InsertItemBefore(nsIDOMSVGNumber *newItem,
00239                                   PRUint32 index,
00240                                   nsIDOMSVGNumber **_retval)
00241 {
00242   *_retval = newItem;
00243   if (!newItem)
00244     return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
00245 
00246   nsSVGValueAutoNotifier autonotifier(this);
00247 
00248   PRInt32 idx = index;
00249   PRInt32 count = mNumbers.Count();
00250 
00251   if (!InsertElementAt(newItem, (idx < count)? idx: count)) {
00252     *_retval = nsnull;
00253     return NS_ERROR_OUT_OF_MEMORY;
00254   }
00255 
00256   NS_ADDREF(*_retval);
00257   return NS_OK;
00258 }
00259 
00260 /* nsIDOMSVGNumber replaceItem (in nsIDOMSVGNumber newItem, in unsigned long index); */
00261 NS_IMETHODIMP
00262 nsSVGNumberList::ReplaceItem(nsIDOMSVGNumber *newItem,
00263                              PRUint32 index,
00264                              nsIDOMSVGNumber **_retval)
00265 {
00266   if (!newItem) {
00267     *_retval = nsnull;
00268     return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
00269   }
00270 
00271   nsresult rv = RemoveItem(index, _retval);
00272   if (NS_FAILED(rv))
00273     return rv;
00274 
00275   return InsertElementAt(newItem, index);
00276 }
00277 
00278 /* nsIDOMSVGNumberList removeItem (in unsigned long index); */
00279 NS_IMETHODIMP nsSVGNumberList::RemoveItem(PRUint32 index, nsIDOMSVGNumber **_retval)
00280 {
00281   if (index >= NS_STATIC_CAST(PRUint32, mNumbers.Count())) {
00282     *_retval = nsnull;
00283     return NS_ERROR_DOM_INDEX_SIZE_ERR;
00284   }
00285 
00286   *_retval = ElementAt(index);
00287   NS_ADDREF(*_retval);
00288   WillModify();
00289   RemoveElementAt(index);
00290   DidModify();
00291   return NS_OK;
00292 }
00293 
00294 /* nsIDOMSVGNumberList appendItem (in nsIDOMSVGNumberList newItem); */
00295 NS_IMETHODIMP
00296 nsSVGNumberList::AppendItem(nsIDOMSVGNumber *newItem, nsIDOMSVGNumber **_retval)
00297 {
00298   *_retval = newItem;
00299   if (!newItem)
00300     return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
00301   AppendElement(newItem);
00302   NS_ADDREF(*_retval);
00303   return NS_OK;
00304 }
00305 
00306 //----------------------------------------------------------------------
00307 // nsISVGValueObserver methods
00308 
00309 NS_IMETHODIMP
00310 nsSVGNumberList::WillModifySVGObservable(nsISVGValue* observable,
00311                                          modificationType aModType)
00312 {
00313   WillModify(aModType);
00314   return NS_OK;
00315 }
00316 
00317 NS_IMETHODIMP
00318 nsSVGNumberList::DidModifySVGObservable(nsISVGValue* observable,
00319                                         modificationType aModType)
00320 {
00321   DidModify(aModType);
00322   return NS_OK;
00323 }
00324 
00325 //----------------------------------------------------------------------
00326 // Implementation helpers
00327 
00328 void
00329 nsSVGNumberList::ReleaseNumbers()
00330 {
00331   WillModify();
00332   PRInt32 count = mNumbers.Count();
00333   for (PRInt32 i = 0; i < count; ++i) {
00334     nsIDOMSVGNumber* number = ElementAt(i);
00335     NS_REMOVE_SVGVALUE_OBSERVER(number);
00336     NS_RELEASE(number);
00337   }
00338   mNumbers.Clear();
00339   DidModify();
00340 }
00341 
00342 nsIDOMSVGNumber*
00343 nsSVGNumberList::ElementAt(PRInt32 index)
00344 {
00345   return (nsIDOMSVGNumber*)mNumbers.ElementAt(index);
00346 }
00347 
00348 void
00349 nsSVGNumberList::AppendElement(nsIDOMSVGNumber* aElement)
00350 {
00351   WillModify();
00352   NS_ADDREF(aElement);
00353   
00354   // The SVG specs state that 'if newItem is already in a list, it
00355   // is removed from its previous list before it is inserted into this
00356   // list':
00357   //  aElement->SetListOwner(this);
00358   
00359   mNumbers.AppendElement((void*)aElement);
00360   NS_ADD_SVGVALUE_OBSERVER(aElement);
00361   DidModify();
00362 }
00363 
00364 void
00365 nsSVGNumberList::RemoveElementAt(PRInt32 index)
00366 {
00367   WillModify();
00368   nsIDOMSVGNumber* number = ElementAt(index);
00369   NS_ASSERTION(number, "null number");
00370   NS_REMOVE_SVGVALUE_OBSERVER(number);
00371   mNumbers.RemoveElementAt(index);
00372   NS_RELEASE(number);
00373   DidModify();
00374 }
00375 
00376 nsresult
00377 nsSVGNumberList::InsertElementAt(nsIDOMSVGNumber* aElement, PRInt32 index)
00378 {
00379   nsresult rv;
00380   WillModify();
00381   NS_ADDREF(aElement);
00382 
00383   // The SVG specs state that 'if newItem is already in a list, it
00384   // is removed from its previous list before it is inserted into this
00385   // list':
00386   //  aElement->SetListOwner(this);
00387   
00388   if (!NS_FAILED(rv = mNumbers.InsertElementAt((void*)aElement, index)))
00389     NS_ADD_SVGVALUE_OBSERVER(aElement);
00390   DidModify();
00391   return rv;
00392 }
00393 
00394 
00396 // Exported creation functions:
00397 
00398 nsresult
00399 NS_NewSVGNumberList(nsIDOMSVGNumberList** result)
00400 {
00401   *result = nsnull;
00402   
00403   nsSVGNumberList* numberList = new nsSVGNumberList();
00404   if (!numberList) return NS_ERROR_OUT_OF_MEMORY;
00405   NS_ADDREF(numberList);
00406 
00407   *result = numberList;
00408   
00409   return NS_OK;
00410 }
00411 
00412