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 #ifndef MOZILLA_DOM_DOMMATRIX_H_
8 #define MOZILLA_DOM_DOMMATRIX_H_
9 
10 #include <cstring>
11 #include <utility>
12 #include "js/RootingAPI.h"
13 #include "mozilla/AlreadyAddRefed.h"
14 #include "mozilla/Assertions.h"
15 #include "mozilla/UniquePtr.h"
16 #include "mozilla/dom/TypedArray.h"
17 #include "mozilla/gfx/Matrix.h"
18 #include "nsCOMPtr.h"
19 #include "nsCycleCollectionParticipant.h"
20 #include "nsISupports.h"
21 #include "nsStringFwd.h"
22 #include "nsWrapperCache.h"
23 
24 class JSObject;
25 class nsIGlobalObject;
26 struct JSContext;
27 struct JSStructuredCloneReader;
28 struct JSStructuredCloneWriter;
29 
30 namespace mozilla {
31 class ErrorResult;
32 
33 namespace dom {
34 
35 class GlobalObject;
36 class DOMMatrix;
37 class DOMPoint;
38 template <typename T>
39 class Optional;
40 class UTF8StringOrUnrestrictedDoubleSequenceOrDOMMatrixReadOnly;
41 struct DOMPointInit;
42 struct DOMMatrixInit;
43 struct DOMMatrix2DInit;
44 
45 class DOMMatrixReadOnly : public nsWrapperCache {
46  public:
DOMMatrixReadOnly(nsISupports * aParent)47   explicit DOMMatrixReadOnly(nsISupports* aParent)
48       : mParent(aParent), mMatrix2D(new gfx::MatrixDouble()) {}
49 
DOMMatrixReadOnly(nsISupports * aParent,const DOMMatrixReadOnly & other)50   DOMMatrixReadOnly(nsISupports* aParent, const DOMMatrixReadOnly& other)
51       : mParent(aParent) {
52     if (other.mMatrix2D) {
53       mMatrix2D = MakeUnique<gfx::MatrixDouble>(*other.mMatrix2D);
54     } else {
55       mMatrix3D = MakeUnique<gfx::Matrix4x4Double>(*other.mMatrix3D);
56     }
57   }
58 
DOMMatrixReadOnly(nsISupports * aParent,const gfx::Matrix4x4 & aMatrix)59   DOMMatrixReadOnly(nsISupports* aParent, const gfx::Matrix4x4& aMatrix)
60       : mParent(aParent) {
61     mMatrix3D = MakeUnique<gfx::Matrix4x4Double>(aMatrix);
62   }
63 
DOMMatrixReadOnly(nsISupports * aParent,const gfx::Matrix & aMatrix)64   DOMMatrixReadOnly(nsISupports* aParent, const gfx::Matrix& aMatrix)
65       : mParent(aParent) {
66     mMatrix2D = MakeUnique<gfx::MatrixDouble>(aMatrix);
67   }
68 
69   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMMatrixReadOnly)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMMatrixReadOnly)70   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMMatrixReadOnly)
71 
72   nsISupports* GetParentObject() const { return mParent; }
73   virtual JSObject* WrapObject(JSContext* cx,
74                                JS::Handle<JSObject*> aGivenProto) override;
75 
76   static already_AddRefed<DOMMatrixReadOnly> FromMatrix(
77       nsISupports* aParent, const DOMMatrix2DInit& aMatrixInit,
78       ErrorResult& aRv);
79 
80   static already_AddRefed<DOMMatrixReadOnly> FromMatrix(
81       nsISupports* aParent, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv);
82 
83   static already_AddRefed<DOMMatrixReadOnly> FromMatrix(
84       const GlobalObject& aGlobal, const DOMMatrixInit& aMatrixInit,
85       ErrorResult& aRv);
86 
87   static already_AddRefed<DOMMatrixReadOnly> FromFloat32Array(
88       const GlobalObject& aGlobal, const Float32Array& aArray32,
89       ErrorResult& aRv);
90 
91   static already_AddRefed<DOMMatrixReadOnly> FromFloat64Array(
92       const GlobalObject& aGlobal, const Float64Array& aArray64,
93       ErrorResult& aRv);
94 
95   static already_AddRefed<DOMMatrixReadOnly> Constructor(
96       const GlobalObject& aGlobal,
97       const Optional<UTF8StringOrUnrestrictedDoubleSequenceOrDOMMatrixReadOnly>&
98           aArg,
99       ErrorResult& aRv);
100 
101   static already_AddRefed<DOMMatrixReadOnly> ReadStructuredClone(
102       JSContext* aCx, nsIGlobalObject* aGlobal,
103       JSStructuredCloneReader* aReader);
104 
105   // clang-format off
106 #define GetMatrixMember(entry2D, entry3D, default) \
107   {                                                \
108     if (mMatrix3D) {                               \
109       return mMatrix3D->entry3D;                   \
110     }                                              \
111     return mMatrix2D->entry2D;                     \
112   }
113 
114 #define Get3DMatrixMember(entry3D, default) \
115   {                                         \
116     if (mMatrix3D) {                        \
117       return mMatrix3D->entry3D;            \
118     }                                       \
119     return default;                         \
120   }
121 
122   double A() const GetMatrixMember(_11, _11, 1.0)
123   double B() const GetMatrixMember(_12, _12, 0)
124   double C() const GetMatrixMember(_21, _21, 0)
125   double D() const GetMatrixMember(_22, _22, 1.0)
126   double E() const GetMatrixMember(_31, _41, 0)
127   double F() const GetMatrixMember(_32, _42, 0)
128 
129   double M11() const GetMatrixMember(_11, _11, 1.0)
130   double M12() const GetMatrixMember(_12, _12, 0)
131   double M13() const Get3DMatrixMember(_13, 0)
132   double M14() const Get3DMatrixMember(_14, 0)
133   double M21() const GetMatrixMember(_21, _21, 0)
134   double M22() const GetMatrixMember(_22, _22, 1.0)
135   double M23() const Get3DMatrixMember(_23, 0)
136   double M24() const Get3DMatrixMember(_24, 0)
137   double M31() const Get3DMatrixMember(_31, 0)
138   double M32() const Get3DMatrixMember(_32, 0)
139   double M33() const Get3DMatrixMember(_33, 1.0)
140   double M34() const Get3DMatrixMember(_34, 0)
141   double M41() const GetMatrixMember(_31, _41, 0)
142   double M42() const GetMatrixMember(_32, _42, 0)
143   double M43() const Get3DMatrixMember(_43, 0)
144   double M44() const Get3DMatrixMember(_44, 1.0)
145 
146 #undef GetMatrixMember
147 #undef Get3DMatrixMember
148 
149   // Defined here so we can construct DOMMatrixReadOnly objects.
150 #define Set2DMatrixMember(entry2D, entry3D) \
151   {                                         \
152     if (mMatrix3D) {                        \
153       mMatrix3D->entry3D = v;               \
154     } else {                                \
155       mMatrix2D->entry2D = v;               \
156     }                                       \
157   }
158 
159 #define Set3DMatrixMember(entry3D, default) \
160   {                                         \
161     if (mMatrix3D || (v != default)) {      \
162       Ensure3DMatrix();                     \
163       mMatrix3D->entry3D = v;               \
164     }                                       \
165   }
166 
167   void SetA(double v) Set2DMatrixMember(_11, _11)
168   void SetB(double v) Set2DMatrixMember(_12, _12)
169   void SetC(double v) Set2DMatrixMember(_21, _21)
170   void SetD(double v) Set2DMatrixMember(_22, _22)
171   void SetE(double v) Set2DMatrixMember(_31, _41)
172   void SetF(double v) Set2DMatrixMember(_32, _42)
173 
174   void SetM11(double v) Set2DMatrixMember(_11, _11)
175   void SetM12(double v) Set2DMatrixMember(_12, _12)
176   void SetM13(double v) Set3DMatrixMember(_13, 0)
177   void SetM14(double v) Set3DMatrixMember(_14, 0)
178   void SetM21(double v) Set2DMatrixMember(_21, _21)
179   void SetM22(double v) Set2DMatrixMember(_22, _22)
180   void SetM23(double v) Set3DMatrixMember(_23, 0)
181   void SetM24(double v) Set3DMatrixMember(_24, 0)
182   void SetM31(double v) Set3DMatrixMember(_31, 0)
183   void SetM32(double v) Set3DMatrixMember(_32, 0)
184   void SetM33(double v) Set3DMatrixMember(_33, 1.0)
185   void SetM34(double v) Set3DMatrixMember(_34, 0)
186   void SetM41(double v) Set2DMatrixMember(_31, _41)
187   void SetM42(double v) Set2DMatrixMember(_32, _42)
188   void SetM43(double v) Set3DMatrixMember(_43, 0)
189   void SetM44(double v) Set3DMatrixMember(_44, 1.0)
190   ; // semi-colon here to get clang-format to align properly from here on
191 
192 #undef Set2DMatrixMember
193 #undef Set3DMatrixMember
194   // clang-format on
195 
196   already_AddRefed<DOMMatrix> Translate(double aTx, double aTy,
197                                         double aTz = 0) const;
198   already_AddRefed<DOMMatrix> Scale(double aScaleX,
199                                     const Optional<double>& aScaleY,
200                                     double aScaleZ, double aOriginX,
201                                     double aOriginY, double aOriginZ) const;
202   already_AddRefed<DOMMatrix> Scale3d(double aScale, double aOriginX = 0,
203                                       double aOriginY = 0,
204                                       double aOriginZ = 0) const;
205   already_AddRefed<DOMMatrix> ScaleNonUniform(double aScaleX,
206                                               double aScaleY) const;
207   already_AddRefed<DOMMatrix> Rotate(double aRotX,
208                                      const Optional<double>& aRotY,
209                                      const Optional<double>& aRotZ) const;
210   already_AddRefed<DOMMatrix> RotateFromVector(double aX, double aY) const;
211   already_AddRefed<DOMMatrix> RotateAxisAngle(double aX, double aY, double aZ,
212                                               double aAngle) const;
213   already_AddRefed<DOMMatrix> SkewX(double aSx) const;
214   already_AddRefed<DOMMatrix> SkewY(double aSy) const;
215   already_AddRefed<DOMMatrix> Multiply(const DOMMatrixInit& aOther,
216                                        ErrorResult& aRv) const;
217   already_AddRefed<DOMMatrix> FlipX() const;
218   already_AddRefed<DOMMatrix> FlipY() const;
219   already_AddRefed<DOMMatrix> Inverse() const;
220 
221   bool Is2D() const;
222   bool IsIdentity() const;
223   already_AddRefed<DOMPoint> TransformPoint(const DOMPointInit& aPoint) const;
224   void ToFloat32Array(JSContext* aCx, JS::MutableHandle<JSObject*> aResult,
225                       ErrorResult& aRv) const;
226   void ToFloat64Array(JSContext* aCx, JS::MutableHandle<JSObject*> aResult,
227                       ErrorResult& aRv) const;
228   void Stringify(nsAString& aResult, ErrorResult& aRv);
229 
230   bool WriteStructuredClone(JSContext* aCx,
231                             JSStructuredCloneWriter* aWriter) const;
GetInternal2D()232   const gfx::MatrixDouble* GetInternal2D() const {
233     if (Is2D()) {
234       return mMatrix2D.get();
235     }
236     return nullptr;
237   }
238 
239  protected:
240   nsCOMPtr<nsISupports> mParent;
241   UniquePtr<gfx::MatrixDouble> mMatrix2D;
242   UniquePtr<gfx::Matrix4x4Double> mMatrix3D;
243 
244   virtual ~DOMMatrixReadOnly() = default;
245 
246   /**
247    * Sets data from a fully validated and fixed-up matrix init,
248    * where all of its members are properly defined.
249    * The init dictionary's dimension must match the matrix one.
250    */
251   void SetDataFromMatrix2DInit(const DOMMatrix2DInit& aMatrixInit);
252   void SetDataFromMatrixInit(const DOMMatrixInit& aMatrixInit);
253 
254   DOMMatrixReadOnly* SetMatrixValue(const nsACString&, ErrorResult&);
255   void Ensure3DMatrix();
256 
DOMMatrixReadOnly(nsISupports * aParent,bool is2D)257   DOMMatrixReadOnly(nsISupports* aParent, bool is2D) : mParent(aParent) {
258     if (is2D) {
259       mMatrix2D = MakeUnique<gfx::MatrixDouble>();
260     } else {
261       mMatrix3D = MakeUnique<gfx::Matrix4x4Double>();
262     }
263   }
264 
265   static bool ReadStructuredCloneElements(JSStructuredCloneReader* aReader,
266                                           DOMMatrixReadOnly* matrix);
267 
268  private:
269   DOMMatrixReadOnly() = delete;
270   DOMMatrixReadOnly(const DOMMatrixReadOnly&) = delete;
271   DOMMatrixReadOnly& operator=(const DOMMatrixReadOnly&) = delete;
272 };
273 
274 class DOMMatrix : public DOMMatrixReadOnly {
275  public:
DOMMatrix(nsISupports * aParent)276   explicit DOMMatrix(nsISupports* aParent) : DOMMatrixReadOnly(aParent) {}
277 
DOMMatrix(nsISupports * aParent,const DOMMatrixReadOnly & other)278   DOMMatrix(nsISupports* aParent, const DOMMatrixReadOnly& other)
279       : DOMMatrixReadOnly(aParent, other) {}
280 
DOMMatrix(nsISupports * aParent,const gfx::Matrix4x4 & aMatrix)281   DOMMatrix(nsISupports* aParent, const gfx::Matrix4x4& aMatrix)
282       : DOMMatrixReadOnly(aParent, aMatrix) {}
283 
DOMMatrix(nsISupports * aParent,const gfx::Matrix & aMatrix)284   DOMMatrix(nsISupports* aParent, const gfx::Matrix& aMatrix)
285       : DOMMatrixReadOnly(aParent, aMatrix) {}
286 
287   static already_AddRefed<DOMMatrix> FromMatrix(
288       nsISupports* aParent, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv);
289 
290   static already_AddRefed<DOMMatrix> FromMatrix(
291       const GlobalObject& aGlobal, const DOMMatrixInit& aMatrixInit,
292       ErrorResult& aRv);
293 
294   static already_AddRefed<DOMMatrix> FromFloat32Array(
295       const GlobalObject& aGlobal, const Float32Array& aArray32,
296       ErrorResult& aRv);
297 
298   static already_AddRefed<DOMMatrix> FromFloat64Array(
299       const GlobalObject& aGlobal, const Float64Array& aArray64,
300       ErrorResult& aRv);
301 
302   static already_AddRefed<DOMMatrix> Constructor(
303       const GlobalObject& aGlobal,
304       const Optional<UTF8StringOrUnrestrictedDoubleSequenceOrDOMMatrixReadOnly>&
305           aArg,
306       ErrorResult& aRv);
307 
308   static already_AddRefed<DOMMatrix> ReadStructuredClone(
309       JSContext* aCx, nsIGlobalObject* aGlobal,
310       JSStructuredCloneReader* aReader);
311 
312   virtual JSObject* WrapObject(JSContext* aCx,
313                                JS::Handle<JSObject*> aGivenProto) override;
314 
315   DOMMatrix* MultiplySelf(const DOMMatrixInit& aOther, ErrorResult& aRv);
316   DOMMatrix* PreMultiplySelf(const DOMMatrixInit& aOther, ErrorResult& aRv);
317   DOMMatrix* TranslateSelf(double aTx, double aTy, double aTz = 0);
318   DOMMatrix* ScaleSelf(double aScaleX, const Optional<double>& aScaleY,
319                        double aScaleZ, double aOriginX, double aOriginY,
320                        double aOriginZ);
321   DOMMatrix* Scale3dSelf(double aScale, double aOriginX = 0,
322                          double aOriginY = 0, double aOriginZ = 0);
323   DOMMatrix* RotateSelf(double aRotX, const Optional<double>& aRotY,
324                         const Optional<double>& aRotZ);
325   DOMMatrix* RotateFromVectorSelf(double aX, double aY);
326   DOMMatrix* RotateAxisAngleSelf(double aX, double aY, double aZ,
327                                  double aAngle);
328   DOMMatrix* SkewXSelf(double aSx);
329   DOMMatrix* SkewYSelf(double aSy);
330   DOMMatrix* InvertSelf();
331   DOMMatrix* SetMatrixValue(const nsACString&, ErrorResult&);
332 
333   virtual ~DOMMatrix() = default;
334 
335  private:
DOMMatrix(nsISupports * aParent,bool is2D)336   DOMMatrix(nsISupports* aParent, bool is2D)
337       : DOMMatrixReadOnly(aParent, is2D) {}
338 };
339 
340 }  // namespace dom
341 }  // namespace mozilla
342 
343 #endif /*MOZILLA_DOM_DOMMATRIX_H_*/
344