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/dom/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/dom/DOMMatrix.h" |
| 14 #include "core/dom/DOMMatrixInit.h" |
| 15 #include "core/dom/DOMPoint.h" |
| 16 #include "core/dom/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 |