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 "SVGTransform.h"
8 
9 #include "nsError.h"
10 #include "nsContentUtils.h"  // for NS_ENSURE_FINITE
11 #include "nsTextFormatter.h"
12 
13 namespace {
14 const double kRadPerDegree = 2.0 * M_PI / 360.0;
15 }  // namespace
16 
17 namespace mozilla {
18 
19 using namespace dom::SVGTransform_Binding;
20 
GetValueAsString(nsAString & aValue) const21 void SVGTransform::GetValueAsString(nsAString& aValue) const {
22   switch (mType) {
23     case SVG_TRANSFORM_TRANSLATE:
24       // The spec say that if Y is not provided, it is assumed to be zero.
25       if (mMatrix._32 != 0)
26         nsTextFormatter::ssprintf(aValue, u"translate(%g, %g)", mMatrix._31,
27                                   mMatrix._32);
28       else
29         nsTextFormatter::ssprintf(aValue, u"translate(%g)", mMatrix._31);
30       break;
31     case SVG_TRANSFORM_ROTATE:
32       if (mOriginX != 0.0f || mOriginY != 0.0f)
33         nsTextFormatter::ssprintf(aValue, u"rotate(%g, %g, %g)", mAngle,
34                                   mOriginX, mOriginY);
35       else
36         nsTextFormatter::ssprintf(aValue, u"rotate(%g)", mAngle);
37       break;
38     case SVG_TRANSFORM_SCALE:
39       if (mMatrix._11 != mMatrix._22)
40         nsTextFormatter::ssprintf(aValue, u"scale(%g, %g)", mMatrix._11,
41                                   mMatrix._22);
42       else
43         nsTextFormatter::ssprintf(aValue, u"scale(%g)", mMatrix._11);
44       break;
45     case SVG_TRANSFORM_SKEWX:
46       nsTextFormatter::ssprintf(aValue, u"skewX(%g)", mAngle);
47       break;
48     case SVG_TRANSFORM_SKEWY:
49       nsTextFormatter::ssprintf(aValue, u"skewY(%g)", mAngle);
50       break;
51     case SVG_TRANSFORM_MATRIX:
52       nsTextFormatter::ssprintf(aValue, u"matrix(%g, %g, %g, %g, %g, %g)",
53                                 mMatrix._11, mMatrix._12, mMatrix._21,
54                                 mMatrix._22, mMatrix._31, mMatrix._32);
55       break;
56     default:
57       aValue.Truncate();
58       NS_ERROR("unknown transformation type");
59       break;
60   }
61 }
62 
SetMatrix(const gfxMatrix & aMatrix)63 void SVGTransform::SetMatrix(const gfxMatrix& aMatrix) {
64   mType = SVG_TRANSFORM_MATRIX;
65   mMatrix = aMatrix;
66   // We set the other members here too, since operator== requires it and
67   // the DOM requires it for mAngle.
68   mAngle = 0.f;
69   mOriginX = 0.f;
70   mOriginY = 0.f;
71 }
72 
SetTranslate(float aTx,float aTy)73 void SVGTransform::SetTranslate(float aTx, float aTy) {
74   mType = SVG_TRANSFORM_TRANSLATE;
75   mMatrix = gfxMatrix::Translation(aTx, aTy);
76   mAngle = 0.f;
77   mOriginX = 0.f;
78   mOriginY = 0.f;
79 }
80 
SetScale(float aSx,float aSy)81 void SVGTransform::SetScale(float aSx, float aSy) {
82   mType = SVG_TRANSFORM_SCALE;
83   mMatrix = gfxMatrix::Scaling(aSx, aSy);
84   mAngle = 0.f;
85   mOriginX = 0.f;
86   mOriginY = 0.f;
87 }
88 
SetRotate(float aAngle,float aCx,float aCy)89 void SVGTransform::SetRotate(float aAngle, float aCx, float aCy) {
90   mType = SVG_TRANSFORM_ROTATE;
91   mMatrix = gfxMatrix::Translation(aCx, aCy)
92                 .PreRotate(aAngle * kRadPerDegree)
93                 .PreTranslate(-aCx, -aCy);
94   mAngle = aAngle;
95   mOriginX = aCx;
96   mOriginY = aCy;
97 }
98 
SetSkewX(float aAngle)99 nsresult SVGTransform::SetSkewX(float aAngle) {
100   double ta = tan(aAngle * kRadPerDegree);
101   // No one actually cares about the exact error return type here.
102   NS_ENSURE_FINITE(ta, NS_ERROR_INVALID_ARG);
103 
104   mType = SVG_TRANSFORM_SKEWX;
105   mMatrix = gfxMatrix();
106   mMatrix._21 = ta;
107   mAngle = aAngle;
108   mOriginX = 0.f;
109   mOriginY = 0.f;
110   return NS_OK;
111 }
112 
SetSkewY(float aAngle)113 nsresult SVGTransform::SetSkewY(float aAngle) {
114   double ta = tan(aAngle * kRadPerDegree);
115   // No one actually cares about the exact error return type here.
116   NS_ENSURE_FINITE(ta, NS_ERROR_INVALID_ARG);
117 
118   mType = SVG_TRANSFORM_SKEWY;
119   mMatrix = gfxMatrix();
120   mMatrix._12 = ta;
121   mAngle = aAngle;
122   mOriginX = 0.f;
123   mOriginY = 0.f;
124   return NS_OK;
125 }
126 
SVGTransformSMILData(const SVGTransform & aTransform)127 SVGTransformSMILData::SVGTransformSMILData(const SVGTransform& aTransform)
128     : mTransformType(aTransform.Type()) {
129   MOZ_ASSERT(mTransformType >= SVG_TRANSFORM_MATRIX &&
130                  mTransformType <= SVG_TRANSFORM_SKEWY,
131              "Unexpected transform type");
132 
133   for (uint32_t i = 0; i < NUM_STORED_PARAMS; ++i) {
134     mParams[i] = 0.f;
135   }
136 
137   switch (mTransformType) {
138     case SVG_TRANSFORM_MATRIX: {
139       const gfxMatrix& mx = aTransform.GetMatrix();
140       mParams[0] = static_cast<float>(mx._11);
141       mParams[1] = static_cast<float>(mx._12);
142       mParams[2] = static_cast<float>(mx._21);
143       mParams[3] = static_cast<float>(mx._22);
144       mParams[4] = static_cast<float>(mx._31);
145       mParams[5] = static_cast<float>(mx._32);
146       break;
147     }
148     case SVG_TRANSFORM_TRANSLATE: {
149       const gfxMatrix& mx = aTransform.GetMatrix();
150       mParams[0] = static_cast<float>(mx._31);
151       mParams[1] = static_cast<float>(mx._32);
152       break;
153     }
154     case SVG_TRANSFORM_SCALE: {
155       const gfxMatrix& mx = aTransform.GetMatrix();
156       mParams[0] = static_cast<float>(mx._11);
157       mParams[1] = static_cast<float>(mx._22);
158       break;
159     }
160     case SVG_TRANSFORM_ROTATE:
161       mParams[0] = aTransform.Angle();
162       aTransform.GetRotationOrigin(mParams[1], mParams[2]);
163       break;
164 
165     case SVG_TRANSFORM_SKEWX:
166     case SVG_TRANSFORM_SKEWY:
167       mParams[0] = aTransform.Angle();
168       break;
169 
170     default:
171       MOZ_ASSERT_UNREACHABLE("Unexpected transform type");
172       break;
173   }
174 }
175 
ToSVGTransform() const176 SVGTransform SVGTransformSMILData::ToSVGTransform() const {
177   SVGTransform result;
178 
179   switch (mTransformType) {
180     case SVG_TRANSFORM_MATRIX:
181       result.SetMatrix(gfxMatrix(mParams[0], mParams[1], mParams[2], mParams[3],
182                                  mParams[4], mParams[5]));
183       break;
184 
185     case SVG_TRANSFORM_TRANSLATE:
186       result.SetTranslate(mParams[0], mParams[1]);
187       break;
188 
189     case SVG_TRANSFORM_SCALE:
190       result.SetScale(mParams[0], mParams[1]);
191       break;
192 
193     case SVG_TRANSFORM_ROTATE:
194       result.SetRotate(mParams[0], mParams[1], mParams[2]);
195       break;
196 
197     case SVG_TRANSFORM_SKEWX:
198       result.SetSkewX(mParams[0]);
199       break;
200 
201     case SVG_TRANSFORM_SKEWY:
202       result.SetSkewY(mParams[0]);
203       break;
204 
205     default:
206       MOZ_ASSERT_UNREACHABLE("Unexpected transform type");
207       break;
208   }
209   return result;
210 }
211 
212 }  // namespace mozilla
213