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