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 /**
8  * Notes on transforms in Mozilla and the SVG code.
9  *
10  * It's important to note that the matrix convention used in the SVG standard
11  * is the opposite convention to the one used in the Mozilla code or, more
12  * specifically, the convention used in Thebes code (code using gfxMatrix).
13  * Whereas the SVG standard uses the column vector convention, Thebes code uses
14  * the row vector convention. Thus, whereas in the SVG standard you have
15  * [M1][M2][M3]|p|, in Thebes you have |p|'[M3]'[M2]'[M1]'. In other words, the
16  * following are equivalent:
17  *
18  *                       / a1 c1 tx1 \   / a2 c2 tx2 \   / a3 c3 tx3 \   / x \
19  * SVG:                  | b1 d1 ty1 |   | b2 d2 ty2 |   | b3 d3 ty3 |   | y |
20  *                       \  0  0   1 /   \  0  0   1 /   \  0  0   1 /   \ 1 /
21  *
22  *                       /  a3  b3 0 \   /  a2  b2 0 \   /  a1  b1 0 \
23  * Thebes:   [ x y 1 ]   |  c3  d3 0 |   |  c2  d2 0 |   |  c1  d1 0 |
24  *                       \ tx3 ty3 1 /   \ tx2 ty2 1 /   \ tx1 ty1 1 /
25  *
26  * Because the Thebes representation of a transform is the transpose of the SVG
27  * representation, our transform order must be reversed when representing SVG
28  * transforms using gfxMatrix in the SVG code. Since the SVG implementation
29  * stores and obtains matrices in SVG order, to do this we must pre-multiply
30  * gfxMatrix objects that represent SVG transforms instead of post-multiplying
31  * them as we would for matrices using SVG's column vector convention.
32  * Pre-multiplying may look wrong if you're only familiar with the SVG
33  * convention, but in that case hopefully the above explanation clears things
34  * up.
35  */
36 
37 #ifndef DOM_SVG_SVGMATRIX_H_
38 #define DOM_SVG_SVGMATRIX_H_
39 
40 #include "DOMSVGTransform.h"
41 #include "gfxMatrix.h"
42 #include "nsCycleCollectionParticipant.h"
43 #include "nsWrapperCache.h"
44 #include "mozilla/Attributes.h"
45 
46 namespace mozilla {
47 namespace dom {
48 
49 /**
50  * DOM wrapper for an SVG matrix.
51  */
52 class SVGMatrix final : public nsWrapperCache {
53  public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(SVGMatrix)54   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(SVGMatrix)
55   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(SVGMatrix)
56 
57   /**
58    * Ctor for SVGMatrix objects that belong to a DOMSVGTransform.
59    */
60   explicit SVGMatrix(DOMSVGTransform& aTransform) : mTransform(&aTransform) {}
61 
62   /**
63    * Ctors for SVGMatrix objects created independently of a DOMSVGTransform.
64    */
65   // Default ctor for gfxMatrix will produce identity mx
66   SVGMatrix() = default;
67 
SVGMatrix(const gfxMatrix & aMatrix)68   explicit SVGMatrix(const gfxMatrix& aMatrix) : mMatrix(aMatrix) {}
69 
70   // WebIDL
71   DOMSVGTransform* GetParentObject() const;
72   virtual JSObject* WrapObject(JSContext* aCx,
73                                JS::Handle<JSObject*> aGivenProto) override;
74 
A()75   float A() const { return static_cast<float>(GetMatrix()._11); }
76   void SetA(float aA, ErrorResult& rv);
B()77   float B() const { return static_cast<float>(GetMatrix()._12); }
78   void SetB(float aB, ErrorResult& rv);
C()79   float C() const { return static_cast<float>(GetMatrix()._21); }
80   void SetC(float aC, ErrorResult& rv);
D()81   float D() const { return static_cast<float>(GetMatrix()._22); }
82   void SetD(float aD, ErrorResult& rv);
E()83   float E() const { return static_cast<float>(GetMatrix()._31); }
84   void SetE(float aE, ErrorResult& rv);
F()85   float F() const { return static_cast<float>(GetMatrix()._32); }
86   void SetF(float aF, ErrorResult& rv);
87   already_AddRefed<SVGMatrix> Multiply(SVGMatrix& aMatrix);
88   already_AddRefed<SVGMatrix> Inverse(ErrorResult& aRv);
89   already_AddRefed<SVGMatrix> Translate(float x, float y);
90   already_AddRefed<SVGMatrix> Scale(float scaleFactor);
91   already_AddRefed<SVGMatrix> ScaleNonUniform(float scaleFactorX,
92                                               float scaleFactorY);
93   already_AddRefed<SVGMatrix> Rotate(float angle);
94   already_AddRefed<SVGMatrix> RotateFromVector(float x, float y,
95                                                ErrorResult& aRv);
96   already_AddRefed<SVGMatrix> FlipX();
97   already_AddRefed<SVGMatrix> FlipY();
98   already_AddRefed<SVGMatrix> SkewX(float angle, ErrorResult& rv);
99   already_AddRefed<SVGMatrix> SkewY(float angle, ErrorResult& rv);
100 
101  private:
102   ~SVGMatrix() = default;
103 
GetMatrix()104   const gfxMatrix& GetMatrix() const {
105     return mTransform ? mTransform->Matrixgfx() : mMatrix;
106   }
107 
SetMatrix(const gfxMatrix & aMatrix)108   void SetMatrix(const gfxMatrix& aMatrix) {
109     if (mTransform) {
110       mTransform->SetMatrix(aMatrix);
111     } else {
112       mMatrix = aMatrix;
113     }
114   }
115 
IsAnimVal()116   bool IsAnimVal() const {
117     return mTransform ? mTransform->IsAnimVal() : false;
118   }
119 
120   RefPtr<DOMSVGTransform> mTransform;
121 
122   // Typically we operate on the matrix data accessed via mTransform but for
123   // matrices that exist independently of an DOMSVGTransform we use mMatrix
124   // below.
125   gfxMatrix mMatrix;
126 };
127 
128 }  // namespace dom
129 }  // namespace mozilla
130 
131 #endif  // DOM_SVG_SVGMATRIX_H_
132