OLD | NEW |
| (Empty) |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "core/geometry/DOMMatrixReadOnly.h" | |
6 | |
7 #include "bindings/core/v8/V8ObjectBuilder.h" | |
8 #include "core/css/CSSIdentifierValue.h" | |
9 #include "core/css/CSSToLengthConversionData.h" | |
10 #include "core/css/CSSValueList.h" | |
11 #include "core/css/parser/CSSParser.h" | |
12 #include "core/css/resolver/TransformBuilder.h" | |
13 #include "core/geometry/DOMMatrix.h" | |
14 #include "core/geometry/DOMMatrixInit.h" | |
15 #include "core/geometry/DOMPoint.h" | |
16 #include "core/geometry/DOMPointInit.h" | |
17 #include "core/layout/api/LayoutViewItem.h" | |
18 #include "core/style/ComputedStyle.h" | |
19 | |
20 namespace blink { | |
21 namespace { | |
22 | |
23 void setDictionaryMembers(DOMMatrixInit& other) { | |
24 if (!other.hasM11()) | |
25 other.setM11(other.hasA() ? other.a() : 1); | |
26 | |
27 if (!other.hasM12()) | |
28 other.setM12(other.hasB() ? other.b() : 0); | |
29 | |
30 if (!other.hasM21()) | |
31 other.setM21(other.hasC() ? other.c() : 0); | |
32 | |
33 if (!other.hasM22()) | |
34 other.setM22(other.hasD() ? other.d() : 1); | |
35 | |
36 if (!other.hasM41()) | |
37 other.setM41(other.hasE() ? other.e() : 0); | |
38 | |
39 if (!other.hasM42()) | |
40 other.setM42(other.hasF() ? other.f() : 0); | |
41 } | |
42 | |
43 String getErrorMessage(const char* a, const char* b) { | |
44 return String::format("The '%s' property should equal the '%s' property.", a, | |
45 b); | |
46 } | |
47 | |
48 } // namespace | |
49 | |
50 bool DOMMatrixReadOnly::validateAndFixup(DOMMatrixInit& other, | |
51 ExceptionState& exceptionState) { | |
52 if (other.hasA() && other.hasM11() && other.a() != other.m11()) { | |
53 exceptionState.throwTypeError(getErrorMessage("a", "m11")); | |
54 return false; | |
55 } | |
56 if (other.hasB() && other.hasM12() && other.b() != other.m12()) { | |
57 exceptionState.throwTypeError(getErrorMessage("b", "m12")); | |
58 return false; | |
59 } | |
60 if (other.hasC() && other.hasM21() && other.c() != other.m21()) { | |
61 exceptionState.throwTypeError(getErrorMessage("c", "m21")); | |
62 return false; | |
63 } | |
64 if (other.hasD() && other.hasM22() && other.d() != other.m22()) { | |
65 exceptionState.throwTypeError(getErrorMessage("d", "m22")); | |
66 return false; | |
67 } | |
68 if (other.hasE() && other.hasM41() && other.e() != other.m41()) { | |
69 exceptionState.throwTypeError(getErrorMessage("e", "m41")); | |
70 return false; | |
71 } | |
72 if (other.hasF() && other.hasM42() && other.f() != other.m42()) { | |
73 exceptionState.throwTypeError(getErrorMessage("f", "m42")); | |
74 return false; | |
75 } | |
76 if (other.hasIs2D() && other.is2D() && | |
77 (other.m31() || other.m32() || other.m13() || other.m23() || | |
78 other.m43() || other.m14() || other.m24() || other.m34() || | |
79 other.m33() != 1 || other.m44() != 1)) { | |
80 exceptionState.throwTypeError( | |
81 "The is2D member is set to true but the input matrix is 3d matrix."); | |
82 return false; | |
83 } | |
84 | |
85 setDictionaryMembers(other); | |
86 if (!other.hasIs2D()) { | |
87 bool is2D = !(other.m31() || other.m32() || other.m13() || other.m23() || | |
88 other.m43() || other.m14() || other.m24() || other.m34() || | |
89 other.m33() != 1 || other.m44() != 1); | |
90 other.setIs2D(is2D); | |
91 } | |
92 return true; | |
93 } | |
94 | |
95 DOMMatrixReadOnly* DOMMatrixReadOnly::create(ExceptionState& exceptionState) { | |
96 return new DOMMatrixReadOnly(TransformationMatrix()); | |
97 } | |
98 | |
99 DOMMatrixReadOnly* DOMMatrixReadOnly::create(const String& transformList, | |
100 ExceptionState& exceptionState) { | |
101 DOMMatrixReadOnly* matrix = new DOMMatrixReadOnly(TransformationMatrix()); | |
102 matrix->setMatrixValueFromString(transformList, exceptionState); | |
103 return matrix; | |
104 } | |
105 | |
106 DOMMatrixReadOnly* DOMMatrixReadOnly::create(Vector<double> sequence, | |
107 ExceptionState& exceptionState) { | |
108 if (sequence.size() != 6 && sequence.size() != 16) { | |
109 exceptionState.throwTypeError( | |
110 "The sequence must contain 6 elements for a 2D matrix or 16 elements " | |
111 "for a 3D matrix."); | |
112 return nullptr; | |
113 } | |
114 return new DOMMatrixReadOnly(sequence, sequence.size()); | |
115 } | |
116 | |
117 DOMMatrixReadOnly* DOMMatrixReadOnly::fromFloat32Array( | |
118 DOMFloat32Array* float32Array, | |
119 ExceptionState& exceptionState) { | |
120 if (float32Array->length() != 6 && float32Array->length() != 16) { | |
121 exceptionState.throwTypeError( | |
122 "The sequence must contain 6 elements for a 2D matrix or 16 elements a " | |
123 "for 3D matrix."); | |
124 return nullptr; | |
125 } | |
126 return new DOMMatrixReadOnly(float32Array->data(), float32Array->length()); | |
127 } | |
128 | |
129 DOMMatrixReadOnly* DOMMatrixReadOnly::fromFloat64Array( | |
130 DOMFloat64Array* float64Array, | |
131 ExceptionState& exceptionState) { | |
132 if (float64Array->length() != 6 && float64Array->length() != 16) { | |
133 exceptionState.throwTypeError( | |
134 "The sequence must contain 6 elements for a 2D matrix or 16 elements " | |
135 "for a 3D matrix."); | |
136 return nullptr; | |
137 } | |
138 return new DOMMatrixReadOnly(float64Array->data(), float64Array->length()); | |
139 } | |
140 | |
141 DOMMatrixReadOnly* DOMMatrixReadOnly::fromMatrix( | |
142 DOMMatrixInit& other, | |
143 ExceptionState& exceptionState) { | |
144 if (!validateAndFixup(other, exceptionState)) { | |
145 DCHECK(exceptionState.hadException()); | |
146 return nullptr; | |
147 } | |
148 | |
149 if (other.is2D()) { | |
150 double args[] = {other.m11(), other.m12(), other.m21(), | |
151 other.m22(), other.m41(), other.m42()}; | |
152 return new DOMMatrixReadOnly(args, 6); | |
153 } | |
154 | |
155 double args[] = {other.m11(), other.m12(), other.m13(), other.m14(), | |
156 other.m21(), other.m22(), other.m23(), other.m24(), | |
157 other.m31(), other.m32(), other.m33(), other.m34(), | |
158 other.m41(), other.m42(), other.m43(), other.m44()}; | |
159 return new DOMMatrixReadOnly(args, 16); | |
160 } | |
161 | |
162 DOMMatrixReadOnly::~DOMMatrixReadOnly() {} | |
163 | |
164 bool DOMMatrixReadOnly::is2D() const { | |
165 return m_is2D; | |
166 } | |
167 | |
168 bool DOMMatrixReadOnly::isIdentity() const { | |
169 return m_matrix->isIdentity(); | |
170 } | |
171 | |
172 DOMMatrix* DOMMatrixReadOnly::multiply(DOMMatrixInit& other, | |
173 ExceptionState& exceptionState) { | |
174 return DOMMatrix::create(this)->multiplySelf(other, exceptionState); | |
175 } | |
176 | |
177 DOMMatrix* DOMMatrixReadOnly::translate(double tx, double ty, double tz) { | |
178 return DOMMatrix::create(this)->translateSelf(tx, ty, tz); | |
179 } | |
180 | |
181 DOMMatrix* DOMMatrixReadOnly::scale(double sx) { | |
182 return scale(sx, sx); | |
183 } | |
184 | |
185 DOMMatrix* DOMMatrixReadOnly::scale(double sx, | |
186 double sy, | |
187 double sz, | |
188 double ox, | |
189 double oy, | |
190 double oz) { | |
191 return DOMMatrix::create(this)->scaleSelf(sx, sy, sz, ox, oy, oz); | |
192 } | |
193 | |
194 DOMMatrix* DOMMatrixReadOnly::scale3d(double scale, | |
195 double ox, | |
196 double oy, | |
197 double oz) { | |
198 return DOMMatrix::create(this)->scale3dSelf(scale, ox, oy, oz); | |
199 } | |
200 | |
201 DOMMatrix* DOMMatrixReadOnly::rotate(double rotX) { | |
202 return DOMMatrix::create(this)->rotateSelf(rotX); | |
203 } | |
204 | |
205 DOMMatrix* DOMMatrixReadOnly::rotate(double rotX, double rotY) { | |
206 return DOMMatrix::create(this)->rotateSelf(rotX, rotY); | |
207 } | |
208 | |
209 DOMMatrix* DOMMatrixReadOnly::rotate(double rotX, double rotY, double rotZ) { | |
210 return DOMMatrix::create(this)->rotateSelf(rotX, rotY, rotZ); | |
211 } | |
212 | |
213 DOMMatrix* DOMMatrixReadOnly::rotateFromVector(double x, double y) { | |
214 return DOMMatrix::create(this)->rotateFromVectorSelf(x, y); | |
215 } | |
216 | |
217 DOMMatrix* DOMMatrixReadOnly::rotateAxisAngle(double x, | |
218 double y, | |
219 double z, | |
220 double angle) { | |
221 return DOMMatrix::create(this)->rotateAxisAngleSelf(x, y, z, angle); | |
222 } | |
223 | |
224 DOMMatrix* DOMMatrixReadOnly::skewX(double sx) { | |
225 return DOMMatrix::create(this)->skewXSelf(sx); | |
226 } | |
227 | |
228 DOMMatrix* DOMMatrixReadOnly::skewY(double sy) { | |
229 return DOMMatrix::create(this)->skewYSelf(sy); | |
230 } | |
231 | |
232 DOMMatrix* DOMMatrixReadOnly::flipX() { | |
233 DOMMatrix* flipX = DOMMatrix::create(this); | |
234 flipX->setM11(-this->m11()); | |
235 flipX->setM12(-this->m12()); | |
236 flipX->setM13(-this->m13()); | |
237 flipX->setM14(-this->m14()); | |
238 return flipX; | |
239 } | |
240 | |
241 DOMMatrix* DOMMatrixReadOnly::flipY() { | |
242 DOMMatrix* flipY = DOMMatrix::create(this); | |
243 flipY->setM21(-this->m21()); | |
244 flipY->setM22(-this->m22()); | |
245 flipY->setM23(-this->m23()); | |
246 flipY->setM24(-this->m24()); | |
247 return flipY; | |
248 } | |
249 | |
250 DOMMatrix* DOMMatrixReadOnly::inverse() { | |
251 return DOMMatrix::create(this)->invertSelf(); | |
252 } | |
253 | |
254 DOMPoint* DOMMatrixReadOnly::transformPoint(const DOMPointInit& point) { | |
255 if (is2D() && point.z() == 0 && point.w() == 1) { | |
256 double x = point.x() * m11() + point.y() * m12() + m41(); | |
257 double y = point.x() * m12() + point.y() * m22() + m42(); | |
258 return DOMPoint::create(x, y, 0, 1); | |
259 } | |
260 | |
261 double x = point.x() * m11() + point.y() * m21() + point.z() * m31() + | |
262 point.w() * m41(); | |
263 double y = point.x() * m12() + point.y() * m22() + point.z() * m32() + | |
264 point.w() * m42(); | |
265 double z = point.x() * m13() + point.y() * m23() + point.z() * m33() + | |
266 point.w() * m43(); | |
267 double w = point.x() * m14() + point.y() * m24() + point.z() * m34() + | |
268 point.w() * m44(); | |
269 return DOMPoint::create(x, y, z, w); | |
270 } | |
271 | |
272 DOMMatrixReadOnly::DOMMatrixReadOnly(const TransformationMatrix& matrix, | |
273 bool is2D) { | |
274 m_matrix = TransformationMatrix::create(matrix); | |
275 m_is2D = is2D; | |
276 } | |
277 | |
278 DOMFloat32Array* DOMMatrixReadOnly::toFloat32Array() const { | |
279 float array[] = { | |
280 static_cast<float>(m_matrix->m11()), static_cast<float>(m_matrix->m12()), | |
281 static_cast<float>(m_matrix->m13()), static_cast<float>(m_matrix->m14()), | |
282 static_cast<float>(m_matrix->m21()), static_cast<float>(m_matrix->m22()), | |
283 static_cast<float>(m_matrix->m23()), static_cast<float>(m_matrix->m24()), | |
284 static_cast<float>(m_matrix->m31()), static_cast<float>(m_matrix->m32()), | |
285 static_cast<float>(m_matrix->m33()), static_cast<float>(m_matrix->m34()), | |
286 static_cast<float>(m_matrix->m41()), static_cast<float>(m_matrix->m42()), | |
287 static_cast<float>(m_matrix->m43()), static_cast<float>(m_matrix->m44())}; | |
288 | |
289 return DOMFloat32Array::create(array, 16); | |
290 } | |
291 | |
292 DOMFloat64Array* DOMMatrixReadOnly::toFloat64Array() const { | |
293 double array[] = { | |
294 m_matrix->m11(), m_matrix->m12(), m_matrix->m13(), m_matrix->m14(), | |
295 m_matrix->m21(), m_matrix->m22(), m_matrix->m23(), m_matrix->m24(), | |
296 m_matrix->m31(), m_matrix->m32(), m_matrix->m33(), m_matrix->m34(), | |
297 m_matrix->m41(), m_matrix->m42(), m_matrix->m43(), m_matrix->m44()}; | |
298 | |
299 return DOMFloat64Array::create(array, 16); | |
300 } | |
301 | |
302 const String DOMMatrixReadOnly::toString() const { | |
303 std::stringstream stream; | |
304 if (is2D()) { | |
305 stream << "matrix(" << a() << ", " << b() << ", " << c() << ", " << d() | |
306 << ", " << e() << ", " << f(); | |
307 } else { | |
308 stream << "matrix3d(" << m11() << ", " << m12() << ", " << m13() << ", " | |
309 << m14() << ", " << m21() << ", " << m22() << ", " << m23() << ", " | |
310 << m24() << ", " << m31() << ", " << m32() << ", " << m33() << ", " | |
311 << m34() << ", " << m41() << ", " << m42() << ", " << m43() << ", " | |
312 << m44(); | |
313 } | |
314 stream << ")"; | |
315 | |
316 return String(stream.str().c_str()); | |
317 } | |
318 | |
319 ScriptValue DOMMatrixReadOnly::toJSONForBinding( | |
320 ScriptState* scriptState) const { | |
321 V8ObjectBuilder result(scriptState); | |
322 result.addNumber("a", a()); | |
323 result.addNumber("b", b()); | |
324 result.addNumber("c", c()); | |
325 result.addNumber("d", d()); | |
326 result.addNumber("e", e()); | |
327 result.addNumber("f", f()); | |
328 result.addNumber("m11", m11()); | |
329 result.addNumber("m12", m12()); | |
330 result.addNumber("m13", m13()); | |
331 result.addNumber("m14", m14()); | |
332 result.addNumber("m21", m21()); | |
333 result.addNumber("m22", m22()); | |
334 result.addNumber("m23", m23()); | |
335 result.addNumber("m24", m24()); | |
336 result.addNumber("m31", m31()); | |
337 result.addNumber("m32", m32()); | |
338 result.addNumber("m33", m33()); | |
339 result.addNumber("m34", m34()); | |
340 result.addNumber("m41", m41()); | |
341 result.addNumber("m42", m42()); | |
342 result.addNumber("m43", m43()); | |
343 result.addNumber("m44", m44()); | |
344 result.addBoolean("is2D", is2D()); | |
345 result.addBoolean("isIdentity", isIdentity()); | |
346 return result.scriptValue(); | |
347 } | |
348 | |
349 void DOMMatrixReadOnly::setMatrixValueFromString( | |
350 const String& inputString, | |
351 ExceptionState& exceptionState) { | |
352 DEFINE_STATIC_LOCAL(String, identityMatrix2D, ("matrix(1, 0, 0, 1, 0, 0)")); | |
353 String string = inputString; | |
354 if (string.isEmpty()) | |
355 string = identityMatrix2D; | |
356 | |
357 const CSSValue* value = | |
358 CSSParser::parseSingleValue(CSSPropertyTransform, string); | |
359 | |
360 if (!value || value->isCSSWideKeyword()) { | |
361 exceptionState.throwDOMException(SyntaxError, | |
362 "Failed to parse '" + inputString + "'."); | |
363 return; | |
364 } | |
365 | |
366 if (value->isIdentifierValue()) { | |
367 DCHECK(toCSSIdentifierValue(value)->getValueID() == CSSValueNone); | |
368 m_matrix->makeIdentity(); | |
369 m_is2D = true; | |
370 return; | |
371 } | |
372 | |
373 if (TransformBuilder::hasRelativeLengths(toCSSValueList(*value))) { | |
374 exceptionState.throwDOMException(SyntaxError, | |
375 "Lengths must be absolute, not relative"); | |
376 return; | |
377 } | |
378 | |
379 const ComputedStyle& initialStyle = ComputedStyle::initialStyle(); | |
380 TransformOperations operations = TransformBuilder::createTransformOperations( | |
381 *value, CSSToLengthConversionData(&initialStyle, &initialStyle, | |
382 LayoutViewItem(nullptr), 1.0f)); | |
383 | |
384 if (operations.dependsOnBoxSize()) { | |
385 exceptionState.throwDOMException( | |
386 SyntaxError, "Lengths must be absolute, not depend on the box size"); | |
387 return; | |
388 } | |
389 | |
390 m_matrix->makeIdentity(); | |
391 operations.apply(FloatSize(0, 0), *m_matrix); | |
392 | |
393 m_is2D = !operations.has3DOperation(); | |
394 | |
395 return; | |
396 } | |
397 | |
398 } // namespace blink | |
OLD | NEW |