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