Coverage Report

Created: 2018-09-25 14:53

/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