Back to index

lightning-sunbird  0.9+nobinonly
nsSVGTransform.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 "nsSVGTransform.h"
00040 #include "prdtoa.h"
00041 #include "nsSVGMatrix.h"
00042 #include "nsSVGAtoms.h"
00043 #include "nsSVGValue.h"
00044 #include "nsISVGValueUtils.h"
00045 #include "nsISVGValueObserver.h"
00046 #include "nsWeakReference.h"
00047 #include "nsSVGMatrix.h"
00048 #include "nsTextFormatter.h"
00049 #include "nsContentUtils.h"
00050 #include "nsDOMError.h"
00051 
00052 
00054 // nsSVGTransform
00055 
00056 class nsSVGTransform : public nsIDOMSVGTransform,
00057                        public nsSVGValue,
00058                        public nsISVGValueObserver,
00059                        public nsSupportsWeakReference
00060 {
00061 public:
00062   static nsresult Create(nsIDOMSVGTransform** aResult);
00063   
00064 protected:
00065   nsSVGTransform();
00066   ~nsSVGTransform();
00067   nsresult Init();
00068 public:
00069   // nsISupports interface:
00070   NS_DECL_ISUPPORTS
00071 
00072   // nsIDOMSVGTransform interface:
00073   NS_DECL_NSIDOMSVGTRANSFORM
00074 
00075   // nsISVGValue interface:
00076   NS_IMETHOD SetValueString(const nsAString& aValue);
00077   NS_IMETHOD GetValueString(nsAString& aValue);
00078 
00079   // nsISVGValueObserver
00080   NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
00081                                      modificationType aModType);
00082   NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
00083                                      modificationType aModType);
00084 
00085 protected:
00086   nsCOMPtr<nsIDOMSVGMatrix> mMatrix;
00087   float mAngle, mOriginX, mOriginY;
00088   PRUint16 mType;
00089 };
00090 
00091 
00092 //----------------------------------------------------------------------
00093 // Implementation
00094 
00095 nsresult
00096 nsSVGTransform::Create(nsIDOMSVGTransform** aResult)
00097 {
00098   nsSVGTransform *pl = new nsSVGTransform();
00099   NS_ENSURE_TRUE(pl, NS_ERROR_OUT_OF_MEMORY);
00100   NS_ADDREF(pl);
00101   if (NS_FAILED(pl->Init())) {
00102     NS_RELEASE(pl);
00103     *aResult = nsnull;
00104     return NS_ERROR_FAILURE;
00105   }
00106   *aResult = pl;
00107   return NS_OK;
00108 }
00109 
00110 
00111 nsSVGTransform::nsSVGTransform()
00112     : mAngle(0.0f),
00113       mOriginX(0.0f),
00114       mOriginY(0.0f),
00115       mType( SVG_TRANSFORM_MATRIX )
00116 {
00117 }
00118 
00119 nsSVGTransform::~nsSVGTransform()
00120 {
00121   NS_REMOVE_SVGVALUE_OBSERVER(mMatrix);
00122 }
00123 
00124 nsresult nsSVGTransform::Init()
00125 {
00126   nsresult rv = NS_NewSVGMatrix(getter_AddRefs(mMatrix));
00127   NS_ADD_SVGVALUE_OBSERVER(mMatrix);
00128   return rv;
00129 }
00130 
00131 //----------------------------------------------------------------------
00132 // nsISupports methods:
00133 
00134 NS_IMPL_ADDREF(nsSVGTransform)
00135 NS_IMPL_RELEASE(nsSVGTransform)
00136 
00137 NS_INTERFACE_MAP_BEGIN(nsSVGTransform)
00138   NS_INTERFACE_MAP_ENTRY(nsISVGValue)
00139   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGTransform)
00140   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00141   NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
00142   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGTransform)
00143   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGValue)
00144 NS_INTERFACE_MAP_END
00145 
00146 
00147 //----------------------------------------------------------------------
00148 // nsISVGValue methods:
00149 
00150 NS_IMETHODIMP
00151 nsSVGTransform::SetValueString(const nsAString& aValue)
00152 {
00153   NS_NOTYETIMPLEMENTED("nsSVGTransform::SetValueString");
00154   return NS_ERROR_NOT_IMPLEMENTED;
00155 }
00156 
00157 NS_IMETHODIMP
00158 nsSVGTransform::GetValueString(nsAString& aValue)
00159 {
00160   aValue.Truncate();
00161   PRUnichar buf[256];
00162   
00163   switch (mType) {
00164     case nsIDOMSVGTransform::SVG_TRANSFORM_TRANSLATE:
00165       {
00166         float dx, dy;
00167         mMatrix->GetE(&dx);
00168         mMatrix->GetF(&dy);
00169         if (dy != 0.0f)
00170           nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar), NS_LITERAL_STRING("translate(%g, %g)").get(), dx, dy);
00171         else
00172           nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar), NS_LITERAL_STRING("translate(%g)").get(), dx);
00173       }
00174       break;
00175     case nsIDOMSVGTransform::SVG_TRANSFORM_ROTATE:
00176       {
00177         if (mOriginX != 0.0f || mOriginY != 0.0f)
00178           nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
00179                                     NS_LITERAL_STRING("rotate(%g, %g, %g)").get(),
00180                                     mAngle, mOriginX, mOriginY);
00181         else
00182           nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
00183                                     NS_LITERAL_STRING("rotate(%g)").get(), mAngle);
00184       }
00185       break;        
00186     case nsIDOMSVGTransform::SVG_TRANSFORM_SCALE:
00187       {
00188         float sx, sy;
00189         mMatrix->GetA(&sx);
00190         mMatrix->GetD(&sy);
00191         if (sy != 0.0f)
00192           nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
00193                                     NS_LITERAL_STRING("scale(%g, %g)").get(), sx, sy);
00194         else
00195           nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
00196                                     NS_LITERAL_STRING("scale(%g)").get(), sx);
00197       }
00198       break;
00199     case nsIDOMSVGTransform::SVG_TRANSFORM_SKEWX:
00200       {
00201         nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
00202                                   NS_LITERAL_STRING("skewX(%g)").get(), mAngle);
00203       }
00204       break;
00205     case nsIDOMSVGTransform::SVG_TRANSFORM_SKEWY:
00206       {
00207         nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
00208                                   NS_LITERAL_STRING("skewY(%g)").get(), mAngle);
00209       }
00210       break;
00211     case nsIDOMSVGTransform::SVG_TRANSFORM_MATRIX:
00212       {
00213         float a,b,c,d,e,f;
00214         mMatrix->GetA(&a);
00215         mMatrix->GetB(&b);
00216         mMatrix->GetC(&c);
00217         mMatrix->GetD(&d);
00218         mMatrix->GetE(&e);
00219         mMatrix->GetF(&f);
00220         nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
00221                                   NS_LITERAL_STRING("matrix(%g, %g, %g, %g, %g, %g)").get(),
00222                                   a, b, c, d, e, f);
00223       }
00224       break;
00225     default:
00226       buf[0] = '\0';
00227       NS_ERROR("unknown transformation type");
00228       break;
00229   }
00230 
00231   aValue.Append(buf);
00232   
00233   return NS_OK;
00234 }
00235 
00236 
00237 //----------------------------------------------------------------------
00238 // nsISVGValueObserver methods:
00239 
00240 NS_IMETHODIMP nsSVGTransform::WillModifySVGObservable(nsISVGValue* observable,
00241                                                       modificationType aModType)
00242 {
00243   WillModify();
00244   return NS_OK;
00245 }
00246 
00247 NS_IMETHODIMP nsSVGTransform::DidModifySVGObservable (nsISVGValue* observable,
00248                                                       modificationType aModType)
00249 {
00250   DidModify();
00251   return NS_OK;
00252 }
00253 
00254 
00255 //----------------------------------------------------------------------
00256 // nsIDOMSVGTransform methods:
00257 
00258 /* readonly attribute unsigned short type; */
00259 NS_IMETHODIMP nsSVGTransform::GetType(PRUint16 *aType)
00260 {
00261   *aType = mType;
00262   return NS_OK;
00263 }
00264 
00265 /* readonly attribute nsIDOMSVGMatrix matrix; */
00266 NS_IMETHODIMP nsSVGTransform::GetMatrix(nsIDOMSVGMatrix * *aMatrix)
00267 {
00268   // XXX should we make a copy here? is the matrix supposed to be live
00269   // or not?
00270   *aMatrix = mMatrix;
00271   NS_IF_ADDREF(*aMatrix);
00272   return NS_OK;
00273 }
00274 
00275 /* readonly attribute float angle; */
00276 NS_IMETHODIMP nsSVGTransform::GetAngle(float *aAngle)
00277 {
00278   *aAngle = mAngle;
00279   return NS_OK;
00280 }
00281 
00282 /* void setMatrix (in nsIDOMSVGMatrix matrix); */
00283 NS_IMETHODIMP nsSVGTransform::SetMatrix(nsIDOMSVGMatrix *matrix)
00284 {
00285   if (!matrix)
00286     return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
00287 
00288   WillModify();
00289 
00290   mType = SVG_TRANSFORM_MATRIX;
00291   mAngle = 0.0f;
00292   mOriginX = 0.0f;
00293   mOriginY = 0.0f;
00294   
00295   // XXX should we copy the matrix instead of replacing?
00296   NS_REMOVE_SVGVALUE_OBSERVER(mMatrix);
00297   mMatrix = matrix;
00298   NS_ADD_SVGVALUE_OBSERVER(mMatrix);
00299 
00300   DidModify();
00301   return NS_OK;
00302 }
00303 
00304 /* void setTranslate (in float tx, in float ty); */
00305 NS_IMETHODIMP nsSVGTransform::SetTranslate(float tx, float ty)
00306 {
00307   WillModify();
00308   
00309   mType = SVG_TRANSFORM_TRANSLATE;
00310   mAngle = 0.0f;
00311   mOriginX = 0.0f;
00312   mOriginY = 0.0f;
00313   mMatrix->SetA(1.0f);
00314   mMatrix->SetB(0.0f);
00315   mMatrix->SetC(0.0f);
00316   mMatrix->SetD(1.0f);
00317   mMatrix->SetE(tx);
00318   mMatrix->SetF(ty);
00319 
00320   DidModify();
00321   return NS_OK;
00322 }
00323 
00324 /* void setScale (in float sx, in float sy); */
00325 NS_IMETHODIMP nsSVGTransform::SetScale(float sx, float sy)
00326 {
00327   WillModify();
00328   
00329   mType = SVG_TRANSFORM_SCALE;
00330   mAngle = 0.0f;
00331   mOriginX = 0.0f;
00332   mOriginY = 0.0f;
00333   mMatrix->SetA(sx);
00334   mMatrix->SetB(0.0f);
00335   mMatrix->SetC(0.0f);
00336   mMatrix->SetD(sy);
00337   mMatrix->SetE(0.0f);
00338   mMatrix->SetF(0.0f);
00339 
00340   DidModify();
00341   return NS_OK;
00342 }
00343 
00344 /* void setRotate (in float angle, in float cx, in float cy); */
00345 NS_IMETHODIMP nsSVGTransform::SetRotate(float angle, float cx, float cy)
00346 {
00347   WillModify();
00348   
00349   mType = SVG_TRANSFORM_ROTATE;
00350   mAngle = angle;
00351   mOriginX = cx;
00352   mOriginY = cy;
00353 
00354   NS_REMOVE_SVGVALUE_OBSERVER(mMatrix);
00355   NS_NewSVGMatrix(getter_AddRefs(mMatrix));
00356   nsCOMPtr<nsIDOMSVGMatrix> temp;
00357   mMatrix->Translate(cx, cy, getter_AddRefs(temp));
00358   mMatrix = temp;
00359   mMatrix->Rotate(angle, getter_AddRefs(temp));
00360   mMatrix = temp;
00361   mMatrix->Translate(-cx,-cy, getter_AddRefs(temp));
00362   mMatrix = temp;
00363   NS_ADD_SVGVALUE_OBSERVER(mMatrix);
00364 
00365   DidModify();
00366   return NS_OK;
00367 }
00368 
00369 /* void setSkewX (in float angle); */
00370 NS_IMETHODIMP nsSVGTransform::SetSkewX(float angle)
00371 {
00372   WillModify();
00373   
00374   mType = SVG_TRANSFORM_SKEWX;
00375   mAngle = angle;
00376 
00377   NS_REMOVE_SVGVALUE_OBSERVER(mMatrix);
00378   NS_NewSVGMatrix(getter_AddRefs(mMatrix));
00379   nsCOMPtr<nsIDOMSVGMatrix> temp;
00380   mMatrix->SkewX(angle, getter_AddRefs(temp));
00381   mMatrix = temp;
00382   NS_ADD_SVGVALUE_OBSERVER(mMatrix);
00383 
00384   DidModify();
00385   return NS_OK;
00386 }
00387 
00388 /* void setSkewY (in float angle); */
00389 NS_IMETHODIMP nsSVGTransform::SetSkewY(float angle)
00390 {
00391   WillModify();
00392   
00393   mType = SVG_TRANSFORM_SKEWY;
00394   mAngle = angle;
00395 
00396   NS_REMOVE_SVGVALUE_OBSERVER(mMatrix);
00397   NS_NewSVGMatrix(getter_AddRefs(mMatrix));
00398   nsCOMPtr<nsIDOMSVGMatrix> temp;
00399   mMatrix->SkewY(angle, getter_AddRefs(temp));
00400   mMatrix = temp;
00401   NS_ADD_SVGVALUE_OBSERVER(mMatrix);
00402 
00403   DidModify();
00404   return NS_OK;
00405 }
00406 
00407 
00408 
00410 // Exported creation functions:
00411 
00412 nsresult
00413 NS_NewSVGTransform(nsIDOMSVGTransform** result)
00414 {
00415   return nsSVGTransform::Create(result);
00416 }