SVGMatrix.cpp (5275B)
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/SVGMatrix.h" 8 9 #include <math.h> 10 11 #include "mozilla/dom/DOMMatrix.h" 12 #include "mozilla/dom/SVGMatrixBinding.h" 13 #include "nsError.h" 14 15 const double radPerDegree = 2.0 * M_PI / 360.0; 16 17 namespace mozilla::dom { 18 19 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SVGMatrix, mTransform) 20 21 DOMSVGTransform* SVGMatrix::GetParentObject() const { return mTransform; } 22 23 JSObject* SVGMatrix::WrapObject(JSContext* aCx, 24 JS::Handle<JSObject*> aGivenProto) { 25 return SVGMatrix_Binding::Wrap(aCx, this, aGivenProto); 26 } 27 28 void SVGMatrix::SetA(float aA, ErrorResult& aRv) { 29 if (IsAnimVal()) { 30 aRv.ThrowNoModificationAllowedError("Animated values cannot be set"); 31 return; 32 } 33 34 gfxMatrix mx = GetMatrix(); 35 mx._11 = aA; 36 SetMatrix(mx); 37 } 38 39 void SVGMatrix::SetB(float aB, ErrorResult& aRv) { 40 if (IsAnimVal()) { 41 aRv.ThrowNoModificationAllowedError("Animated values cannot be set"); 42 return; 43 } 44 45 gfxMatrix mx = GetMatrix(); 46 mx._12 = aB; 47 SetMatrix(mx); 48 } 49 50 void SVGMatrix::SetC(float aC, ErrorResult& aRv) { 51 if (IsAnimVal()) { 52 aRv.ThrowNoModificationAllowedError("Animated values cannot be set"); 53 return; 54 } 55 56 gfxMatrix mx = GetMatrix(); 57 mx._21 = aC; 58 SetMatrix(mx); 59 } 60 61 void SVGMatrix::SetD(float aD, ErrorResult& aRv) { 62 if (IsAnimVal()) { 63 aRv.ThrowNoModificationAllowedError("Animated values cannot be set"); 64 return; 65 } 66 67 gfxMatrix mx = GetMatrix(); 68 mx._22 = aD; 69 SetMatrix(mx); 70 } 71 72 void SVGMatrix::SetE(float aE, ErrorResult& aRv) { 73 if (IsAnimVal()) { 74 aRv.ThrowNoModificationAllowedError("Animated values cannot be set"); 75 return; 76 } 77 78 gfxMatrix mx = GetMatrix(); 79 mx._31 = aE; 80 SetMatrix(mx); 81 } 82 83 void SVGMatrix::SetF(float aF, ErrorResult& aRv) { 84 if (IsAnimVal()) { 85 aRv.ThrowNoModificationAllowedError("Animated values cannot be set"); 86 return; 87 } 88 89 gfxMatrix mx = GetMatrix(); 90 mx._32 = aF; 91 SetMatrix(mx); 92 } 93 94 already_AddRefed<SVGMatrix> SVGMatrix::Multiply(const DOMMatrix2DInit& aMatrix, 95 ErrorResult& aRv) { 96 auto matrix2D = DOMMatrixReadOnly::ToValidatedMatrixDouble(aMatrix, aRv); 97 if (aRv.Failed()) { 98 return nullptr; 99 } 100 if (!matrix2D.IsFinite()) { 101 aRv.ThrowTypeError<MSG_NOT_FINITE>("SVGMatrix::Multiply matrix"); 102 return nullptr; 103 } 104 return do_AddRef(new SVGMatrix(matrix2D * GetMatrix())); 105 } 106 107 already_AddRefed<SVGMatrix> SVGMatrix::Inverse(ErrorResult& aRv) { 108 gfxMatrix mat = GetMatrix(); 109 if (!mat.Invert()) { 110 aRv.ThrowInvalidStateError("Matrix is not invertible"); 111 return nullptr; 112 } 113 return do_AddRef(new SVGMatrix(mat)); 114 } 115 116 already_AddRefed<SVGMatrix> SVGMatrix::Translate(float x, float y) { 117 return do_AddRef( 118 new SVGMatrix(gfxMatrix(GetMatrix()).PreTranslate(gfxPoint(x, y)))); 119 } 120 121 already_AddRefed<SVGMatrix> SVGMatrix::Scale(float scaleFactor) { 122 return ScaleNonUniform(scaleFactor, scaleFactor); 123 } 124 125 already_AddRefed<SVGMatrix> SVGMatrix::ScaleNonUniform(float scaleFactorX, 126 float scaleFactorY) { 127 return do_AddRef(new SVGMatrix( 128 gfxMatrix(GetMatrix()).PreScale(scaleFactorX, scaleFactorY))); 129 } 130 131 already_AddRefed<SVGMatrix> SVGMatrix::Rotate(float angle) { 132 return do_AddRef( 133 new SVGMatrix(gfxMatrix(GetMatrix()).PreRotate(angle * radPerDegree))); 134 } 135 136 already_AddRefed<SVGMatrix> SVGMatrix::RotateFromVector(float x, float y, 137 ErrorResult& aRv) { 138 if (x == 0.0 || y == 0.0) { 139 aRv.ThrowInvalidAccessError("Neither input parameter may be zero"); 140 return nullptr; 141 } 142 143 return do_AddRef( 144 new SVGMatrix(gfxMatrix(GetMatrix()).PreRotate(atan2(y, x)))); 145 } 146 147 already_AddRefed<SVGMatrix> SVGMatrix::FlipX() { 148 const gfxMatrix& mx = GetMatrix(); 149 return do_AddRef(new SVGMatrix( 150 gfxMatrix(-mx._11, -mx._12, mx._21, mx._22, mx._31, mx._32))); 151 } 152 153 already_AddRefed<SVGMatrix> SVGMatrix::FlipY() { 154 const gfxMatrix& mx = GetMatrix(); 155 return do_AddRef(new SVGMatrix( 156 gfxMatrix(mx._11, mx._12, -mx._21, -mx._22, mx._31, mx._32))); 157 } 158 159 already_AddRefed<SVGMatrix> SVGMatrix::SkewX(float angle, ErrorResult& aRv) { 160 double ta = tan(angle * radPerDegree); 161 if (!std::isfinite(ta)) { 162 aRv.ThrowInvalidAccessError("Invalid angle"); 163 return nullptr; 164 } 165 166 const gfxMatrix& mx = GetMatrix(); 167 gfxMatrix skewMx(mx._11, mx._12, mx._21 + mx._11 * ta, mx._22 + mx._12 * ta, 168 mx._31, mx._32); 169 return do_AddRef(new SVGMatrix(skewMx)); 170 } 171 172 already_AddRefed<SVGMatrix> SVGMatrix::SkewY(float angle, ErrorResult& aRv) { 173 double ta = tan(angle * radPerDegree); 174 if (!std::isfinite(ta)) { 175 aRv.ThrowInvalidAccessError("Invalid angle"); 176 return nullptr; 177 } 178 179 const gfxMatrix& mx = GetMatrix(); 180 gfxMatrix skewMx(mx._11 + mx._21 * ta, mx._12 + mx._22 * ta, mx._21, mx._22, 181 mx._31, mx._32); 182 183 return do_AddRef(new SVGMatrix(skewMx)); 184 } 185 186 } // namespace mozilla::dom