Use "= default" to denote default constructor or destructor
[WebKit-https.git] / Source / WebCore / css / WebKitCSSMatrix.cpp
1 /*
2  * Copyright (C) 2008 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. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "WebKitCSSMatrix.h"
28
29 #include "CSSParser.h"
30 #include "CSSPrimitiveValue.h"
31 #include "CSSPropertyNames.h"
32 #include "CSSToLengthConversionData.h"
33 #include "CSSValueKeywords.h"
34 #include "StyleProperties.h"
35 #include "TransformFunctions.h"
36 #include <wtf/MathExtras.h>
37 #include <wtf/text/StringBuilder.h>
38
39 namespace WebCore {
40
41 inline WebKitCSSMatrix::WebKitCSSMatrix(const TransformationMatrix& matrix)
42     : m_matrix(matrix)
43 {
44 }
45
46 Ref<WebKitCSSMatrix> WebKitCSSMatrix::create(const TransformationMatrix& matrix)
47 {
48     return adoptRef(*new WebKitCSSMatrix(matrix));
49 }
50
51 ExceptionOr<Ref<WebKitCSSMatrix>> WebKitCSSMatrix::create(const String& string)
52 {
53     auto result = adoptRef(*new WebKitCSSMatrix);
54     auto setMatrixValueResult = result->setMatrixValue(string);
55     if (setMatrixValueResult.hasException())
56         return setMatrixValueResult.releaseException();
57     return WTFMove(result);
58 }
59
60 WebKitCSSMatrix::~WebKitCSSMatrix() = default;
61
62 ExceptionOr<void> WebKitCSSMatrix::setMatrixValue(const String& string)
63 {
64     if (string.isEmpty())
65         return { };
66
67     auto styleDeclaration = MutableStyleProperties::create();
68     if (CSSParser::parseValue(styleDeclaration, CSSPropertyTransform, string, true, HTMLStandardMode) == CSSParser::ParseResult::Error)
69         return Exception { SyntaxError };
70
71     // Convert to TransformOperations. This can fail if a property requires style (i.e., param uses 'ems' or 'exs')
72     auto value = styleDeclaration->getPropertyCSSValue(CSSPropertyTransform);
73
74     // Check for a "none" or empty transform. In these cases we can use the default identity matrix.
75     if (!value || (is<CSSPrimitiveValue>(*value) && downcast<CSSPrimitiveValue>(*value).valueID() == CSSValueNone))
76         return { };
77
78     TransformOperations operations;
79     if (!transformsForValue(*value, CSSToLengthConversionData(), operations))
80         return Exception { SyntaxError };
81
82     // Convert transform operations to a TransformationMatrix. This can fail if a parameter has a percentage ('%').
83     TransformationMatrix matrix;
84     for (auto& operation : operations.operations()) {
85         if (operation->apply(matrix, IntSize(0, 0)))
86             return Exception { SyntaxError };
87     }
88     m_matrix = matrix;
89     return { };
90 }
91
92 // Perform a concatenation of the matrices (this * secondMatrix)
93 RefPtr<WebKitCSSMatrix> WebKitCSSMatrix::multiply(WebKitCSSMatrix* secondMatrix) const
94 {
95     if (!secondMatrix)
96         return nullptr;
97
98     auto matrix = create(m_matrix);
99     matrix->m_matrix.multiply(secondMatrix->m_matrix);
100     return WTFMove(matrix);
101 }
102
103 ExceptionOr<Ref<WebKitCSSMatrix>> WebKitCSSMatrix::inverse() const
104 {
105     auto inverse = m_matrix.inverse();
106     if (!inverse)
107         return Exception { NotSupportedError };
108     return create(inverse.value());
109 }
110
111 Ref<WebKitCSSMatrix> WebKitCSSMatrix::translate(double x, double y, double z) const
112 {
113     if (std::isnan(x))
114         x = 0;
115     if (std::isnan(y))
116         y = 0;
117     if (std::isnan(z))
118         z = 0;
119
120     auto matrix = create(m_matrix);
121     matrix->m_matrix.translate3d(x, y, z);
122     return matrix;
123 }
124
125 Ref<WebKitCSSMatrix> WebKitCSSMatrix::scale(double scaleX, double scaleY, double scaleZ) const
126 {
127     if (std::isnan(scaleX))
128         scaleX = 1;
129     if (std::isnan(scaleY))
130         scaleY = scaleX;
131     if (std::isnan(scaleZ))
132         scaleZ = 1;
133
134     auto matrix = create(m_matrix);
135     matrix->m_matrix.scale3d(scaleX, scaleY, scaleZ);
136     return matrix;
137 }
138
139 Ref<WebKitCSSMatrix> WebKitCSSMatrix::rotate(double rotX, double rotY, double rotZ) const
140 {
141     if (std::isnan(rotX))
142         rotX = 0;
143
144     if (std::isnan(rotY) && std::isnan(rotZ)) {
145         rotZ = rotX;
146         rotX = 0;
147         rotY = 0;
148     }
149
150     if (std::isnan(rotY))
151         rotY = 0;
152     if (std::isnan(rotZ))
153         rotZ = 0;
154
155     auto matrix = create(m_matrix);
156     matrix->m_matrix.rotate3d(rotX, rotY, rotZ);
157     return matrix;
158 }
159
160 Ref<WebKitCSSMatrix> WebKitCSSMatrix::rotateAxisAngle(double x, double y, double z, double angle) const
161 {
162     if (std::isnan(x))
163         x = 0;
164     if (std::isnan(y))
165         y = 0;
166     if (std::isnan(z))
167         z = 0;
168     if (std::isnan(angle))
169         angle = 0;
170     if (x == 0 && y == 0 && z == 0)
171         z = 1;
172
173     auto matrix = create(m_matrix);
174     matrix->m_matrix.rotate3d(x, y, z, angle);
175     return matrix;
176 }
177
178 Ref<WebKitCSSMatrix> WebKitCSSMatrix::skewX(double angle) const
179 {
180     if (std::isnan(angle))
181         angle = 0;
182
183     auto matrix = create(m_matrix);
184     matrix->m_matrix.skewX(angle);
185     return matrix;
186 }
187
188 Ref<WebKitCSSMatrix> WebKitCSSMatrix::skewY(double angle) const
189 {
190     if (std::isnan(angle))
191         angle = 0;
192
193     auto matrix = create(m_matrix);
194     matrix->m_matrix.skewY(angle);
195     return matrix;
196 }
197
198 ExceptionOr<String> WebKitCSSMatrix::toString() const
199 {
200     if (!m_matrix.containsOnlyFiniteValues())
201         return Exception { InvalidStateError, ASCIILiteral("Matrix contains non-finite values") };
202
203     StringBuilder builder;
204     if (m_matrix.isAffine()) {
205         builder.appendLiteral("matrix(");
206         builder.append(String::numberToStringECMAScript(m_matrix.a()));
207         builder.appendLiteral(", ");
208         builder.append(String::numberToStringECMAScript(m_matrix.b()));
209         builder.appendLiteral(", ");
210         builder.append(String::numberToStringECMAScript(m_matrix.c()));
211         builder.appendLiteral(", ");
212         builder.append(String::numberToStringECMAScript(m_matrix.d()));
213         builder.appendLiteral(", ");
214         builder.append(String::numberToStringECMAScript(m_matrix.e()));
215         builder.appendLiteral(", ");
216         builder.append(String::numberToStringECMAScript(m_matrix.f()));
217     } else {
218         builder.appendLiteral("matrix3d(");
219         builder.append(String::numberToStringECMAScript(m_matrix.m11()));
220         builder.appendLiteral(", ");
221         builder.append(String::numberToStringECMAScript(m_matrix.m12()));
222         builder.appendLiteral(", ");
223         builder.append(String::numberToStringECMAScript(m_matrix.m13()));
224         builder.appendLiteral(", ");
225         builder.append(String::numberToStringECMAScript(m_matrix.m14()));
226         builder.appendLiteral(", ");
227         builder.append(String::numberToStringECMAScript(m_matrix.m21()));
228         builder.appendLiteral(", ");
229         builder.append(String::numberToStringECMAScript(m_matrix.m22()));
230         builder.appendLiteral(", ");
231         builder.append(String::numberToStringECMAScript(m_matrix.m23()));
232         builder.appendLiteral(", ");
233         builder.append(String::numberToStringECMAScript(m_matrix.m24()));
234         builder.appendLiteral(", ");
235         builder.append(String::numberToStringECMAScript(m_matrix.m31()));
236         builder.appendLiteral(", ");
237         builder.append(String::numberToStringECMAScript(m_matrix.m32()));
238         builder.appendLiteral(", ");
239         builder.append(String::numberToStringECMAScript(m_matrix.m33()));
240         builder.appendLiteral(", ");
241         builder.append(String::numberToStringECMAScript(m_matrix.m34()));
242         builder.appendLiteral(", ");
243         builder.append(String::numberToStringECMAScript(m_matrix.m41()));
244         builder.appendLiteral(", ");
245         builder.append(String::numberToStringECMAScript(m_matrix.m42()));
246         builder.appendLiteral(", ");
247         builder.append(String::numberToStringECMAScript(m_matrix.m43()));
248         builder.appendLiteral(", ");
249         builder.append(String::numberToStringECMAScript(m_matrix.m44()));
250     }
251     builder.append(')');
252     return builder.toString();
253 }
254
255 } // namespace WebCore