Back to index

lightning-sunbird  0.9+nobinonly
nsSVGPointList.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 "nsSVGPointList.h"
00040 #include "nsSVGPoint.h"
00041 #include "nsDOMError.h"
00042 #include "prdtoa.h"
00043 #include "nsReadableUtils.h"
00044 #include "nsTextFormatter.h"
00045 #include "nsCRT.h"
00046 #include "nsCOMArray.h"
00047 #include "nsContentUtils.h"
00048 
00049 nsresult
00050 nsSVGPointList::Create(const nsAString& aValue,
00051                        nsISVGValue** aResult)
00052 {
00053   *aResult = (nsISVGValue*) new nsSVGPointList();
00054   if(!*aResult) return NS_ERROR_OUT_OF_MEMORY;
00055   
00056   NS_ADDREF(*aResult);
00057 
00058   (*aResult)->SetValueString(aValue);  
00059   return NS_OK;
00060 }
00061 
00062 nsresult
00063 nsSVGPointList::Create(nsIDOMSVGPointList** aResult)
00064 {
00065   *aResult = (nsIDOMSVGPointList*) new nsSVGPointList();
00066   if(!*aResult) return NS_ERROR_OUT_OF_MEMORY;
00067   
00068   NS_ADDREF(*aResult);
00069   return NS_OK;
00070 }
00071 
00072 nsSVGPointList::nsSVGPointList()
00073 {
00074 }
00075 
00076 nsSVGPointList::~nsSVGPointList()
00077 {
00078   ReleasePoints();
00079 }
00080 
00081 void
00082 nsSVGPointList::ReleasePoints()
00083 {
00084   WillModify();
00085   PRInt32 count = mPoints.Count();
00086   for (PRInt32 i = 0; i < count; ++i) {
00087     nsIDOMSVGPoint* point = ElementAt(i);
00088     nsCOMPtr<nsISVGValue> val = do_QueryInterface(point);
00089     if (val)
00090       val->RemoveObserver(this);
00091     NS_RELEASE(point);
00092   }
00093   mPoints.Clear();
00094   DidModify();
00095 }
00096 
00097 nsIDOMSVGPoint*
00098 nsSVGPointList::ElementAt(PRInt32 index)
00099 {
00100   return (nsIDOMSVGPoint*)mPoints.ElementAt(index);
00101 }
00102 
00103 void
00104 nsSVGPointList::AppendElement(nsIDOMSVGPoint* aElement)
00105 {
00106   WillModify();
00107   NS_ADDREF(aElement);
00108   mPoints.AppendElement((void*)aElement);
00109   nsCOMPtr<nsISVGValue> val = do_QueryInterface(aElement);
00110   if (val)
00111     val->AddObserver(this);
00112   DidModify();
00113 }
00114 
00115 void
00116 nsSVGPointList::RemoveElementAt(PRInt32 index)
00117 {
00118   WillModify();
00119   nsIDOMSVGPoint* point = ElementAt(index);
00120   NS_ASSERTION(point, "null point");
00121   nsCOMPtr<nsISVGValue> val = do_QueryInterface(point);
00122   if (val)
00123     val->RemoveObserver(this);
00124   mPoints.RemoveElementAt(index);
00125   NS_RELEASE(point);
00126   DidModify();
00127 }
00128 
00129 void
00130 nsSVGPointList::InsertElementAt(nsIDOMSVGPoint* aElement, PRInt32 index)
00131 {
00132   WillModify();
00133   NS_ADDREF(aElement);
00134   mPoints.InsertElementAt((void*)aElement, index);
00135   nsCOMPtr<nsISVGValue> val = do_QueryInterface(aElement);
00136   if (val)
00137     val->AddObserver(this);
00138   DidModify();
00139 }
00140 
00141 //----------------------------------------------------------------------
00142 // nsISupports methods:
00143 
00144 NS_IMPL_ADDREF(nsSVGPointList)
00145 NS_IMPL_RELEASE(nsSVGPointList)
00146 
00147 NS_INTERFACE_MAP_BEGIN(nsSVGPointList)
00148   NS_INTERFACE_MAP_ENTRY(nsISVGValue)
00149   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGPointList)
00150   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00151   NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
00152   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGPointList)
00153   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGValue)
00154 NS_INTERFACE_MAP_END
00155 
00156 
00157 //----------------------------------------------------------------------
00158 // nsISVGValue methods:
00159 
00160 NS_IMETHODIMP
00161 nsSVGPointList::SetValueString(const nsAString& aValue)
00162 {
00163   nsresult rv = NS_OK;
00164 
00165   char* str = ToNewCString(aValue);
00166   
00167   char* rest = str;
00168   char* token1;
00169   char* token2;
00170   const char* delimiters = ",\x20\x9\xD\xA";
00171   nsCOMArray<nsIDOMSVGPoint> points;
00172   
00173   while ( (token1 = nsCRT::strtok(rest, delimiters, &rest)) &&
00174           (token2 = nsCRT::strtok(rest, delimiters, &rest)) ) {
00175 
00176     char *end;
00177     
00178     double x = PR_strtod(token1, &end);
00179     if (*end != '\0') {
00180       rv = NS_ERROR_FAILURE;
00181       break; // parse error
00182     }
00183     double y = PR_strtod(token2, &end);
00184     if (*end != '\0') {
00185       rv = NS_ERROR_FAILURE;
00186       break; // parse error
00187     }
00188     
00189     nsCOMPtr<nsIDOMSVGPoint> point;
00190     NS_NewSVGPoint(getter_AddRefs(point), (float)x, (float)y);
00191     if (!point) {
00192       rv = NS_ERROR_OUT_OF_MEMORY;
00193       break;
00194     }
00195     points.AppendObject(point);
00196   }
00197 
00198   if (token1 || NS_FAILED(rv)) {
00199     // there was a parse error or we ran out of memory
00200     rv = NS_ERROR_FAILURE;
00201   }
00202   else {
00203     WillModify();
00204     ReleasePoints();
00205     PRInt32 count = points.Count();
00206     for (PRInt32 i=0; i<count; ++i) {
00207       AppendElement(points.ObjectAt(i));
00208     }
00209     DidModify();
00210   }
00211 
00212   nsMemory::Free(str);
00213   
00214   return rv;
00215 }
00216 
00217 NS_IMETHODIMP
00218 nsSVGPointList::GetValueString(nsAString& aValue)
00219 {
00220   aValue.Truncate();
00221 
00222   PRInt32 count = mPoints.Count();
00223 
00224   if (count<=0) return NS_OK;
00225 
00226   PRInt32 i = 0;
00227   PRUnichar buf[48];
00228   
00229   while (1) {
00230     nsIDOMSVGPoint* point = ElementAt(i);
00231     float x, y;
00232     point->GetX(&x);
00233     point->GetY(&y);
00234     
00235     nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar), NS_LITERAL_STRING("%g,%g").get(), (double)x, (double)y);
00236     aValue.Append(buf);
00237 
00238     if (++i >= count) break;
00239 
00240     aValue.AppendLiteral(" ");
00241   }
00242   
00243   return NS_OK;
00244 }
00245 
00246 //----------------------------------------------------------------------
00247 // nsIDOMSVGPointList methods:
00248 
00249 /* readonly attribute unsigned long numberOfItems; */
00250 NS_IMETHODIMP nsSVGPointList::GetNumberOfItems(PRUint32 *aNumberOfItems)
00251 {
00252   *aNumberOfItems = mPoints.Count();
00253   return NS_OK;
00254 }
00255 
00256 /* void clear (); */
00257 NS_IMETHODIMP nsSVGPointList::Clear()
00258 {
00259   WillModify();
00260   ReleasePoints();
00261   DidModify();
00262   return NS_OK;
00263 }
00264 
00265 /* nsIDOMSVGPoint initialize (in nsIDOMSVGPoint newItem); */
00266 NS_IMETHODIMP nsSVGPointList::Initialize(nsIDOMSVGPoint *newItem,
00267                                          nsIDOMSVGPoint **_retval)
00268 {
00269   if (!newItem) {
00270     *_retval = nsnull;
00271     return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
00272   }
00273   Clear();
00274   return AppendItem(newItem, _retval);
00275 }
00276 
00277 /* nsIDOMSVGPoint getItem (in unsigned long index); */
00278 NS_IMETHODIMP nsSVGPointList::GetItem(PRUint32 index, nsIDOMSVGPoint **_retval)
00279 {
00280   if (index >= NS_STATIC_CAST(PRUint32, mPoints.Count())) {
00281     *_retval = nsnull;
00282     return NS_ERROR_DOM_INDEX_SIZE_ERR;
00283   }
00284 
00285   *_retval  = ElementAt(index);
00286   NS_ADDREF(*_retval);
00287   return NS_OK;
00288 }
00289 
00290 /* nsIDOMSVGPoint insertItemBefore (in nsIDOMSVGPoint newItem, in unsigned long index); */
00291 NS_IMETHODIMP nsSVGPointList::InsertItemBefore(nsIDOMSVGPoint *newItem,
00292                                                PRUint32 index,
00293                                                nsIDOMSVGPoint **_retval)
00294 {
00295   // null check when implementing - this method can be used by scripts!
00296   // if (!newItem)
00297   //   return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
00298 
00299   NS_NOTYETIMPLEMENTED("write me");
00300   return NS_ERROR_NOT_IMPLEMENTED;
00301 }
00302 
00303 /* nsIDOMSVGPoint replaceItem (in nsIDOMSVGPoint newItem, in unsigned long index); */
00304 NS_IMETHODIMP nsSVGPointList::ReplaceItem(nsIDOMSVGPoint *newItem,
00305                                           PRUint32 index,
00306                                           nsIDOMSVGPoint **_retval)
00307 {
00308   // null check when implementing - this method can be used by scripts!
00309   // if (!newItem)
00310   //   return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
00311 
00312   NS_NOTYETIMPLEMENTED("write me");
00313   return NS_ERROR_NOT_IMPLEMENTED;
00314 }
00315 
00316 /* nsIDOMSVGPoint removeItem (in unsigned long index); */
00317 NS_IMETHODIMP nsSVGPointList::RemoveItem(PRUint32 index, nsIDOMSVGPoint **_retval)
00318 {
00319   if (index >= NS_STATIC_CAST(PRUint32, mPoints.Count())) {
00320     *_retval = nsnull;
00321     return NS_ERROR_DOM_INDEX_SIZE_ERR;
00322   }
00323 
00324   *_retval = ElementAt(index);
00325   NS_ADDREF(*_retval);
00326   WillModify();
00327   RemoveElementAt(index);
00328   DidModify();
00329   return NS_OK;
00330 }
00331 
00332 /* nsIDOMSVGPoint appendItem (in nsIDOMSVGPoint newItem); */
00333 NS_IMETHODIMP nsSVGPointList::AppendItem(nsIDOMSVGPoint *newItem,
00334                                          nsIDOMSVGPoint **_retval)
00335 {
00336   // XXX The SVG specs state that 'if newItem is already in a list, it
00337   // is removed from its previous list before it is inserted into this
00338   // list'. We don't do that. Should we?
00339   
00340   *_retval = newItem;
00341   if (!newItem)
00342     return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
00343   AppendElement(newItem);
00344   NS_ADDREF(*_retval);
00345   return NS_OK;
00346 }
00347 
00348 //----------------------------------------------------------------------
00349 // nsISVGValueObserver methods
00350 
00351 NS_IMETHODIMP
00352 nsSVGPointList::WillModifySVGObservable(nsISVGValue* observable,
00353                                         modificationType aModType)
00354 {
00355   WillModify(aModType);
00356   return NS_OK;
00357 }
00358 
00359 NS_IMETHODIMP
00360 nsSVGPointList::DidModifySVGObservable (nsISVGValue* observable,
00361                                         modificationType aModType)
00362 {
00363   DidModify(aModType);
00364   return NS_OK;
00365 }