/src/mozilla-central/dom/base/DOMMatrix.cpp
Line | Count | Source (jump to first uncovered line) |
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/DOMMatrix.h" |
8 | | |
9 | | #include "mozilla/dom/BindingUtils.h" |
10 | | #include "mozilla/dom/DOMMatrixBinding.h" |
11 | | #include "mozilla/dom/DOMPoint.h" |
12 | | #include "mozilla/dom/DOMPointBinding.h" |
13 | | #include "mozilla/dom/BindingDeclarations.h" |
14 | | #include "mozilla/dom/ToJSValue.h" |
15 | | #include "mozilla/ServoCSSParser.h" |
16 | | #include "nsGlobalWindowInner.h" |
17 | | #include "nsStyleTransformMatrix.h" |
18 | | #include "nsGlobalWindowInner.h" |
19 | | |
20 | | #include <math.h> |
21 | | |
22 | | namespace mozilla { |
23 | | namespace dom { |
24 | | |
25 | | template <typename T> |
26 | | static void |
27 | | SetDataInMatrix(DOMMatrixReadOnly* aMatrix, const T* aData, int aLength, ErrorResult& aRv); |
28 | | |
29 | | static const double radPerDegree = 2.0 * M_PI / 360.0; |
30 | | |
31 | | NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMMatrixReadOnly, mParent) |
32 | | |
33 | | NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMMatrixReadOnly, AddRef) |
34 | | NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMMatrixReadOnly, Release) |
35 | | |
36 | | JSObject* |
37 | | DOMMatrixReadOnly::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) |
38 | 0 | { |
39 | 0 | return DOMMatrixReadOnly_Binding::Wrap(aCx, this, aGivenProto); |
40 | 0 | } |
41 | | |
42 | | already_AddRefed<DOMMatrixReadOnly> |
43 | | DOMMatrixReadOnly::Constructor( |
44 | | const GlobalObject& aGlobal, |
45 | | const Optional<StringOrUnrestrictedDoubleSequence>& aArg, |
46 | | ErrorResult& aRv) |
47 | 0 | { |
48 | 0 | RefPtr<DOMMatrixReadOnly> rval = new DOMMatrixReadOnly(aGlobal.GetAsSupports()); |
49 | 0 | if (!aArg.WasPassed()) { |
50 | 0 | return rval.forget(); |
51 | 0 | } |
52 | 0 | |
53 | 0 | const auto& arg = aArg.Value(); |
54 | 0 | if (arg.IsString()) { |
55 | 0 | nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(aGlobal.GetAsSupports()); |
56 | 0 | if (!win) { |
57 | 0 | aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>(); |
58 | 0 | return nullptr; |
59 | 0 | } |
60 | 0 | rval->SetMatrixValue(arg.GetAsString(), aRv); |
61 | 0 | } else { |
62 | 0 | const auto& sequence = arg.GetAsUnrestrictedDoubleSequence(); |
63 | 0 | SetDataInMatrix(rval, sequence.Elements(), sequence.Length(), aRv); |
64 | 0 | } |
65 | 0 |
|
66 | 0 | return rval.forget(); |
67 | 0 | } |
68 | | |
69 | | already_AddRefed<DOMMatrix> |
70 | | DOMMatrixReadOnly::Translate(double aTx, |
71 | | double aTy, |
72 | | double aTz) const |
73 | 0 | { |
74 | 0 | RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this); |
75 | 0 | retval->TranslateSelf(aTx, aTy, aTz); |
76 | 0 |
|
77 | 0 | return retval.forget(); |
78 | 0 | } |
79 | | |
80 | | already_AddRefed<DOMMatrix> |
81 | | DOMMatrixReadOnly::Scale(double aScale, |
82 | | double aOriginX, |
83 | | double aOriginY) const |
84 | 0 | { |
85 | 0 | RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this); |
86 | 0 | retval->ScaleSelf(aScale, aOriginX, aOriginY); |
87 | 0 |
|
88 | 0 | return retval.forget(); |
89 | 0 | } |
90 | | |
91 | | already_AddRefed<DOMMatrix> |
92 | | DOMMatrixReadOnly::Scale3d(double aScale, |
93 | | double aOriginX, |
94 | | double aOriginY, |
95 | | double aOriginZ) const |
96 | 0 | { |
97 | 0 | RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this); |
98 | 0 | retval->Scale3dSelf(aScale, aOriginX, aOriginY, aOriginZ); |
99 | 0 |
|
100 | 0 | return retval.forget(); |
101 | 0 | } |
102 | | |
103 | | already_AddRefed<DOMMatrix> |
104 | | DOMMatrixReadOnly::ScaleNonUniform(double aScaleX, |
105 | | double aScaleY, |
106 | | double aScaleZ, |
107 | | double aOriginX, |
108 | | double aOriginY, |
109 | | double aOriginZ) const |
110 | 0 | { |
111 | 0 | RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this); |
112 | 0 | retval->ScaleNonUniformSelf(aScaleX, aScaleY, aScaleZ, aOriginX, aOriginY, aOriginZ); |
113 | 0 |
|
114 | 0 | return retval.forget(); |
115 | 0 | } |
116 | | |
117 | | already_AddRefed<DOMMatrix> |
118 | | DOMMatrixReadOnly::Rotate(double aAngle, |
119 | | double aOriginX , |
120 | | double aOriginY) const |
121 | 0 | { |
122 | 0 | RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this); |
123 | 0 | retval->RotateSelf(aAngle, aOriginX, aOriginY); |
124 | 0 |
|
125 | 0 | return retval.forget(); |
126 | 0 | } |
127 | | |
128 | | already_AddRefed<DOMMatrix> |
129 | | DOMMatrixReadOnly::RotateFromVector(double x, |
130 | | double y) const |
131 | 0 | { |
132 | 0 | RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this); |
133 | 0 | retval->RotateFromVectorSelf(x, y); |
134 | 0 |
|
135 | 0 | return retval.forget(); |
136 | 0 | } |
137 | | |
138 | | already_AddRefed<DOMMatrix> |
139 | | DOMMatrixReadOnly::RotateAxisAngle(double aX, |
140 | | double aY, |
141 | | double aZ, |
142 | | double aAngle) const |
143 | 0 | { |
144 | 0 | RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this); |
145 | 0 | retval->RotateAxisAngleSelf(aX, aY, aZ, aAngle); |
146 | 0 |
|
147 | 0 | return retval.forget(); |
148 | 0 | } |
149 | | |
150 | | already_AddRefed<DOMMatrix> |
151 | | DOMMatrixReadOnly::SkewX(double aSx) const |
152 | 0 | { |
153 | 0 | RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this); |
154 | 0 | retval->SkewXSelf(aSx); |
155 | 0 |
|
156 | 0 | return retval.forget(); |
157 | 0 | } |
158 | | |
159 | | already_AddRefed<DOMMatrix> |
160 | | DOMMatrixReadOnly::SkewY(double aSy) const |
161 | 0 | { |
162 | 0 | RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this); |
163 | 0 | retval->SkewYSelf(aSy); |
164 | 0 |
|
165 | 0 | return retval.forget(); |
166 | 0 | } |
167 | | |
168 | | already_AddRefed<DOMMatrix> |
169 | | DOMMatrixReadOnly::Multiply(const DOMMatrix& other) const |
170 | 0 | { |
171 | 0 | RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this); |
172 | 0 | retval->MultiplySelf(other); |
173 | 0 |
|
174 | 0 | return retval.forget(); |
175 | 0 | } |
176 | | |
177 | | already_AddRefed<DOMMatrix> |
178 | | DOMMatrixReadOnly::FlipX() const |
179 | 0 | { |
180 | 0 | RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this); |
181 | 0 | if (mMatrix3D) { |
182 | 0 | gfx::Matrix4x4 m; |
183 | 0 | m._11 = -1; |
184 | 0 | retval->mMatrix3D = new gfx::Matrix4x4(m * *mMatrix3D); |
185 | 0 | } else { |
186 | 0 | gfx::Matrix m; |
187 | 0 | m._11 = -1; |
188 | 0 | retval->mMatrix2D = new gfx::Matrix(mMatrix2D ? m * *mMatrix2D : m); |
189 | 0 | } |
190 | 0 |
|
191 | 0 | return retval.forget(); |
192 | 0 | } |
193 | | |
194 | | already_AddRefed<DOMMatrix> |
195 | | DOMMatrixReadOnly::FlipY() const |
196 | 0 | { |
197 | 0 | RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this); |
198 | 0 | if (mMatrix3D) { |
199 | 0 | gfx::Matrix4x4 m; |
200 | 0 | m._22 = -1; |
201 | 0 | retval->mMatrix3D = new gfx::Matrix4x4(m * *mMatrix3D); |
202 | 0 | } else { |
203 | 0 | gfx::Matrix m; |
204 | 0 | m._22 = -1; |
205 | 0 | retval->mMatrix2D = new gfx::Matrix(mMatrix2D ? m * *mMatrix2D : m); |
206 | 0 | } |
207 | 0 |
|
208 | 0 | return retval.forget(); |
209 | 0 | } |
210 | | |
211 | | already_AddRefed<DOMMatrix> |
212 | | DOMMatrixReadOnly::Inverse() const |
213 | 0 | { |
214 | 0 | RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this); |
215 | 0 | retval->InvertSelf(); |
216 | 0 |
|
217 | 0 | return retval.forget(); |
218 | 0 | } |
219 | | |
220 | | bool |
221 | | DOMMatrixReadOnly::Is2D() const |
222 | 0 | { |
223 | 0 | return !mMatrix3D; |
224 | 0 | } |
225 | | |
226 | | bool |
227 | | DOMMatrixReadOnly::IsIdentity() const |
228 | 0 | { |
229 | 0 | if (mMatrix3D) { |
230 | 0 | return mMatrix3D->IsIdentity(); |
231 | 0 | } |
232 | 0 | |
233 | 0 | return mMatrix2D->IsIdentity(); |
234 | 0 | } |
235 | | |
236 | | already_AddRefed<DOMPoint> |
237 | | DOMMatrixReadOnly::TransformPoint(const DOMPointInit& point) const |
238 | 0 | { |
239 | 0 | RefPtr<DOMPoint> retval = new DOMPoint(mParent); |
240 | 0 |
|
241 | 0 | if (mMatrix3D) { |
242 | 0 | gfx::Point4D transformedPoint; |
243 | 0 | transformedPoint.x = point.mX; |
244 | 0 | transformedPoint.y = point.mY; |
245 | 0 | transformedPoint.z = point.mZ; |
246 | 0 | transformedPoint.w = point.mW; |
247 | 0 |
|
248 | 0 | transformedPoint = mMatrix3D->TransformPoint(transformedPoint); |
249 | 0 |
|
250 | 0 | retval->SetX(transformedPoint.x); |
251 | 0 | retval->SetY(transformedPoint.y); |
252 | 0 | retval->SetZ(transformedPoint.z); |
253 | 0 | retval->SetW(transformedPoint.w); |
254 | 0 | } else if (point.mZ != 0 || point.mW != 1.0) { |
255 | 0 | gfx::Matrix4x4 tempMatrix(gfx::Matrix4x4::From2D(*mMatrix2D)); |
256 | 0 |
|
257 | 0 | gfx::Point4D transformedPoint; |
258 | 0 | transformedPoint.x = point.mX; |
259 | 0 | transformedPoint.y = point.mY; |
260 | 0 | transformedPoint.z = point.mZ; |
261 | 0 | transformedPoint.w = point.mW; |
262 | 0 |
|
263 | 0 | transformedPoint = tempMatrix.TransformPoint(transformedPoint); |
264 | 0 |
|
265 | 0 | retval->SetX(transformedPoint.x); |
266 | 0 | retval->SetY(transformedPoint.y); |
267 | 0 | retval->SetZ(transformedPoint.z); |
268 | 0 | retval->SetW(transformedPoint.w); |
269 | 0 | } else { |
270 | 0 | gfx::Point transformedPoint; |
271 | 0 | transformedPoint.x = point.mX; |
272 | 0 | transformedPoint.y = point.mY; |
273 | 0 |
|
274 | 0 | transformedPoint = mMatrix2D->TransformPoint(transformedPoint); |
275 | 0 |
|
276 | 0 | retval->SetX(transformedPoint.x); |
277 | 0 | retval->SetY(transformedPoint.y); |
278 | 0 | retval->SetZ(point.mZ); |
279 | 0 | retval->SetW(point.mW); |
280 | 0 | } |
281 | 0 | return retval.forget(); |
282 | 0 | } |
283 | | |
284 | | template <typename T> void GetDataFromMatrix(const DOMMatrixReadOnly* aMatrix, T* aData) |
285 | 0 | { |
286 | 0 | aData[0] = static_cast<T>(aMatrix->M11()); |
287 | 0 | aData[1] = static_cast<T>(aMatrix->M12()); |
288 | 0 | aData[2] = static_cast<T>(aMatrix->M13()); |
289 | 0 | aData[3] = static_cast<T>(aMatrix->M14()); |
290 | 0 | aData[4] = static_cast<T>(aMatrix->M21()); |
291 | 0 | aData[5] = static_cast<T>(aMatrix->M22()); |
292 | 0 | aData[6] = static_cast<T>(aMatrix->M23()); |
293 | 0 | aData[7] = static_cast<T>(aMatrix->M24()); |
294 | 0 | aData[8] = static_cast<T>(aMatrix->M31()); |
295 | 0 | aData[9] = static_cast<T>(aMatrix->M32()); |
296 | 0 | aData[10] = static_cast<T>(aMatrix->M33()); |
297 | 0 | aData[11] = static_cast<T>(aMatrix->M34()); |
298 | 0 | aData[12] = static_cast<T>(aMatrix->M41()); |
299 | 0 | aData[13] = static_cast<T>(aMatrix->M42()); |
300 | 0 | aData[14] = static_cast<T>(aMatrix->M43()); |
301 | 0 | aData[15] = static_cast<T>(aMatrix->M44()); |
302 | 0 | } Unexecuted instantiation: void mozilla::dom::GetDataFromMatrix<float>(mozilla::dom::DOMMatrixReadOnly const*, float*) Unexecuted instantiation: void mozilla::dom::GetDataFromMatrix<double>(mozilla::dom::DOMMatrixReadOnly const*, double*) |
303 | | |
304 | | void |
305 | | DOMMatrixReadOnly::ToFloat32Array(JSContext* aCx, JS::MutableHandle<JSObject*> aResult, ErrorResult& aRv) const |
306 | 0 | { |
307 | 0 | AutoTArray<float, 16> arr; |
308 | 0 | arr.SetLength(16); |
309 | 0 | GetDataFromMatrix(this, arr.Elements()); |
310 | 0 | JS::Rooted<JS::Value> value(aCx); |
311 | 0 | if (!ToJSValue(aCx, TypedArrayCreator<Float32Array>(arr), &value)) { |
312 | 0 | aRv.Throw(NS_ERROR_OUT_OF_MEMORY); |
313 | 0 | return; |
314 | 0 | } |
315 | 0 | aResult.set(&value.toObject()); |
316 | 0 | } |
317 | | |
318 | | void |
319 | | DOMMatrixReadOnly::ToFloat64Array(JSContext* aCx, JS::MutableHandle<JSObject*> aResult, ErrorResult& aRv) const |
320 | 0 | { |
321 | 0 | AutoTArray<double, 16> arr; |
322 | 0 | arr.SetLength(16); |
323 | 0 | GetDataFromMatrix(this, arr.Elements()); |
324 | 0 | JS::Rooted<JS::Value> value(aCx); |
325 | 0 | if (!ToJSValue(aCx, TypedArrayCreator<Float64Array>(arr), &value)) { |
326 | 0 | aRv.Throw(NS_ERROR_OUT_OF_MEMORY); |
327 | 0 | return; |
328 | 0 | } |
329 | 0 | aResult.set(&value.toObject()); |
330 | 0 | } |
331 | | |
332 | | // Convenient way to append things as floats, not doubles. We use this because |
333 | | // we only want to output about 6 digits of precision for our matrix() |
334 | | // functions, to preserve the behavior we used to have when we used |
335 | | // AppendPrintf. |
336 | | static void |
337 | | AppendFloat(nsAString& aStr, float f) |
338 | 0 | { |
339 | 0 | aStr.AppendFloat(f); |
340 | 0 | } |
341 | | |
342 | | void |
343 | | DOMMatrixReadOnly::Stringify(nsAString& aResult) |
344 | 0 | { |
345 | 0 | nsAutoString matrixStr; |
346 | 0 | if (mMatrix3D) { |
347 | 0 | // We can't use AppendPrintf here, because it does locale-specific |
348 | 0 | // formatting of floating-point values. |
349 | 0 | matrixStr.AssignLiteral("matrix3d("); |
350 | 0 | AppendFloat(matrixStr, M11()); matrixStr.AppendLiteral(", "); |
351 | 0 | AppendFloat(matrixStr, M12()); matrixStr.AppendLiteral(", "); |
352 | 0 | AppendFloat(matrixStr, M13()); matrixStr.AppendLiteral(", "); |
353 | 0 | AppendFloat(matrixStr, M14()); matrixStr.AppendLiteral(", "); |
354 | 0 | AppendFloat(matrixStr, M21()); matrixStr.AppendLiteral(", "); |
355 | 0 | AppendFloat(matrixStr, M22()); matrixStr.AppendLiteral(", "); |
356 | 0 | AppendFloat(matrixStr, M23()); matrixStr.AppendLiteral(", "); |
357 | 0 | AppendFloat(matrixStr, M24()); matrixStr.AppendLiteral(", "); |
358 | 0 | AppendFloat(matrixStr, M31()); matrixStr.AppendLiteral(", "); |
359 | 0 | AppendFloat(matrixStr, M32()); matrixStr.AppendLiteral(", "); |
360 | 0 | AppendFloat(matrixStr, M33()); matrixStr.AppendLiteral(", "); |
361 | 0 | AppendFloat(matrixStr, M34()); matrixStr.AppendLiteral(", "); |
362 | 0 | AppendFloat(matrixStr, M41()); matrixStr.AppendLiteral(", "); |
363 | 0 | AppendFloat(matrixStr, M42()); matrixStr.AppendLiteral(", "); |
364 | 0 | AppendFloat(matrixStr, M43()); matrixStr.AppendLiteral(", "); |
365 | 0 | AppendFloat(matrixStr, M44()); |
366 | 0 | matrixStr.AppendLiteral(")"); |
367 | 0 | } else { |
368 | 0 | // We can't use AppendPrintf here, because it does locale-specific |
369 | 0 | // formatting of floating-point values. |
370 | 0 | matrixStr.AssignLiteral("matrix("); |
371 | 0 | AppendFloat(matrixStr, A()); matrixStr.AppendLiteral(", "); |
372 | 0 | AppendFloat(matrixStr, B()); matrixStr.AppendLiteral(", "); |
373 | 0 | AppendFloat(matrixStr, C()); matrixStr.AppendLiteral(", "); |
374 | 0 | AppendFloat(matrixStr, D()); matrixStr.AppendLiteral(", "); |
375 | 0 | AppendFloat(matrixStr, E()); matrixStr.AppendLiteral(", "); |
376 | 0 | AppendFloat(matrixStr, F()); |
377 | 0 | matrixStr.AppendLiteral(")"); |
378 | 0 | } |
379 | 0 |
|
380 | 0 | aResult = matrixStr; |
381 | 0 | } |
382 | | |
383 | | already_AddRefed<DOMMatrix> |
384 | | DOMMatrix::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv) |
385 | 0 | { |
386 | 0 | RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports()); |
387 | 0 | return obj.forget(); |
388 | 0 | } |
389 | | |
390 | | already_AddRefed<DOMMatrix> |
391 | | DOMMatrix::Constructor(const GlobalObject& aGlobal, const nsAString& aTransformList, ErrorResult& aRv) |
392 | 0 | { |
393 | 0 | RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports()); |
394 | 0 | obj = obj->SetMatrixValue(aTransformList, aRv); |
395 | 0 | return obj.forget(); |
396 | 0 | } |
397 | | |
398 | | already_AddRefed<DOMMatrix> |
399 | | DOMMatrix::Constructor(const GlobalObject& aGlobal, const DOMMatrixReadOnly& aOther, ErrorResult& aRv) |
400 | 0 | { |
401 | 0 | RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports(), aOther); |
402 | 0 | return obj.forget(); |
403 | 0 | } |
404 | | |
405 | | template <typename T> |
406 | | static void |
407 | | SetDataInMatrix(DOMMatrixReadOnly* aMatrix, const T* aData, int aLength, ErrorResult& aRv) |
408 | 0 | { |
409 | 0 | if (aLength == 16) { |
410 | 0 | aMatrix->SetM11(aData[0]); |
411 | 0 | aMatrix->SetM12(aData[1]); |
412 | 0 | aMatrix->SetM13(aData[2]); |
413 | 0 | aMatrix->SetM14(aData[3]); |
414 | 0 | aMatrix->SetM21(aData[4]); |
415 | 0 | aMatrix->SetM22(aData[5]); |
416 | 0 | aMatrix->SetM23(aData[6]); |
417 | 0 | aMatrix->SetM24(aData[7]); |
418 | 0 | aMatrix->SetM31(aData[8]); |
419 | 0 | aMatrix->SetM32(aData[9]); |
420 | 0 | aMatrix->SetM33(aData[10]); |
421 | 0 | aMatrix->SetM34(aData[11]); |
422 | 0 | aMatrix->SetM41(aData[12]); |
423 | 0 | aMatrix->SetM42(aData[13]); |
424 | 0 | aMatrix->SetM43(aData[14]); |
425 | 0 | aMatrix->SetM44(aData[15]); |
426 | 0 | } else if (aLength == 6) { |
427 | 0 | aMatrix->SetA(aData[0]); |
428 | 0 | aMatrix->SetB(aData[1]); |
429 | 0 | aMatrix->SetC(aData[2]); |
430 | 0 | aMatrix->SetD(aData[3]); |
431 | 0 | aMatrix->SetE(aData[4]); |
432 | 0 | aMatrix->SetF(aData[5]); |
433 | 0 | } else { |
434 | 0 | nsAutoString lengthStr; |
435 | 0 | lengthStr.AppendInt(aLength); |
436 | 0 | aRv.ThrowTypeError<MSG_MATRIX_INIT_LENGTH_WRONG>(lengthStr); |
437 | 0 | } |
438 | 0 | } Unexecuted instantiation: Unified_cpp_dom_base1.cpp:void mozilla::dom::SetDataInMatrix<double>(mozilla::dom::DOMMatrixReadOnly*, double const*, int, mozilla::ErrorResult&) Unexecuted instantiation: Unified_cpp_dom_base1.cpp:void mozilla::dom::SetDataInMatrix<float>(mozilla::dom::DOMMatrixReadOnly*, float const*, int, mozilla::ErrorResult&) |
439 | | |
440 | | already_AddRefed<DOMMatrix> |
441 | | DOMMatrix::Constructor(const GlobalObject& aGlobal, const Float32Array& aArray32, ErrorResult& aRv) |
442 | 0 | { |
443 | 0 | RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports()); |
444 | 0 | aArray32.ComputeLengthAndData(); |
445 | 0 | SetDataInMatrix(obj, aArray32.Data(), aArray32.Length(), aRv); |
446 | 0 |
|
447 | 0 | return obj.forget(); |
448 | 0 | } |
449 | | |
450 | | already_AddRefed<DOMMatrix> |
451 | | DOMMatrix::Constructor(const GlobalObject& aGlobal, const Float64Array& aArray64, ErrorResult& aRv) |
452 | 0 | { |
453 | 0 | RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports()); |
454 | 0 | aArray64.ComputeLengthAndData(); |
455 | 0 | SetDataInMatrix(obj, aArray64.Data(), aArray64.Length(), aRv); |
456 | 0 |
|
457 | 0 | return obj.forget(); |
458 | 0 | } |
459 | | |
460 | | already_AddRefed<DOMMatrix> |
461 | | DOMMatrix::Constructor(const GlobalObject& aGlobal, const Sequence<double>& aNumberSequence, ErrorResult& aRv) |
462 | 0 | { |
463 | 0 | RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports()); |
464 | 0 | SetDataInMatrix(obj, aNumberSequence.Elements(), aNumberSequence.Length(), aRv); |
465 | 0 |
|
466 | 0 | return obj.forget(); |
467 | 0 | } |
468 | | |
469 | | void |
470 | | DOMMatrixReadOnly::Ensure3DMatrix() |
471 | 0 | { |
472 | 0 | if (!mMatrix3D) { |
473 | 0 | mMatrix3D = new gfx::Matrix4x4(gfx::Matrix4x4::From2D(*mMatrix2D)); |
474 | 0 | mMatrix2D = nullptr; |
475 | 0 | } |
476 | 0 | } |
477 | | |
478 | | DOMMatrix* |
479 | | DOMMatrix::MultiplySelf(const DOMMatrix& aOther) |
480 | 0 | { |
481 | 0 | if (aOther.IsIdentity()) { |
482 | 0 | return this; |
483 | 0 | } |
484 | 0 | |
485 | 0 | if (aOther.Is2D()) { |
486 | 0 | if (mMatrix3D) { |
487 | 0 | *mMatrix3D = gfx::Matrix4x4::From2D(*aOther.mMatrix2D) * *mMatrix3D; |
488 | 0 | } else { |
489 | 0 | *mMatrix2D = *aOther.mMatrix2D * *mMatrix2D; |
490 | 0 | } |
491 | 0 | } else { |
492 | 0 | Ensure3DMatrix(); |
493 | 0 | *mMatrix3D = *aOther.mMatrix3D * *mMatrix3D; |
494 | 0 | } |
495 | 0 |
|
496 | 0 | return this; |
497 | 0 | } |
498 | | |
499 | | DOMMatrix* |
500 | | DOMMatrix::PreMultiplySelf(const DOMMatrix& aOther) |
501 | 0 | { |
502 | 0 | if (aOther.IsIdentity()) { |
503 | 0 | return this; |
504 | 0 | } |
505 | 0 | |
506 | 0 | if (aOther.Is2D()) { |
507 | 0 | if (mMatrix3D) { |
508 | 0 | *mMatrix3D = *mMatrix3D * gfx::Matrix4x4::From2D(*aOther.mMatrix2D); |
509 | 0 | } else { |
510 | 0 | *mMatrix2D = *mMatrix2D * *aOther.mMatrix2D; |
511 | 0 | } |
512 | 0 | } else { |
513 | 0 | Ensure3DMatrix(); |
514 | 0 | *mMatrix3D = *mMatrix3D * *aOther.mMatrix3D; |
515 | 0 | } |
516 | 0 |
|
517 | 0 | return this; |
518 | 0 | } |
519 | | |
520 | | DOMMatrix* |
521 | | DOMMatrix::TranslateSelf(double aTx, |
522 | | double aTy, |
523 | | double aTz) |
524 | 0 | { |
525 | 0 | if (aTx == 0 && aTy == 0 && aTz == 0) { |
526 | 0 | return this; |
527 | 0 | } |
528 | 0 | |
529 | 0 | if (mMatrix3D || aTz != 0) { |
530 | 0 | Ensure3DMatrix(); |
531 | 0 | mMatrix3D->PreTranslate(aTx, aTy, aTz); |
532 | 0 | } else { |
533 | 0 | mMatrix2D->PreTranslate(aTx, aTy); |
534 | 0 | } |
535 | 0 |
|
536 | 0 | return this; |
537 | 0 | } |
538 | | |
539 | | DOMMatrix* |
540 | | DOMMatrix::ScaleSelf(double aScale, double aOriginX, double aOriginY) |
541 | 0 | { |
542 | 0 | ScaleNonUniformSelf(aScale, aScale, 1.0, aOriginX, aOriginY, 0); |
543 | 0 |
|
544 | 0 | return this; |
545 | 0 | } |
546 | | |
547 | | DOMMatrix* |
548 | | DOMMatrix::Scale3dSelf(double aScale, double aOriginX, |
549 | | double aOriginY, double aOriginZ) |
550 | 0 | { |
551 | 0 | ScaleNonUniformSelf(aScale, aScale, aScale, aOriginX, aOriginY, aOriginZ); |
552 | 0 |
|
553 | 0 | return this; |
554 | 0 | } |
555 | | |
556 | | DOMMatrix* |
557 | | DOMMatrix::ScaleNonUniformSelf(double aScaleX, |
558 | | double aScaleY, |
559 | | double aScaleZ, |
560 | | double aOriginX, |
561 | | double aOriginY, |
562 | | double aOriginZ) |
563 | 0 | { |
564 | 0 | if (aScaleX == 1.0 && aScaleY == 1.0 && aScaleZ == 1.0) { |
565 | 0 | return this; |
566 | 0 | } |
567 | 0 | |
568 | 0 | TranslateSelf(aOriginX, aOriginY, aOriginZ); |
569 | 0 |
|
570 | 0 | if (mMatrix3D || aScaleZ != 1.0 || aOriginZ != 0) { |
571 | 0 | Ensure3DMatrix(); |
572 | 0 | gfx::Matrix4x4 m; |
573 | 0 | m._11 = aScaleX; |
574 | 0 | m._22 = aScaleY; |
575 | 0 | m._33 = aScaleZ; |
576 | 0 | *mMatrix3D = m * *mMatrix3D; |
577 | 0 | } else { |
578 | 0 | gfx::Matrix m; |
579 | 0 | m._11 = aScaleX; |
580 | 0 | m._22 = aScaleY; |
581 | 0 | *mMatrix2D = m * *mMatrix2D; |
582 | 0 | } |
583 | 0 |
|
584 | 0 | TranslateSelf(-aOriginX, -aOriginY, -aOriginZ); |
585 | 0 |
|
586 | 0 | return this; |
587 | 0 | } |
588 | | |
589 | | DOMMatrix* |
590 | | DOMMatrix::RotateFromVectorSelf(double aX, double aY) |
591 | 0 | { |
592 | 0 | if (aX == 0.0 || aY == 0.0) { |
593 | 0 | return this; |
594 | 0 | } |
595 | 0 | |
596 | 0 | RotateSelf(atan2(aY, aX) / radPerDegree); |
597 | 0 |
|
598 | 0 | return this; |
599 | 0 | } |
600 | | |
601 | | DOMMatrix* |
602 | | DOMMatrix::RotateSelf(double aAngle, double aOriginX, double aOriginY) |
603 | 0 | { |
604 | 0 | if (fmod(aAngle, 360) == 0) { |
605 | 0 | return this; |
606 | 0 | } |
607 | 0 | |
608 | 0 | TranslateSelf(aOriginX, aOriginY); |
609 | 0 |
|
610 | 0 | if (mMatrix3D) { |
611 | 0 | RotateAxisAngleSelf(0, 0, 1, aAngle); |
612 | 0 | } else { |
613 | 0 | *mMatrix2D = mMatrix2D->PreRotate(aAngle * radPerDegree); |
614 | 0 | } |
615 | 0 |
|
616 | 0 | TranslateSelf(-aOriginX, -aOriginY); |
617 | 0 |
|
618 | 0 | return this; |
619 | 0 | } |
620 | | |
621 | | DOMMatrix* |
622 | | DOMMatrix::RotateAxisAngleSelf(double aX, double aY, |
623 | | double aZ, double aAngle) |
624 | 0 | { |
625 | 0 | if (fmod(aAngle, 360) == 0) { |
626 | 0 | return this; |
627 | 0 | } |
628 | 0 | |
629 | 0 | aAngle *= radPerDegree; |
630 | 0 |
|
631 | 0 | Ensure3DMatrix(); |
632 | 0 | gfx::Matrix4x4 m; |
633 | 0 | m.SetRotateAxisAngle(aX, aY, aZ, aAngle); |
634 | 0 |
|
635 | 0 | *mMatrix3D = m * *mMatrix3D; |
636 | 0 |
|
637 | 0 | return this; |
638 | 0 | } |
639 | | |
640 | | DOMMatrix* |
641 | | DOMMatrix::SkewXSelf(double aSx) |
642 | 0 | { |
643 | 0 | if (fmod(aSx, 360) == 0) { |
644 | 0 | return this; |
645 | 0 | } |
646 | 0 | |
647 | 0 | if (mMatrix3D) { |
648 | 0 | gfx::Matrix4x4 m; |
649 | 0 | m._21 = tan(aSx * radPerDegree); |
650 | 0 | *mMatrix3D = m * *mMatrix3D; |
651 | 0 | } else { |
652 | 0 | gfx::Matrix m; |
653 | 0 | m._21 = tan(aSx * radPerDegree); |
654 | 0 | *mMatrix2D = m * *mMatrix2D; |
655 | 0 | } |
656 | 0 |
|
657 | 0 | return this; |
658 | 0 | } |
659 | | |
660 | | DOMMatrix* |
661 | | DOMMatrix::SkewYSelf(double aSy) |
662 | 0 | { |
663 | 0 | if (fmod(aSy, 360) == 0) { |
664 | 0 | return this; |
665 | 0 | } |
666 | 0 | |
667 | 0 | if (mMatrix3D) { |
668 | 0 | gfx::Matrix4x4 m; |
669 | 0 | m._12 = tan(aSy * radPerDegree); |
670 | 0 | *mMatrix3D = m * *mMatrix3D; |
671 | 0 | } else { |
672 | 0 | gfx::Matrix m; |
673 | 0 | m._12 = tan(aSy * radPerDegree); |
674 | 0 | *mMatrix2D = m * *mMatrix2D; |
675 | 0 | } |
676 | 0 |
|
677 | 0 | return this; |
678 | 0 | } |
679 | | |
680 | | DOMMatrix* |
681 | | DOMMatrix::InvertSelf() |
682 | 0 | { |
683 | 0 | if (mMatrix3D) { |
684 | 0 | if (!mMatrix3D->Invert()) { |
685 | 0 | mMatrix3D->SetNAN(); |
686 | 0 | } |
687 | 0 | } else if (!mMatrix2D->Invert()) { |
688 | 0 | mMatrix2D = nullptr; |
689 | 0 |
|
690 | 0 | mMatrix3D = new gfx::Matrix4x4(); |
691 | 0 | mMatrix3D->SetNAN(); |
692 | 0 | } |
693 | 0 |
|
694 | 0 | return this; |
695 | 0 | } |
696 | | |
697 | | DOMMatrixReadOnly* |
698 | | DOMMatrixReadOnly::SetMatrixValue(const nsAString& aTransformList, ErrorResult& aRv) |
699 | 0 | { |
700 | 0 | // An empty string is a no-op. |
701 | 0 | if (aTransformList.IsEmpty()) { |
702 | 0 | return this; |
703 | 0 | } |
704 | 0 | |
705 | 0 | gfx::Matrix4x4 transform; |
706 | 0 | bool contains3dTransform = false; |
707 | 0 | if (!ServoCSSParser::ParseTransformIntoMatrix(aTransformList, |
708 | 0 | contains3dTransform, |
709 | 0 | transform.components)) { |
710 | 0 | aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); |
711 | 0 | return nullptr; |
712 | 0 | } |
713 | 0 | |
714 | 0 | if (!contains3dTransform) { |
715 | 0 | mMatrix3D = nullptr; |
716 | 0 | mMatrix2D = new gfx::Matrix(); |
717 | 0 |
|
718 | 0 | SetA(transform._11); |
719 | 0 | SetB(transform._12); |
720 | 0 | SetC(transform._21); |
721 | 0 | SetD(transform._22); |
722 | 0 | SetE(transform._41); |
723 | 0 | SetF(transform._42); |
724 | 0 | } else { |
725 | 0 | mMatrix3D = new gfx::Matrix4x4(transform); |
726 | 0 | mMatrix2D = nullptr; |
727 | 0 | } |
728 | 0 |
|
729 | 0 | return this; |
730 | 0 | } |
731 | | |
732 | | DOMMatrix* |
733 | | DOMMatrix::SetMatrixValue(const nsAString& aTransformList, ErrorResult& aRv) |
734 | 0 | { |
735 | 0 | DOMMatrixReadOnly::SetMatrixValue(aTransformList, aRv); |
736 | 0 | return this; |
737 | 0 | } |
738 | | |
739 | | JSObject* |
740 | | DOMMatrix::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) |
741 | 0 | { |
742 | 0 | return DOMMatrix_Binding::Wrap(aCx, this, aGivenProto); |
743 | 0 | } |
744 | | |
745 | | } // namespace dom |
746 | | } // namespace mozilla |