Use Optional::valueOr() instead of Optional::value_or()
[WebKit-https.git] / Source / WebCore / css / DOMMatrix.cpp
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "DOMMatrix.h"
28
29 #include "ScriptExecutionContext.h"
30 #include <cmath>
31 #include <limits>
32
33 namespace WebCore {
34
35 // https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-dommatrixreadonly
36 ExceptionOr<Ref<DOMMatrix>> DOMMatrix::create(ScriptExecutionContext& scriptExecutionContext, Optional<Variant<String, Vector<double>>>&& init)
37 {
38     if (!init)
39         return adoptRef(*new DOMMatrix);
40
41     return WTF::switchOn(init.value(),
42         [&scriptExecutionContext](const String& init) -> ExceptionOr<Ref<DOMMatrix>> {
43             if (!scriptExecutionContext.isDocument())
44                 return Exception { TypeError };
45
46             auto parseResult = parseStringIntoAbstractMatrix(init);
47             if (parseResult.hasException())
48                 return parseResult.releaseException();
49             
50             return adoptRef(*new DOMMatrix(parseResult.returnValue().matrix, parseResult.returnValue().is2D ? Is2D::Yes : Is2D::No));
51         },
52         [](const Vector<double>& init) -> ExceptionOr<Ref<DOMMatrix>> {
53             if (init.size() == 6) {
54                 return adoptRef(*new DOMMatrix(TransformationMatrix {
55                     init[0], init[1], init[2], init[3], init[4], init[5]
56                 }, Is2D::Yes));
57             }
58             if (init.size() == 16) {
59                 return adoptRef(*new DOMMatrix(TransformationMatrix {
60                     init[0], init[1], init[2], init[3],
61                     init[4], init[5], init[6], init[7],
62                     init[8], init[9], init[10], init[11],
63                     init[12], init[13], init[14], init[15]
64                 }, Is2D::No));
65             }
66             return Exception { TypeError };
67         }
68     );
69 }
70
71 DOMMatrix::DOMMatrix(const TransformationMatrix& matrix, Is2D is2D)
72     : DOMMatrixReadOnly(matrix, is2D)
73 {
74 }
75
76 DOMMatrix::DOMMatrix(TransformationMatrix&& matrix, Is2D is2D)
77     : DOMMatrixReadOnly(WTFMove(matrix), is2D)
78 {
79 }
80
81 // https://drafts.fxtf.org/geometry/#create-a-dommatrix-from-the-dictionary
82 ExceptionOr<Ref<DOMMatrix>> DOMMatrix::fromMatrix(DOMMatrixInit&& init)
83 {
84     return fromMatrixHelper<DOMMatrix>(WTFMove(init));
85 }
86
87 ExceptionOr<Ref<DOMMatrix>> DOMMatrix::fromFloat32Array(Ref<Float32Array>&& array32)
88 {
89     if (array32->length() == 6)
90         return DOMMatrix::create(TransformationMatrix(array32->item(0), array32->item(1), array32->item(2), array32->item(3), array32->item(4), array32->item(5)), Is2D::Yes);
91
92     if (array32->length() == 16) {
93         return DOMMatrix::create(TransformationMatrix(
94             array32->item(0), array32->item(1), array32->item(2), array32->item(3),
95             array32->item(4), array32->item(5), array32->item(6), array32->item(7),
96             array32->item(8), array32->item(9), array32->item(10), array32->item(11),
97             array32->item(12), array32->item(13), array32->item(14), array32->item(15)
98         ), Is2D::No);
99     }
100
101     return Exception { TypeError };
102 }
103
104 ExceptionOr<Ref<DOMMatrix>> DOMMatrix::fromFloat64Array(Ref<Float64Array>&& array64)
105 {
106     if (array64->length() == 6)
107         return DOMMatrix::create(TransformationMatrix(array64->item(0), array64->item(1), array64->item(2), array64->item(3), array64->item(4), array64->item(5)), Is2D::Yes);
108
109     if (array64->length() == 16) {
110         return DOMMatrix::create(TransformationMatrix(
111             array64->item(0), array64->item(1), array64->item(2), array64->item(3),
112             array64->item(4), array64->item(5), array64->item(6), array64->item(7),
113             array64->item(8), array64->item(9), array64->item(10), array64->item(11),
114             array64->item(12), array64->item(13), array64->item(14), array64->item(15)
115         ), Is2D::No);
116     }
117
118     return Exception { TypeError };
119 }
120
121 // https://drafts.fxtf.org/geometry/#dom-dommatrix-multiplyself
122 ExceptionOr<Ref<DOMMatrix>> DOMMatrix::multiplySelf(DOMMatrixInit&& other)
123 {
124     auto fromMatrixResult = DOMMatrix::fromMatrix(WTFMove(other));
125     if (fromMatrixResult.hasException())
126         return fromMatrixResult.releaseException();
127     auto otherObject = fromMatrixResult.releaseReturnValue();
128     m_matrix.multiply(otherObject->m_matrix);
129     if (!otherObject->is2D())
130         m_is2D = false;
131     return Ref<DOMMatrix> { *this };
132 }
133
134 // https://drafts.fxtf.org/geometry/#dom-dommatrix-premultiplyself
135 ExceptionOr<Ref<DOMMatrix>> DOMMatrix::preMultiplySelf(DOMMatrixInit&& other)
136 {
137     auto fromMatrixResult = DOMMatrix::fromMatrix(WTFMove(other));
138     if (fromMatrixResult.hasException())
139         return fromMatrixResult.releaseException();
140     auto otherObject = fromMatrixResult.releaseReturnValue();
141     m_matrix = otherObject->m_matrix * m_matrix;
142     if (!otherObject->is2D())
143         m_is2D = false;
144     return Ref<DOMMatrix> { *this };
145 }
146
147 // https://drafts.fxtf.org/geometry/#dom-dommatrix-translateself
148 Ref<DOMMatrix> DOMMatrix::translateSelf(double tx, double ty, double tz)
149 {
150     m_matrix.translate3d(tx, ty, tz);
151     if (tz)
152         m_is2D = false;
153     return *this;
154 }
155
156 // https://drafts.fxtf.org/geometry/#dom-dommatrix-scaleself
157 Ref<DOMMatrix> DOMMatrix::scaleSelf(double scaleX, Optional<double> scaleY, double scaleZ, double originX, double originY, double originZ)
158 {
159     if (!scaleY)
160         scaleY = scaleX;
161     translateSelf(originX, originY, originZ);
162     // Post-multiply a non-uniform scale transformation on the current matrix.
163     // The 3D scale matrix is described in CSS Transforms with sx = scaleX, sy = scaleY and sz = scaleZ.
164     m_matrix.scale3d(scaleX, scaleY.value(), scaleZ);
165     translateSelf(-originX, -originY, -originZ);
166     if (scaleZ != 1 || originZ)
167         m_is2D = false;
168     return *this;
169 }
170
171 // https://drafts.fxtf.org/geometry/#dom-dommatrix-scale3dself
172 Ref<DOMMatrix> DOMMatrix::scale3dSelf(double scale, double originX, double originY, double originZ)
173 {
174     translateSelf(originX, originY, originZ);
175     // Post-multiply a uniform 3D scale transformation (m11 = m22 = m33 = scale) on the current matrix.
176     // The 3D scale matrix is described in CSS Transforms with sx = sy = sz = scale. [CSS3-TRANSFORMS]
177     m_matrix.scale3d(scale, scale, scale);
178     translateSelf(-originX, -originY, -originZ);
179     if (scale != 1)
180         m_is2D = false;
181     return *this;
182 }
183
184 // https://drafts.fxtf.org/geometry/#dom-dommatrix-rotateself
185 Ref<DOMMatrix> DOMMatrix::rotateSelf(double rotX, Optional<double> rotY, Optional<double> rotZ)
186 {
187     if (!rotY && !rotZ) {
188         rotZ = rotX;
189         rotX = 0;
190         rotY = 0;
191     }
192     m_matrix.rotate3d(rotX, rotY.valueOr(0), rotZ.valueOr(0));
193     if (rotX || rotY.valueOr(0))
194         m_is2D = false;
195     return *this;
196 }
197
198 // https://drafts.fxtf.org/geometry/#dom-dommatrix-rotatefromvectorself
199 Ref<DOMMatrix> DOMMatrix::rotateFromVectorSelf(double x, double y)
200 {
201     m_matrix.rotateFromVector(x, y);
202     return *this;
203 }
204
205 // https://drafts.fxtf.org/geometry/#dom-dommatrix-rotateaxisangleself
206 Ref<DOMMatrix> DOMMatrix::rotateAxisAngleSelf(double x, double y, double z, double angle)
207 {
208     m_matrix.rotate3d(x, y, z, angle);
209     if (x || y)
210         m_is2D = false;
211     return *this;
212 }
213
214 // https://drafts.fxtf.org/geometry/#dom-dommatrix-skewxself
215 Ref<DOMMatrix> DOMMatrix::skewXSelf(double sx)
216 {
217     m_matrix.skewX(sx);
218     return *this;
219 }
220
221 // https://drafts.fxtf.org/geometry/#dom-dommatrix-skewyself
222 Ref<DOMMatrix> DOMMatrix::skewYSelf(double sy)
223 {
224     m_matrix.skewY(sy);
225     return *this;
226 }
227
228 // https://drafts.fxtf.org/geometry/#dom-dommatrix-invertself
229 Ref<DOMMatrix> DOMMatrix::invertSelf()
230 {
231     auto inverse = m_matrix.inverse();
232     if (inverse)
233         m_matrix = *inverse;
234     else {
235         m_matrix.setMatrix(
236             std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
237             std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
238             std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
239             std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()
240         );
241         m_is2D = false;
242     }
243     return Ref<DOMMatrix> { *this };
244 }
245
246 ExceptionOr<Ref<DOMMatrix>> DOMMatrix::setMatrixValueForBindings(const String& string)
247 {
248     auto result = setMatrixValue(string);
249     if (result.hasException())
250         return result.releaseException();
251     return Ref<DOMMatrix> { *this };
252 }
253
254 } // namespace WebCore