1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "mozilla/dom/SVGMatrix.h"
8 #include "nsError.h"
9 #include <math.h>
10 #include "mozilla/dom/SVGMatrixBinding.h"
11 #include "mozilla/FloatingPoint.h"
12 
13 const double radPerDegree = 2.0 * M_PI / 360.0;
14 
15 namespace mozilla {
16 namespace dom {
17 
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SVGMatrix,mTransform)18 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SVGMatrix, mTransform)
19 
20 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(SVGMatrix, AddRef)
21 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(SVGMatrix, Release)
22 
23 SVGTransform*
24 SVGMatrix::GetParentObject() const
25 {
26   return mTransform;
27 }
28 
29 JSObject*
WrapObject(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)30 SVGMatrix::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
31 {
32   return SVGMatrixBinding::Wrap(aCx, this, aGivenProto);
33 }
34 
35 void
SetA(float aA,ErrorResult & rv)36 SVGMatrix::SetA(float aA, ErrorResult& rv)
37 {
38   if (IsAnimVal()) {
39     rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
40     return;
41   }
42 
43   gfxMatrix mx = GetMatrix();
44   mx._11 = aA;
45   SetMatrix(mx);
46 }
47 
48 void
SetB(float aB,ErrorResult & rv)49 SVGMatrix::SetB(float aB, ErrorResult& rv)
50 {
51   if (IsAnimVal()) {
52     rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
53     return;
54   }
55 
56   gfxMatrix mx = GetMatrix();
57   mx._12 = aB;
58   SetMatrix(mx);
59 }
60 
61 void
SetC(float aC,ErrorResult & rv)62 SVGMatrix::SetC(float aC, ErrorResult& rv)
63 {
64   if (IsAnimVal()) {
65     rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
66     return;
67   }
68 
69   gfxMatrix mx = GetMatrix();
70   mx._21 = aC;
71   SetMatrix(mx);
72 }
73 
74 void
SetD(float aD,ErrorResult & rv)75 SVGMatrix::SetD(float aD, ErrorResult& rv)
76 {
77   if (IsAnimVal()) {
78     rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
79     return;
80   }
81 
82   gfxMatrix mx = GetMatrix();
83   mx._22 = aD;
84   SetMatrix(mx);
85 }
86 
87 void
SetE(float aE,ErrorResult & rv)88 SVGMatrix::SetE(float aE, ErrorResult& rv)
89 {
90   if (IsAnimVal()) {
91     rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
92     return;
93   }
94 
95   gfxMatrix mx = GetMatrix();
96   mx._31 = aE;
97   SetMatrix(mx);
98 }
99 
100 void
SetF(float aF,ErrorResult & rv)101 SVGMatrix::SetF(float aF, ErrorResult& rv)
102 {
103   if (IsAnimVal()) {
104     rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
105     return;
106   }
107 
108   gfxMatrix mx = GetMatrix();
109   mx._32 = aF;
110   SetMatrix(mx);
111 }
112 
113 already_AddRefed<SVGMatrix>
Multiply(SVGMatrix & aMatrix)114 SVGMatrix::Multiply(SVGMatrix& aMatrix)
115 {
116   RefPtr<SVGMatrix> matrix = new SVGMatrix(aMatrix.GetMatrix() * GetMatrix());
117   return matrix.forget();
118 }
119 
120 already_AddRefed<SVGMatrix>
Inverse(ErrorResult & rv)121 SVGMatrix::Inverse(ErrorResult& rv)
122 {
123   gfxMatrix mat = GetMatrix();
124   if (!mat.Invert()) {
125     rv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
126     return nullptr;
127   }
128   RefPtr<SVGMatrix> matrix = new SVGMatrix(mat);
129   return matrix.forget();
130 }
131 
132 already_AddRefed<SVGMatrix>
Translate(float x,float y)133 SVGMatrix::Translate(float x, float y)
134 {
135   RefPtr<SVGMatrix> matrix =
136     new SVGMatrix(gfxMatrix(GetMatrix()).Translate(gfxPoint(x, y)));
137   return matrix.forget();
138 }
139 
140 already_AddRefed<SVGMatrix>
Scale(float scaleFactor)141 SVGMatrix::Scale(float scaleFactor)
142 {
143   return ScaleNonUniform(scaleFactor, scaleFactor);
144 }
145 
146 already_AddRefed<SVGMatrix>
ScaleNonUniform(float scaleFactorX,float scaleFactorY)147 SVGMatrix::ScaleNonUniform(float scaleFactorX,
148                            float scaleFactorY)
149 {
150   RefPtr<SVGMatrix> matrix =
151     new SVGMatrix(gfxMatrix(GetMatrix()).Scale(scaleFactorX, scaleFactorY));
152   return matrix.forget();
153 }
154 
155 already_AddRefed<SVGMatrix>
Rotate(float angle)156 SVGMatrix::Rotate(float angle)
157 {
158   RefPtr<SVGMatrix> matrix =
159     new SVGMatrix(gfxMatrix(GetMatrix()).Rotate(angle*radPerDegree));
160   return matrix.forget();
161 }
162 
163 already_AddRefed<SVGMatrix>
RotateFromVector(float x,float y,ErrorResult & rv)164 SVGMatrix::RotateFromVector(float x, float y, ErrorResult& rv)
165 {
166   if (x == 0.0 || y == 0.0) {
167     rv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
168     return nullptr;
169   }
170 
171   RefPtr<SVGMatrix> matrix =
172     new SVGMatrix(gfxMatrix(GetMatrix()).Rotate(atan2(y, x)));
173   return matrix.forget();
174 }
175 
176 already_AddRefed<SVGMatrix>
FlipX()177 SVGMatrix::FlipX()
178 {
179   const gfxMatrix& mx = GetMatrix();
180   RefPtr<SVGMatrix> matrix =
181     new SVGMatrix(gfxMatrix(-mx._11, -mx._12, mx._21, mx._22, mx._31, mx._32));
182   return matrix.forget();
183 }
184 
185 already_AddRefed<SVGMatrix>
FlipY()186 SVGMatrix::FlipY()
187 {
188   const gfxMatrix& mx = GetMatrix();
189   RefPtr<SVGMatrix> matrix =
190     new SVGMatrix(gfxMatrix(mx._11, mx._12, -mx._21, -mx._22, mx._31, mx._32));
191   return matrix.forget();
192 }
193 
194 already_AddRefed<SVGMatrix>
SkewX(float angle,ErrorResult & rv)195 SVGMatrix::SkewX(float angle, ErrorResult& rv)
196 {
197   double ta = tan( angle*radPerDegree );
198   if (!IsFinite(ta)) {
199     rv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
200     return nullptr;
201   }
202 
203   const gfxMatrix& mx = GetMatrix();
204   gfxMatrix skewMx(mx._11, mx._12,
205                    (float) (mx._21 + mx._11*ta), (float) (mx._22 + mx._12*ta),
206                    mx._31, mx._32);
207   RefPtr<SVGMatrix> matrix = new SVGMatrix(skewMx);
208   return matrix.forget();
209 }
210 
211 already_AddRefed<SVGMatrix>
SkewY(float angle,ErrorResult & rv)212 SVGMatrix::SkewY(float angle, ErrorResult& rv)
213 {
214   double ta = tan( angle*radPerDegree );
215   if (!IsFinite(ta)) {
216     rv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
217     return nullptr;
218   }
219 
220   const gfxMatrix& mx = GetMatrix();
221   gfxMatrix skewMx((float) (mx._11 + mx._21*ta), (float) (mx._12 + mx._22*ta),
222                    mx._21, mx._22,
223                    mx._31, mx._32);
224 
225   RefPtr<SVGMatrix> matrix = new SVGMatrix(skewMx);
226   return matrix.forget();
227 }
228 
229 } // namespace dom
230 } // namespace mozilla
231