Back to index

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