Index: third_party/WebKit/Source/core/dom/DOMMatrixReadOnly.cpp |
diff --git a/third_party/WebKit/Source/core/dom/DOMMatrixReadOnly.cpp b/third_party/WebKit/Source/core/dom/DOMMatrixReadOnly.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e4c1ed95915423ee26b242a647d136df8fafd511 |
--- /dev/null |
+++ b/third_party/WebKit/Source/core/dom/DOMMatrixReadOnly.cpp |
@@ -0,0 +1,398 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "core/dom/DOMMatrixReadOnly.h" |
+ |
+#include "bindings/core/v8/V8ObjectBuilder.h" |
+#include "core/css/CSSIdentifierValue.h" |
+#include "core/css/CSSToLengthConversionData.h" |
+#include "core/css/CSSValueList.h" |
+#include "core/css/parser/CSSParser.h" |
+#include "core/css/resolver/TransformBuilder.h" |
+#include "core/dom/DOMMatrix.h" |
+#include "core/dom/DOMMatrixInit.h" |
+#include "core/dom/DOMPoint.h" |
+#include "core/dom/DOMPointInit.h" |
+#include "core/layout/api/LayoutViewItem.h" |
+#include "core/style/ComputedStyle.h" |
+ |
+namespace blink { |
+namespace { |
+ |
+void setDictionaryMembers(DOMMatrixInit& other) { |
+ if (!other.hasM11()) |
+ other.setM11(other.hasA() ? other.a() : 1); |
+ |
+ if (!other.hasM12()) |
+ other.setM12(other.hasB() ? other.b() : 0); |
+ |
+ if (!other.hasM21()) |
+ other.setM21(other.hasC() ? other.c() : 0); |
+ |
+ if (!other.hasM22()) |
+ other.setM22(other.hasD() ? other.d() : 1); |
+ |
+ if (!other.hasM41()) |
+ other.setM41(other.hasE() ? other.e() : 0); |
+ |
+ if (!other.hasM42()) |
+ other.setM42(other.hasF() ? other.f() : 0); |
+} |
+ |
+String getErrorMessage(const char* a, const char* b) { |
+ return String::format("The '%s' property should equal the '%s' property.", a, |
+ b); |
+} |
+ |
+} // namespace |
+ |
+bool DOMMatrixReadOnly::validateAndFixup(DOMMatrixInit& other, |
+ ExceptionState& exceptionState) { |
+ if (other.hasA() && other.hasM11() && other.a() != other.m11()) { |
+ exceptionState.throwTypeError(getErrorMessage("a", "m11")); |
+ return false; |
+ } |
+ if (other.hasB() && other.hasM12() && other.b() != other.m12()) { |
+ exceptionState.throwTypeError(getErrorMessage("b", "m12")); |
+ return false; |
+ } |
+ if (other.hasC() && other.hasM21() && other.c() != other.m21()) { |
+ exceptionState.throwTypeError(getErrorMessage("c", "m21")); |
+ return false; |
+ } |
+ if (other.hasD() && other.hasM22() && other.d() != other.m22()) { |
+ exceptionState.throwTypeError(getErrorMessage("d", "m22")); |
+ return false; |
+ } |
+ if (other.hasE() && other.hasM41() && other.e() != other.m41()) { |
+ exceptionState.throwTypeError(getErrorMessage("e", "m41")); |
+ return false; |
+ } |
+ if (other.hasF() && other.hasM42() && other.f() != other.m42()) { |
+ exceptionState.throwTypeError(getErrorMessage("f", "m42")); |
+ return false; |
+ } |
+ if (other.hasIs2D() && other.is2D() && |
+ (other.m31() || other.m32() || other.m13() || other.m23() || |
+ other.m43() || other.m14() || other.m24() || other.m34() || |
+ other.m33() != 1 || other.m44() != 1)) { |
+ exceptionState.throwTypeError( |
+ "The is2D member is set to true but the input matrix is 3d matrix."); |
+ return false; |
+ } |
+ |
+ setDictionaryMembers(other); |
+ if (!other.hasIs2D()) { |
+ bool is2D = !(other.m31() || other.m32() || other.m13() || other.m23() || |
+ other.m43() || other.m14() || other.m24() || other.m34() || |
+ other.m33() != 1 || other.m44() != 1); |
+ other.setIs2D(is2D); |
+ } |
+ return true; |
+} |
+ |
+DOMMatrixReadOnly* DOMMatrixReadOnly::create(ExceptionState& exceptionState) { |
+ return new DOMMatrixReadOnly(TransformationMatrix()); |
+} |
+ |
+DOMMatrixReadOnly* DOMMatrixReadOnly::create(const String& transformList, |
+ ExceptionState& exceptionState) { |
+ DOMMatrixReadOnly* matrix = new DOMMatrixReadOnly(TransformationMatrix()); |
+ matrix->setMatrixValueFromString(transformList, exceptionState); |
+ return matrix; |
+} |
+ |
+DOMMatrixReadOnly* DOMMatrixReadOnly::create(Vector<double> sequence, |
+ ExceptionState& exceptionState) { |
+ if (sequence.size() != 6 && sequence.size() != 16) { |
+ exceptionState.throwTypeError( |
+ "The sequence must contain 6 elements for a 2D matrix or 16 elements " |
+ "for a 3D matrix."); |
+ return nullptr; |
+ } |
+ return new DOMMatrixReadOnly(sequence, sequence.size()); |
+} |
+ |
+DOMMatrixReadOnly* DOMMatrixReadOnly::fromFloat32Array( |
+ DOMFloat32Array* float32Array, |
+ ExceptionState& exceptionState) { |
+ if (float32Array->length() != 6 && float32Array->length() != 16) { |
+ exceptionState.throwTypeError( |
+ "The sequence must contain 6 elements for a 2D matrix or 16 elements a " |
+ "for 3D matrix."); |
+ return nullptr; |
+ } |
+ return new DOMMatrixReadOnly(float32Array->data(), float32Array->length()); |
+} |
+ |
+DOMMatrixReadOnly* DOMMatrixReadOnly::fromFloat64Array( |
+ DOMFloat64Array* float64Array, |
+ ExceptionState& exceptionState) { |
+ if (float64Array->length() != 6 && float64Array->length() != 16) { |
+ exceptionState.throwTypeError( |
+ "The sequence must contain 6 elements for a 2D matrix or 16 elements " |
+ "for a 3D matrix."); |
+ return nullptr; |
+ } |
+ return new DOMMatrixReadOnly(float64Array->data(), float64Array->length()); |
+} |
+ |
+DOMMatrixReadOnly* DOMMatrixReadOnly::fromMatrix( |
+ DOMMatrixInit& other, |
+ ExceptionState& exceptionState) { |
+ if (!validateAndFixup(other, exceptionState)) { |
+ DCHECK(exceptionState.hadException()); |
+ return nullptr; |
+ } |
+ |
+ if (other.is2D()) { |
+ double args[] = {other.m11(), other.m12(), other.m21(), |
+ other.m22(), other.m41(), other.m42()}; |
+ return new DOMMatrixReadOnly(args, 6); |
+ } |
+ |
+ double args[] = {other.m11(), other.m12(), other.m13(), other.m14(), |
+ other.m21(), other.m22(), other.m23(), other.m24(), |
+ other.m31(), other.m32(), other.m33(), other.m34(), |
+ other.m41(), other.m42(), other.m43(), other.m44()}; |
+ return new DOMMatrixReadOnly(args, 16); |
+} |
+ |
+DOMMatrixReadOnly::~DOMMatrixReadOnly() {} |
+ |
+bool DOMMatrixReadOnly::is2D() const { |
+ return m_is2D; |
+} |
+ |
+bool DOMMatrixReadOnly::isIdentity() const { |
+ return m_matrix->isIdentity(); |
+} |
+ |
+DOMMatrix* DOMMatrixReadOnly::multiply(DOMMatrixInit& other, |
+ ExceptionState& exceptionState) { |
+ return DOMMatrix::create(this)->multiplySelf(other, exceptionState); |
+} |
+ |
+DOMMatrix* DOMMatrixReadOnly::translate(double tx, double ty, double tz) { |
+ return DOMMatrix::create(this)->translateSelf(tx, ty, tz); |
+} |
+ |
+DOMMatrix* DOMMatrixReadOnly::scale(double sx) { |
+ return scale(sx, sx); |
+} |
+ |
+DOMMatrix* DOMMatrixReadOnly::scale(double sx, |
+ double sy, |
+ double sz, |
+ double ox, |
+ double oy, |
+ double oz) { |
+ return DOMMatrix::create(this)->scaleSelf(sx, sy, sz, ox, oy, oz); |
+} |
+ |
+DOMMatrix* DOMMatrixReadOnly::scale3d(double scale, |
+ double ox, |
+ double oy, |
+ double oz) { |
+ return DOMMatrix::create(this)->scale3dSelf(scale, ox, oy, oz); |
+} |
+ |
+DOMMatrix* DOMMatrixReadOnly::rotate(double rotX) { |
+ return DOMMatrix::create(this)->rotateSelf(rotX); |
+} |
+ |
+DOMMatrix* DOMMatrixReadOnly::rotate(double rotX, double rotY) { |
+ return DOMMatrix::create(this)->rotateSelf(rotX, rotY); |
+} |
+ |
+DOMMatrix* DOMMatrixReadOnly::rotate(double rotX, double rotY, double rotZ) { |
+ return DOMMatrix::create(this)->rotateSelf(rotX, rotY, rotZ); |
+} |
+ |
+DOMMatrix* DOMMatrixReadOnly::rotateFromVector(double x, double y) { |
+ return DOMMatrix::create(this)->rotateFromVectorSelf(x, y); |
+} |
+ |
+DOMMatrix* DOMMatrixReadOnly::rotateAxisAngle(double x, |
+ double y, |
+ double z, |
+ double angle) { |
+ return DOMMatrix::create(this)->rotateAxisAngleSelf(x, y, z, angle); |
+} |
+ |
+DOMMatrix* DOMMatrixReadOnly::skewX(double sx) { |
+ return DOMMatrix::create(this)->skewXSelf(sx); |
+} |
+ |
+DOMMatrix* DOMMatrixReadOnly::skewY(double sy) { |
+ return DOMMatrix::create(this)->skewYSelf(sy); |
+} |
+ |
+DOMMatrix* DOMMatrixReadOnly::flipX() { |
+ DOMMatrix* flipX = DOMMatrix::create(this); |
+ flipX->setM11(-this->m11()); |
+ flipX->setM12(-this->m12()); |
+ flipX->setM13(-this->m13()); |
+ flipX->setM14(-this->m14()); |
+ return flipX; |
+} |
+ |
+DOMMatrix* DOMMatrixReadOnly::flipY() { |
+ DOMMatrix* flipY = DOMMatrix::create(this); |
+ flipY->setM21(-this->m21()); |
+ flipY->setM22(-this->m22()); |
+ flipY->setM23(-this->m23()); |
+ flipY->setM24(-this->m24()); |
+ return flipY; |
+} |
+ |
+DOMMatrix* DOMMatrixReadOnly::inverse() { |
+ return DOMMatrix::create(this)->invertSelf(); |
+} |
+ |
+DOMPoint* DOMMatrixReadOnly::transformPoint(const DOMPointInit& point) { |
+ if (is2D() && point.z() == 0 && point.w() == 1) { |
+ double x = point.x() * m11() + point.y() * m12() + m41(); |
+ double y = point.x() * m12() + point.y() * m22() + m42(); |
+ return DOMPoint::create(x, y, 0, 1); |
+ } |
+ |
+ double x = point.x() * m11() + point.y() * m21() + point.z() * m31() + |
+ point.w() * m41(); |
+ double y = point.x() * m12() + point.y() * m22() + point.z() * m32() + |
+ point.w() * m42(); |
+ double z = point.x() * m13() + point.y() * m23() + point.z() * m33() + |
+ point.w() * m43(); |
+ double w = point.x() * m14() + point.y() * m24() + point.z() * m34() + |
+ point.w() * m44(); |
+ return DOMPoint::create(x, y, z, w); |
+} |
+ |
+DOMMatrixReadOnly::DOMMatrixReadOnly(const TransformationMatrix& matrix, |
+ bool is2D) { |
+ m_matrix = TransformationMatrix::create(matrix); |
+ m_is2D = is2D; |
+} |
+ |
+DOMFloat32Array* DOMMatrixReadOnly::toFloat32Array() const { |
+ float array[] = { |
+ static_cast<float>(m_matrix->m11()), static_cast<float>(m_matrix->m12()), |
+ static_cast<float>(m_matrix->m13()), static_cast<float>(m_matrix->m14()), |
+ static_cast<float>(m_matrix->m21()), static_cast<float>(m_matrix->m22()), |
+ static_cast<float>(m_matrix->m23()), static_cast<float>(m_matrix->m24()), |
+ static_cast<float>(m_matrix->m31()), static_cast<float>(m_matrix->m32()), |
+ static_cast<float>(m_matrix->m33()), static_cast<float>(m_matrix->m34()), |
+ static_cast<float>(m_matrix->m41()), static_cast<float>(m_matrix->m42()), |
+ static_cast<float>(m_matrix->m43()), static_cast<float>(m_matrix->m44())}; |
+ |
+ return DOMFloat32Array::create(array, 16); |
+} |
+ |
+DOMFloat64Array* DOMMatrixReadOnly::toFloat64Array() const { |
+ double array[] = { |
+ m_matrix->m11(), m_matrix->m12(), m_matrix->m13(), m_matrix->m14(), |
+ m_matrix->m21(), m_matrix->m22(), m_matrix->m23(), m_matrix->m24(), |
+ m_matrix->m31(), m_matrix->m32(), m_matrix->m33(), m_matrix->m34(), |
+ m_matrix->m41(), m_matrix->m42(), m_matrix->m43(), m_matrix->m44()}; |
+ |
+ return DOMFloat64Array::create(array, 16); |
+} |
+ |
+const String DOMMatrixReadOnly::toString() const { |
+ std::stringstream stream; |
+ if (is2D()) { |
+ stream << "matrix(" << a() << ", " << b() << ", " << c() << ", " << d() |
+ << ", " << e() << ", " << f(); |
+ } else { |
+ stream << "matrix3d(" << m11() << ", " << m12() << ", " << m13() << ", " |
+ << m14() << ", " << m21() << ", " << m22() << ", " << m23() << ", " |
+ << m24() << ", " << m31() << ", " << m32() << ", " << m33() << ", " |
+ << m34() << ", " << m41() << ", " << m42() << ", " << m43() << ", " |
+ << m44(); |
+ } |
+ stream << ")"; |
+ |
+ return String(stream.str().c_str()); |
+} |
+ |
+ScriptValue DOMMatrixReadOnly::toJSONForBinding( |
+ ScriptState* scriptState) const { |
+ V8ObjectBuilder result(scriptState); |
+ result.addNumber("a", a()); |
+ result.addNumber("b", b()); |
+ result.addNumber("c", c()); |
+ result.addNumber("d", d()); |
+ result.addNumber("e", e()); |
+ result.addNumber("f", f()); |
+ result.addNumber("m11", m11()); |
+ result.addNumber("m12", m12()); |
+ result.addNumber("m13", m13()); |
+ result.addNumber("m14", m14()); |
+ result.addNumber("m21", m21()); |
+ result.addNumber("m22", m22()); |
+ result.addNumber("m23", m23()); |
+ result.addNumber("m24", m24()); |
+ result.addNumber("m31", m31()); |
+ result.addNumber("m32", m32()); |
+ result.addNumber("m33", m33()); |
+ result.addNumber("m34", m34()); |
+ result.addNumber("m41", m41()); |
+ result.addNumber("m42", m42()); |
+ result.addNumber("m43", m43()); |
+ result.addNumber("m44", m44()); |
+ result.addBoolean("is2D", is2D()); |
+ result.addBoolean("isIdentity", isIdentity()); |
+ return result.scriptValue(); |
+} |
+ |
+void DOMMatrixReadOnly::setMatrixValueFromString( |
+ const String& inputString, |
+ ExceptionState& exceptionState) { |
+ DEFINE_STATIC_LOCAL(String, identityMatrix2D, ("matrix(1, 0, 0, 1, 0, 0)")); |
+ String string = inputString; |
+ if (string.isEmpty()) |
+ string = identityMatrix2D; |
+ |
+ const CSSValue* value = |
+ CSSParser::parseSingleValue(CSSPropertyTransform, string); |
+ |
+ if (!value || value->isCSSWideKeyword()) { |
+ exceptionState.throwDOMException(SyntaxError, |
+ "Failed to parse '" + inputString + "'."); |
+ return; |
+ } |
+ |
+ if (value->isIdentifierValue()) { |
+ DCHECK(toCSSIdentifierValue(value)->getValueID() == CSSValueNone); |
+ m_matrix->makeIdentity(); |
+ m_is2D = true; |
+ return; |
+ } |
+ |
+ if (TransformBuilder::hasRelativeLengths(toCSSValueList(*value))) { |
+ exceptionState.throwDOMException(SyntaxError, |
+ "Lengths must be absolute, not relative"); |
+ return; |
+ } |
+ |
+ const ComputedStyle& initialStyle = ComputedStyle::initialStyle(); |
+ TransformOperations operations = TransformBuilder::createTransformOperations( |
+ *value, CSSToLengthConversionData(&initialStyle, &initialStyle, |
+ LayoutViewItem(nullptr), 1.0f)); |
+ |
+ if (operations.dependsOnBoxSize()) { |
+ exceptionState.throwDOMException( |
+ SyntaxError, "Lengths must be absolute, not depend on the box size"); |
+ return; |
+ } |
+ |
+ m_matrix->makeIdentity(); |
+ operations.apply(FloatSize(0, 0), *m_matrix); |
+ |
+ m_is2D = !operations.has3DOperation(); |
+ |
+ return; |
+} |
+ |
+} // namespace blink |