Back to index

lightning-sunbird  0.9+nobinonly
nsSVGAngle.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 IBM Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 2004
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either of the GNU General Public License Version 2 or later (the "GPL"),
00025  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #include "nsSVGAngle.h"
00038 #include "prdtoa.h"
00039 #include "nsSVGAtoms.h"
00040 #include "nsSVGValue.h"
00041 #include "nsReadableUtils.h"
00042 #include "nsTextFormatter.h"
00043 #include "nsCRT.h"
00044 #include "nsIDOMSVGNumber.h"
00045 #include "nsISVGValueUtils.h"
00046 #include "nsWeakReference.h"
00047 #include "nsContentUtils.h"
00048 #include <math.h>
00049 
00050 #ifndef M_PI
00051 #define M_PI 3.14159265358979323846
00052 #endif
00053 
00055 // nsSVGAngle class
00056 
00057 class nsSVGAngle : public nsIDOMSVGAngle,
00058                    public nsSVGValue,
00059                    public nsISVGValueObserver,
00060                    public nsSupportsWeakReference
00061 {
00062 protected:
00063   friend nsresult NS_NewSVGAngle(nsIDOMSVGAngle** result,
00064                                  float value,
00065                                  PRUint16 unit);
00066 
00067   friend nsresult NS_NewSVGAngle(nsIDOMSVGAngle** result,
00068                                  const nsAString &value);
00069   
00070   nsSVGAngle(float value, PRUint16 unit);
00071   nsSVGAngle();
00072   virtual ~nsSVGAngle();
00073 
00074 public:
00075   // nsISupports interface:
00076   NS_DECL_ISUPPORTS
00077 
00078   // nsIDOMSVGAngle interface:
00079   NS_DECL_NSIDOMSVGANGLE
00080 
00081   // nsISVGValue interface:
00082   NS_IMETHOD SetValueString(const nsAString& aValue);
00083   NS_IMETHOD GetValueString(nsAString& aValue);
00084   
00085   // nsISVGValueObserver interface:
00086   NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
00087                                      modificationType aModType);
00088   NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
00089                                      modificationType aModType);
00090 
00091   // nsISupportsWeakReference
00092   // implementation inherited from nsSupportsWeakReference
00093   
00094 protected:
00095   // implementation helpers:
00096   void  GetUnitString(nsAString& unit);
00097   PRUint16 GetUnitTypeForString(const char* unitStr);
00098   PRBool IsValidUnitType(PRUint16 unit);
00099 
00100   float mValueInSpecifiedUnits;
00101   PRUint8 mSpecifiedUnitType : 3;
00102   PRPackedBool mIsAuto : 1;
00103 };
00104 
00105 
00106 //----------------------------------------------------------------------
00107 // Implementation
00108 
00109 nsresult
00110 NS_NewSVGAngle(nsIDOMSVGAngle** result,
00111                float value,
00112                PRUint16 unit)
00113 {
00114   nsSVGAngle *pl = new nsSVGAngle(value, unit);
00115   NS_ENSURE_TRUE(pl, NS_ERROR_OUT_OF_MEMORY);
00116   NS_ADDREF(pl);
00117   *result = pl;
00118   return NS_OK;
00119 }
00120 
00121 nsresult
00122 NS_NewSVGAngle(nsIDOMSVGAngle** result,
00123                const nsAString &value)
00124 {
00125   *result = nsnull;
00126   nsSVGAngle *pl = new nsSVGAngle();
00127   NS_ENSURE_TRUE(pl, NS_ERROR_OUT_OF_MEMORY);
00128   NS_ADDREF(pl);
00129   if (NS_FAILED(pl->SetValueAsString(value))) {
00130     NS_RELEASE(pl);
00131     return NS_ERROR_FAILURE;
00132   }
00133   *result = pl;
00134   return NS_OK;
00135 }  
00136 
00137 
00138 nsSVGAngle::nsSVGAngle(float value,
00139                        PRUint16 unit)
00140   : mValueInSpecifiedUnits(value),
00141     mIsAuto(PR_FALSE)
00142 {
00143   NS_ASSERTION(unit == SVG_ANGLETYPE_UNKNOWN || IsValidUnitType(unit), "unknown unit");
00144   mSpecifiedUnitType = unit;
00145 }
00146 
00147 nsSVGAngle::nsSVGAngle()
00148 {
00149 }
00150 
00151 nsSVGAngle::~nsSVGAngle()
00152 {
00153 }
00154 
00155 //----------------------------------------------------------------------
00156 // nsISupports methods:
00157 
00158 NS_IMPL_ADDREF(nsSVGAngle)
00159 NS_IMPL_RELEASE(nsSVGAngle)
00160 
00161 NS_INTERFACE_MAP_BEGIN(nsSVGAngle)
00162   NS_INTERFACE_MAP_ENTRY(nsISVGValue)
00163   NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
00164   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAngle)
00165   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00166   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGAngle)
00167   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGValue)
00168 NS_INTERFACE_MAP_END
00169 
00170 //----------------------------------------------------------------------
00171 // nsISVGValue methods:
00172 NS_IMETHODIMP
00173 nsSVGAngle::SetValueString(const nsAString& aValue)
00174 {
00175   return SetValueAsString(aValue);
00176 }
00177 
00178 NS_IMETHODIMP
00179 nsSVGAngle::GetValueString(nsAString& aValue)
00180 {
00181   return GetValueAsString(aValue);
00182 }
00183 
00184 //----------------------------------------------------------------------
00185 // nsISVGValueObserver methods
00186 
00187 NS_IMETHODIMP
00188 nsSVGAngle::WillModifySVGObservable(nsISVGValue* observable,
00189                                     modificationType aModType)
00190 {
00191   WillModify(aModType);
00192   return NS_OK;
00193 }
00194 
00195 NS_IMETHODIMP
00196 nsSVGAngle::DidModifySVGObservable(nsISVGValue* observable,
00197                                    modificationType aModType)
00198 {
00199   DidModify(aModType);
00200   return NS_OK;
00201 }
00202 
00203 //----------------------------------------------------------------------
00204 // nsIDOMSVGAngle methods:
00205 
00206 /* readonly attribute unsigned short unitType; */
00207 NS_IMETHODIMP
00208 nsSVGAngle::GetUnitType(PRUint16 *aUnitType)
00209 {
00210   *aUnitType = mSpecifiedUnitType;
00211   return NS_OK;
00212 }
00213 
00214 /* attribute float value; */
00215 NS_IMETHODIMP
00216 nsSVGAngle::GetValue(float *aValue)
00217 {
00218   nsresult rv = NS_OK;
00219   
00220   switch (mSpecifiedUnitType) {
00221   case SVG_ANGLETYPE_UNSPECIFIED:
00222   case SVG_ANGLETYPE_DEG:
00223     *aValue = float((mValueInSpecifiedUnits * M_PI) / 180.0);
00224     break;
00225   case SVG_ANGLETYPE_RAD:
00226     *aValue = mValueInSpecifiedUnits;
00227     break;
00228   case SVG_ANGLETYPE_GRAD:
00229     *aValue = float((mValueInSpecifiedUnits * M_PI) / 100.0);
00230     break;
00231   default:
00232     rv = NS_ERROR_FAILURE;
00233     break;
00234   }
00235   return rv;
00236 }
00237 
00238 NS_IMETHODIMP
00239 nsSVGAngle::SetValue(float aValue)
00240 {
00241   nsresult rv;
00242   
00243   switch (mSpecifiedUnitType) {
00244   case SVG_ANGLETYPE_UNSPECIFIED:
00245   case SVG_ANGLETYPE_DEG:
00246     rv = SetValueInSpecifiedUnits(float((aValue * 180.0) / M_PI));
00247     break;
00248   case SVG_ANGLETYPE_RAD:
00249     rv = SetValueInSpecifiedUnits(aValue);
00250     break;
00251   case SVG_ANGLETYPE_GRAD:
00252     rv = SetValueInSpecifiedUnits(float((aValue * 100.0) / M_PI));
00253     break;
00254   default:
00255     rv = NS_ERROR_FAILURE;
00256     break;
00257   }
00258 
00259   return rv;
00260 }
00261 
00262 /* attribute float valueInSpecifiedUnits; */
00263 NS_IMETHODIMP
00264 nsSVGAngle::GetValueInSpecifiedUnits(float *aValueInSpecifiedUnits)
00265 {
00266   *aValueInSpecifiedUnits = mValueInSpecifiedUnits;
00267   return NS_OK;
00268 }
00269 
00270 NS_IMETHODIMP
00271 nsSVGAngle::SetValueInSpecifiedUnits(float aValueInSpecifiedUnits)
00272 {
00273   WillModify();
00274   mIsAuto                = PR_FALSE;
00275   mValueInSpecifiedUnits = aValueInSpecifiedUnits;
00276   DidModify();
00277   return NS_OK;
00278 }
00279 
00280 /* attribute DOMString valueAsString; */
00281 NS_IMETHODIMP
00282 nsSVGAngle::GetValueAsString(nsAString & aValueAsString)
00283 {
00284   if (mIsAuto) {
00285     aValueAsString.AssignLiteral("auto");
00286     return NS_OK;
00287   }
00288   aValueAsString.Truncate();
00289 
00290   PRUnichar buf[24];
00291   nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
00292                             NS_LITERAL_STRING("%g").get(),
00293                             (double)mValueInSpecifiedUnits);
00294   aValueAsString.Append(buf);
00295   
00296   nsAutoString unitString;
00297   GetUnitString(unitString);
00298   aValueAsString.Append(unitString);
00299   
00300   return NS_OK;
00301 }
00302 
00303 NS_IMETHODIMP
00304 nsSVGAngle::SetValueAsString(const nsAString & aValueAsString)
00305 {
00306   if (aValueAsString.EqualsLiteral("auto")) {
00307     WillModify();
00308     mIsAuto = PR_TRUE;
00309     DidModify();
00310     return NS_OK;
00311   }
00312   nsresult rv = NS_OK;
00313   
00314   char *str = ToNewCString(aValueAsString);
00315 
00316   char* number = str;
00317   while (*number && isspace(*number))
00318     ++number;
00319 
00320   if (*number) {
00321     char *rest;
00322     double value = PR_strtod(number, &rest);
00323     if (rest!=number) {
00324       PRUint16 unitType = GetUnitTypeForString(nsCRT::strtok(rest, "\x20\x9\xD\xA", &rest));
00325       rv = NewValueSpecifiedUnits(unitType, (float)value);
00326       if (rv != NS_OK) {
00327         NS_ERROR("invalid length type");
00328       }
00329     }
00330     else { // parse error
00331       // no number
00332       rv = NS_ERROR_FAILURE;
00333     }
00334   }
00335   
00336   nsMemory::Free(str);
00337     
00338   return rv;
00339 }
00340 
00341 /* void newValueSpecifiedUnits (in unsigned short unitType, in float valueInSpecifiedUnits); */
00342 NS_IMETHODIMP
00343 nsSVGAngle::NewValueSpecifiedUnits(PRUint16 unitType, float valueInSpecifiedUnits)
00344 {
00345   if (!IsValidUnitType(unitType)) return NS_ERROR_FAILURE;
00346 
00347   WillModify();
00348   mIsAuto                = PR_FALSE;
00349   mValueInSpecifiedUnits = valueInSpecifiedUnits;
00350   mSpecifiedUnitType     = unitType;
00351   DidModify();
00352   
00353   return NS_OK;
00354 }
00355 
00356 /* void convertToSpecifiedUnits (in unsigned short unitType); */
00357 NS_IMETHODIMP
00358 nsSVGAngle::ConvertToSpecifiedUnits(PRUint16 unitType)
00359 {
00360   if (!IsValidUnitType(unitType)) return NS_ERROR_FAILURE;
00361 
00362   float valueInUserUnits;
00363   GetValue(&valueInUserUnits);
00364   mSpecifiedUnitType = unitType;
00365   SetValue(valueInUserUnits);
00366   
00367   return NS_OK;
00368 }
00369 
00370 
00371 //----------------------------------------------------------------------
00372 // Implementation helpers:
00373 
00374 
00375 void nsSVGAngle::GetUnitString(nsAString& unit)
00376 {
00377   nsIAtom* UnitAtom = nsnull;
00378   
00379   switch (mSpecifiedUnitType) {
00380   case SVG_ANGLETYPE_UNSPECIFIED:
00381     UnitAtom = nsnull;
00382     break;
00383   case SVG_ANGLETYPE_DEG:
00384     UnitAtom = nsSVGAtoms::deg;
00385     break;
00386   case SVG_ANGLETYPE_GRAD:
00387     UnitAtom = nsSVGAtoms::grad;
00388     break;
00389   case SVG_ANGLETYPE_RAD:
00390     UnitAtom = nsSVGAtoms::rad;
00391     break;
00392   default:
00393     NS_ASSERTION(PR_FALSE, "unknown unit");
00394     break;
00395   }
00396   if (!UnitAtom) return;
00397 
00398   UnitAtom->ToString(unit);
00399 }
00400 
00401 PRUint16 nsSVGAngle::GetUnitTypeForString(const char* unitStr)
00402 {
00403   if (!unitStr || *unitStr=='\0') return SVG_ANGLETYPE_UNSPECIFIED;
00404                    
00405   nsCOMPtr<nsIAtom> unitAtom = do_GetAtom(unitStr);
00406 
00407   if (unitAtom == nsSVGAtoms::deg)
00408     return SVG_ANGLETYPE_DEG;
00409   else if (unitAtom == nsSVGAtoms::grad)
00410     return SVG_ANGLETYPE_GRAD;
00411   else if (unitAtom == nsSVGAtoms::rad)
00412     return SVG_ANGLETYPE_RAD;
00413 
00414   return SVG_ANGLETYPE_UNKNOWN;
00415 }
00416 
00417 PRBool nsSVGAngle::IsValidUnitType(PRUint16 unit)
00418 {
00419   if (unit>0 && unit<=4)
00420     return PR_TRUE;
00421 
00422   return PR_FALSE;
00423 }