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/WebKitCSSMatrix.h"
8
9 #include "mozilla/dom/BindingUtils.h"
10 #include "mozilla/dom/WebKitCSSMatrixBinding.h"
11 #include "mozilla/Preferences.h"
12 #include "nsCSSParser.h"
13 #include "nsStyleTransformMatrix.h"
14 #include "RuleNodeCacheConditions.h"
15
16 namespace mozilla {
17 namespace dom {
18
19 static const double sRadPerDegree = 2.0 * M_PI / 360.0;
20
21 bool
FeatureEnabled(JSContext * aCx,JSObject * aObj)22 WebKitCSSMatrix::FeatureEnabled(JSContext* aCx, JSObject* aObj)
23 {
24 return Preferences::GetBool("layout.css.DOMMatrix.enabled", false) &&
25 Preferences::GetBool("layout.css.prefixes.webkit", false);
26 }
27
28 already_AddRefed<WebKitCSSMatrix>
Constructor(const GlobalObject & aGlobal,ErrorResult & aRv)29 WebKitCSSMatrix::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
30 {
31 RefPtr<WebKitCSSMatrix> obj = new WebKitCSSMatrix(aGlobal.GetAsSupports());
32 return obj.forget();
33 }
34
35 already_AddRefed<WebKitCSSMatrix>
Constructor(const GlobalObject & aGlobal,const nsAString & aTransformList,ErrorResult & aRv)36 WebKitCSSMatrix::Constructor(const GlobalObject& aGlobal,
37 const nsAString& aTransformList, ErrorResult& aRv)
38 {
39 RefPtr<WebKitCSSMatrix> obj = new WebKitCSSMatrix(aGlobal.GetAsSupports());
40 obj = obj->SetMatrixValue(aTransformList, aRv);
41 return obj.forget();
42 }
43
44 already_AddRefed<WebKitCSSMatrix>
Constructor(const GlobalObject & aGlobal,const DOMMatrixReadOnly & aOther,ErrorResult & aRv)45 WebKitCSSMatrix::Constructor(const GlobalObject& aGlobal,
46 const DOMMatrixReadOnly& aOther, ErrorResult& aRv)
47 {
48 RefPtr<WebKitCSSMatrix> obj = new WebKitCSSMatrix(aGlobal.GetAsSupports(),
49 aOther);
50 return obj.forget();
51 }
52
53 JSObject*
WrapObject(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)54 WebKitCSSMatrix::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
55 {
56 return WebKitCSSMatrixBinding::Wrap(aCx, this, aGivenProto);
57 }
58
59 WebKitCSSMatrix*
SetMatrixValue(const nsAString & aTransformList,ErrorResult & aRv)60 WebKitCSSMatrix::SetMatrixValue(const nsAString& aTransformList,
61 ErrorResult& aRv)
62 {
63 // An empty string is a no-op.
64 if (aTransformList.IsEmpty()) {
65 return this;
66 }
67
68 nsCSSValue value;
69 nsCSSParser parser;
70 bool parseSuccess = parser.ParseTransformProperty(aTransformList,
71 true,
72 value);
73 if (!parseSuccess) {
74 aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
75 return nullptr;
76 }
77
78 // A value of "none" results in a 2D identity matrix.
79 if (value.GetUnit() == eCSSUnit_None) {
80 mMatrix3D = nullptr;
81 mMatrix2D = new gfx::Matrix();
82 return this;
83 }
84
85 // A value other than a transform-list is a syntax error.
86 if (value.GetUnit() != eCSSUnit_SharedList) {
87 aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
88 return nullptr;
89 }
90
91 RuleNodeCacheConditions dummy;
92 nsStyleTransformMatrix::TransformReferenceBox dummyBox;
93 bool contains3dTransform = false;
94 gfx::Matrix4x4 transform = nsStyleTransformMatrix::ReadTransforms(
95 value.GetSharedListValue()->mHead,
96 nullptr, nullptr, dummy, dummyBox,
97 nsPresContext::AppUnitsPerCSSPixel(),
98 &contains3dTransform);
99
100 if (!contains3dTransform) {
101 mMatrix3D = nullptr;
102 mMatrix2D = new gfx::Matrix();
103
104 SetA(transform._11);
105 SetB(transform._12);
106 SetC(transform._21);
107 SetD(transform._22);
108 SetE(transform._41);
109 SetF(transform._42);
110 } else {
111 mMatrix3D = new gfx::Matrix4x4(transform);
112 mMatrix2D = nullptr;
113 }
114
115 return this;
116 }
117
118 already_AddRefed<WebKitCSSMatrix>
Multiply(const WebKitCSSMatrix & other) const119 WebKitCSSMatrix::Multiply(const WebKitCSSMatrix& other) const
120 {
121 RefPtr<WebKitCSSMatrix> retval = new WebKitCSSMatrix(mParent, *this);
122 retval->MultiplySelf(other);
123
124 return retval.forget();
125 }
126
127 already_AddRefed<WebKitCSSMatrix>
Inverse(ErrorResult & aRv) const128 WebKitCSSMatrix::Inverse(ErrorResult& aRv) const
129 {
130 RefPtr<WebKitCSSMatrix> retval = new WebKitCSSMatrix(mParent, *this);
131 retval->InvertSelfThrow(aRv);
132 if (NS_WARN_IF(aRv.Failed())) {
133 return nullptr;
134 }
135
136 return retval.forget();
137 }
138
139 WebKitCSSMatrix*
InvertSelfThrow(ErrorResult & aRv)140 WebKitCSSMatrix::InvertSelfThrow(ErrorResult& aRv)
141 {
142 if (mMatrix3D) {
143 if (!mMatrix3D->Invert()) {
144 aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
145 return nullptr;
146 }
147 } else if (!mMatrix2D->Invert()) {
148 aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
149 return nullptr;
150 }
151
152 return this;
153 }
154
155 already_AddRefed<WebKitCSSMatrix>
Translate(double aTx,double aTy,double aTz) const156 WebKitCSSMatrix::Translate(double aTx,
157 double aTy,
158 double aTz) const
159 {
160 RefPtr<WebKitCSSMatrix> retval = new WebKitCSSMatrix(mParent, *this);
161 retval->TranslateSelf(aTx, aTy, aTz);
162
163 return retval.forget();
164 }
165
166 already_AddRefed<WebKitCSSMatrix>
Scale(double aScaleX,const Optional<double> & aScaleY,double aScaleZ) const167 WebKitCSSMatrix::Scale(double aScaleX,
168 const Optional<double>& aScaleY,
169 double aScaleZ) const
170 {
171 double scaleX = aScaleX;
172 double scaleY = aScaleY.WasPassed() ? aScaleY.Value() : scaleX;
173 double scaleZ = aScaleZ;
174
175 RefPtr<WebKitCSSMatrix> retval = new WebKitCSSMatrix(mParent, *this);
176 retval->ScaleNonUniformSelf(scaleX, scaleY, scaleZ);
177
178 return retval.forget();
179 }
180
181 already_AddRefed<WebKitCSSMatrix>
Rotate(double aRotX,const Optional<double> & aRotY,const Optional<double> & aRotZ) const182 WebKitCSSMatrix::Rotate(double aRotX,
183 const Optional<double>& aRotY,
184 const Optional<double>& aRotZ) const
185 {
186 double rotX = aRotX;
187 double rotY;
188 double rotZ;
189
190 if (!aRotY.WasPassed() && !aRotZ.WasPassed()) {
191 rotZ = rotX;
192 rotX = 0;
193 rotY = 0;
194 } else {
195 rotY = aRotY.WasPassed() ? aRotY.Value() : 0;
196 rotZ = aRotZ.WasPassed() ? aRotZ.Value() : 0;
197 }
198
199 RefPtr<WebKitCSSMatrix> retval = new WebKitCSSMatrix(mParent, *this);
200 retval->Rotate3dSelf(rotX, rotY, rotZ);
201
202 return retval.forget();
203 }
204
205 WebKitCSSMatrix*
Rotate3dSelf(double aRotX,double aRotY,double aRotZ)206 WebKitCSSMatrix::Rotate3dSelf(double aRotX,
207 double aRotY,
208 double aRotZ)
209 {
210 if (aRotX != 0 || aRotY != 0) {
211 Ensure3DMatrix();
212 }
213
214 if (mMatrix3D) {
215 if (fmod(aRotZ, 360) != 0) {
216 mMatrix3D->RotateZ(aRotZ * sRadPerDegree);
217 }
218 if (fmod(aRotY, 360) != 0) {
219 mMatrix3D->RotateY(aRotY * sRadPerDegree);
220 }
221 if (fmod(aRotX, 360) != 0) {
222 mMatrix3D->RotateX(aRotX * sRadPerDegree);
223 }
224 } else if (fmod(aRotZ, 360) != 0) {
225 mMatrix2D->PreRotate(aRotZ * sRadPerDegree);
226 }
227
228 return this;
229 }
230
231 already_AddRefed<WebKitCSSMatrix>
RotateAxisAngle(double aX,double aY,double aZ,double aAngle) const232 WebKitCSSMatrix::RotateAxisAngle(double aX,
233 double aY,
234 double aZ,
235 double aAngle) const
236 {
237 RefPtr<WebKitCSSMatrix> retval = new WebKitCSSMatrix(mParent, *this);
238 retval->RotateAxisAngleSelf(aX, aY, aZ, aAngle);
239
240 return retval.forget();
241 }
242
243 already_AddRefed<WebKitCSSMatrix>
SkewX(double aSx) const244 WebKitCSSMatrix::SkewX(double aSx) const
245 {
246 RefPtr<WebKitCSSMatrix> retval = new WebKitCSSMatrix(mParent, *this);
247 retval->SkewXSelf(aSx);
248
249 return retval.forget();
250 }
251
252 already_AddRefed<WebKitCSSMatrix>
SkewY(double aSy) const253 WebKitCSSMatrix::SkewY(double aSy) const
254 {
255 RefPtr<WebKitCSSMatrix> retval = new WebKitCSSMatrix(mParent, *this);
256 retval->SkewYSelf(aSy);
257
258 return retval.forget();
259 }
260
261 } // namespace dom
262 } // namespace mozilla
263