Align WebKitCSSMatrix stringifier with spec for DOMMatrix
https://bugs.webkit.org/show_bug.cgi?id=172114
Reviewed by Simon Fraser.
Source/WebCore:
Align WebKitCSSMatrix stringifier with spec for DOMMatrix after:
- https://github.com/w3c/fxtf-drafts/pull/148
The following changes were made:
- Use EcmaScript's ToString() to convert floating point values to string
- Throw an invalid state error if the matrix contains non-finite values
- Made WebKitCSSMatrix.toString enumerable as per [1].
[1] https://heycam.github.io/webidl/#es-stringifier
Test: fast/css/matrix-stringifier.html
* css/WebKitCSSMatrix.cpp:
(WebCore::WebKitCSSMatrix::toString):
* css/WebKitCSSMatrix.h:
* css/WebKitCSSMatrix.idl:
* platform/graphics/transforms/TransformationMatrix.cpp:
(WebCore::TransformationMatrix::containsOnlyFiniteValues):
* platform/graphics/transforms/TransformationMatrix.h:
LayoutTests:
* fast/css/matrix-stringifier-expected.txt: Added.
* fast/css/matrix-stringifier.html: Added.
Add layout test coverage.
* fast/dom/Window/custom-constructors-expected.txt:
* fast/dom/Window/custom-constructors.html:
Rebaseline existing test to reflect behavior change.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@216881 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 77fed87..baec1db 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,18 @@
+2017-05-15 Chris Dumez <cdumez@apple.com>
+
+ Align WebKitCSSMatrix stringifier with spec for DOMMatrix
+ https://bugs.webkit.org/show_bug.cgi?id=172114
+
+ Reviewed by Simon Fraser.
+
+ * fast/css/matrix-stringifier-expected.txt: Added.
+ * fast/css/matrix-stringifier.html: Added.
+ Add layout test coverage.
+
+ * fast/dom/Window/custom-constructors-expected.txt:
+ * fast/dom/Window/custom-constructors.html:
+ Rebaseline existing test to reflect behavior change.
+
2017-05-15 Mark Lam <mark.lam@apple.com>
WorkerRunLoop::Task::performTask() should check !scriptController->isTerminatingExecution().
diff --git a/LayoutTests/fast/css/matrix-stringifier-expected.txt b/LayoutTests/fast/css/matrix-stringifier-expected.txt
new file mode 100644
index 0000000..fc1a6be
--- /dev/null
+++ b/LayoutTests/fast/css/matrix-stringifier-expected.txt
@@ -0,0 +1,29 @@
+
+FAIL DOMMatrix stringifier: identity (2d) undefined is not a constructor (evaluating 'new self[constr]()')
+FAIL DOMMatrix stringifier: integer 2d undefined is not a constructor (evaluating 'new self[constr]("matrix(1, 0, 0, 1, 0, 0)")')
+FAIL DOMMatrix stringifier: integer 3d undefined is not a constructor (evaluating 'new self[constr]("matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)")')
+FAIL DOMMatrix stringifier: floating point 2d undefined is not a constructor (evaluating 'new self[constr]("matrix(0.1, 0.2, 0.3, 0.4, 0.5, 0.6)")')
+FAIL DOMMatrix stringifier: floating point 3d undefined is not a constructor (evaluating 'new self[constr]("matrix3d(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7)")')
+FAIL DOMMatrix stringifier: NaN undefined is not a constructor (evaluating 'new self[constr]()')
+FAIL DOMMatrix stringifier: Infinity undefined is not a constructor (evaluating 'new self[constr]()')
+FAIL DOMMatrix stringifier: -Infinity undefined is not a constructor (evaluating 'new self[constr]()')
+FAIL DOMMatrix.toString should be enumerable undefined is not an object (evaluating 'self[constr].prototype')
+FAIL DOMMatrixReadOnly stringifier: identity (2d) undefined is not a constructor (evaluating 'new self[constr]()')
+FAIL DOMMatrixReadOnly stringifier: integer 2d undefined is not a constructor (evaluating 'new self[constr]("matrix(1, 0, 0, 1, 0, 0)")')
+FAIL DOMMatrixReadOnly stringifier: integer 3d undefined is not a constructor (evaluating 'new self[constr]("matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)")')
+FAIL DOMMatrixReadOnly stringifier: floating point 2d undefined is not a constructor (evaluating 'new self[constr]("matrix(0.1, 0.2, 0.3, 0.4, 0.5, 0.6)")')
+FAIL DOMMatrixReadOnly stringifier: floating point 3d undefined is not a constructor (evaluating 'new self[constr]("matrix3d(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7)")')
+FAIL DOMMatrixReadOnly stringifier: NaN undefined is not a constructor (evaluating 'new self[constr]()')
+FAIL DOMMatrixReadOnly stringifier: Infinity undefined is not a constructor (evaluating 'new self[constr]()')
+FAIL DOMMatrixReadOnly stringifier: -Infinity undefined is not a constructor (evaluating 'new self[constr]()')
+FAIL DOMMatrixReadOnly.toString should be enumerable undefined is not an object (evaluating 'self[constr].prototype')
+PASS WebKitCSSMatrix stringifier: identity (2d)
+PASS WebKitCSSMatrix stringifier: integer 2d
+PASS WebKitCSSMatrix stringifier: integer 3d
+PASS WebKitCSSMatrix stringifier: floating point 2d
+PASS WebKitCSSMatrix stringifier: floating point 3d
+PASS WebKitCSSMatrix stringifier: NaN
+PASS WebKitCSSMatrix stringifier: Infinity
+PASS WebKitCSSMatrix stringifier: -Infinity
+PASS WebKitCSSMatrix.toString should be enumerable
+
diff --git a/LayoutTests/fast/css/matrix-stringifier.html b/LayoutTests/fast/css/matrix-stringifier.html
new file mode 100644
index 0000000..42ebce9
--- /dev/null
+++ b/LayoutTests/fast/css/matrix-stringifier.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+["DOMMatrix", "DOMMatrixReadOnly", "WebKitCSSMatrix"].forEach(constr => {
+ const prefix = `${constr} stringifier:`;
+ test(() => {
+ const matrix = new self[constr]();
+ assert_equals(String(matrix), "matrix(1, 0, 0, 1, 0, 0)");
+ }, `${prefix} identity (2d)`);
+
+ test(() => {
+ const matrix = new self[constr]("matrix(1, 0, 0, 1, 0, 0)");
+ assert_equals(String(matrix), "matrix(1, 0, 0, 1, 0, 0)");
+ }, `${prefix} integer 2d`);
+
+ test(() => {
+ const matrix = new self[constr]("matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)");
+ assert_equals(String(matrix), "matrix(1, 0, 0, 1, 0, 0)");
+ }, `${prefix} integer 3d`);
+
+ test(() => {
+ const matrix = new self[constr]("matrix(0.1, 0.2, 0.3, 0.4, 0.5, 0.6)");
+ assert_equals(String(matrix), "matrix(0.1, 0.2, 0.3, 0.4, 0.5, 0.6)");
+ }, `${prefix} floating point 2d`)
+
+ test(() => {
+ const matrix = new self[constr]("matrix3d(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7)");
+ assert_equals(String(matrix), "matrix3d(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7)");
+ }, `${prefix} floating point 3d`);
+
+ [NaN, Infinity, -Infinity].forEach(num => {
+ test(() => {
+ const matrix = new self[constr]();
+ matrix.a = num;
+ assert_throws("InvalidStateError", () => String(matrix));
+ }, `${prefix} ${num}`);
+ });
+
+ test(() => {
+ assert_true(Object.getOwnPropertyDescriptor(self[constr].prototype, "toString").enumerable);
+ }, `${constr}.toString should be enumerable`);
+});
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/dom/Window/custom-constructors-expected.txt b/LayoutTests/fast/dom/Window/custom-constructors-expected.txt
index 48d18a0..68175e0 100644
--- a/LayoutTests/fast/dom/Window/custom-constructors-expected.txt
+++ b/LayoutTests/fast/dom/Window/custom-constructors-expected.txt
@@ -6,9 +6,9 @@
PASS Image.prototype.toString.call(new Image) is '[object HTMLImageElement]'
PASS Option.prototype.toString.call(new Option) is '[object HTMLOptionElement]'
PASS WebKitPoint.prototype.toString.call(new WebKitPoint) is '[object WebKitPoint]'
-PASS WebKitCSSMatrix.prototype.toString.call(new WebKitCSSMatrix) is 'matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)'
-PASS WebKitCSSMatrix.prototype.toString.call(new WebKitCSSMatrix()) is 'matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)'
-PASS WebKitCSSMatrix.prototype.toString.call(new WebKitCSSMatrix(undefined)) is 'matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)'
+PASS WebKitCSSMatrix.prototype.toString.call(new WebKitCSSMatrix) is 'matrix(1, 0, 0, 1, 0, 0)'
+PASS WebKitCSSMatrix.prototype.toString.call(new WebKitCSSMatrix()) is 'matrix(1, 0, 0, 1, 0, 0)'
+PASS WebKitCSSMatrix.prototype.toString.call(new WebKitCSSMatrix(undefined)) is 'matrix(1, 0, 0, 1, 0, 0)'
PASS new WebKitCSSMatrix(null) threw exception SyntaxError (DOM Exception 12): The string did not match the expected pattern..
PASS XMLHttpRequest.prototype.toString.call(new XMLHttpRequest) is '[object XMLHttpRequest]'
PASS XSLTProcessor.prototype.toString.call(new XSLTProcessor) is '[object XSLTProcessor]'
diff --git a/LayoutTests/fast/dom/Window/custom-constructors.html b/LayoutTests/fast/dom/Window/custom-constructors.html
index 5535c58..85748f3 100644
--- a/LayoutTests/fast/dom/Window/custom-constructors.html
+++ b/LayoutTests/fast/dom/Window/custom-constructors.html
@@ -15,9 +15,9 @@
shouldBe("Image.prototype.toString.call(new Image)", "'[object HTMLImageElement]'");
shouldBe("Option.prototype.toString.call(new Option)", "'[object HTMLOptionElement]'");
shouldBe("WebKitPoint.prototype.toString.call(new WebKitPoint)", "'[object WebKitPoint]'");
- shouldBe("WebKitCSSMatrix.prototype.toString.call(new WebKitCSSMatrix)", "'matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)'");
- shouldBe("WebKitCSSMatrix.prototype.toString.call(new WebKitCSSMatrix())", "'matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)'");
- shouldBe("WebKitCSSMatrix.prototype.toString.call(new WebKitCSSMatrix(undefined))", "'matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)'");
+ shouldBe("WebKitCSSMatrix.prototype.toString.call(new WebKitCSSMatrix)", "'matrix(1, 0, 0, 1, 0, 0)'");
+ shouldBe("WebKitCSSMatrix.prototype.toString.call(new WebKitCSSMatrix())", "'matrix(1, 0, 0, 1, 0, 0)'");
+ shouldBe("WebKitCSSMatrix.prototype.toString.call(new WebKitCSSMatrix(undefined))", "'matrix(1, 0, 0, 1, 0, 0)'");
shouldThrow("new WebKitCSSMatrix(null)");
shouldBe("XMLHttpRequest.prototype.toString.call(new XMLHttpRequest)", "'[object XMLHttpRequest]'");
shouldBe("XSLTProcessor.prototype.toString.call(new XSLTProcessor)", "'[object XSLTProcessor]'");
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index e0be59a..9c035cb 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,30 @@
+2017-05-15 Chris Dumez <cdumez@apple.com>
+
+ Align WebKitCSSMatrix stringifier with spec for DOMMatrix
+ https://bugs.webkit.org/show_bug.cgi?id=172114
+
+ Reviewed by Simon Fraser.
+
+ Align WebKitCSSMatrix stringifier with spec for DOMMatrix after:
+ - https://github.com/w3c/fxtf-drafts/pull/148
+
+ The following changes were made:
+ - Use EcmaScript's ToString() to convert floating point values to string
+ - Throw an invalid state error if the matrix contains non-finite values
+ - Made WebKitCSSMatrix.toString enumerable as per [1].
+
+ [1] https://heycam.github.io/webidl/#es-stringifier
+
+ Test: fast/css/matrix-stringifier.html
+
+ * css/WebKitCSSMatrix.cpp:
+ (WebCore::WebKitCSSMatrix::toString):
+ * css/WebKitCSSMatrix.h:
+ * css/WebKitCSSMatrix.idl:
+ * platform/graphics/transforms/TransformationMatrix.cpp:
+ (WebCore::TransformationMatrix::containsOnlyFiniteValues):
+ * platform/graphics/transforms/TransformationMatrix.h:
+
2017-05-15 Mark Lam <mark.lam@apple.com>
WorkerRunLoop::Task::performTask() should check !scriptController->isTerminatingExecution().
diff --git a/Source/WebCore/css/WebKitCSSMatrix.cpp b/Source/WebCore/css/WebKitCSSMatrix.cpp
index 1cb7666..f8e6496 100644
--- a/Source/WebCore/css/WebKitCSSMatrix.cpp
+++ b/Source/WebCore/css/WebKitCSSMatrix.cpp
@@ -35,6 +35,7 @@
#include "StyleProperties.h"
#include "TransformFunctions.h"
#include <wtf/MathExtras.h>
+#include <wtf/text/StringBuilder.h>
namespace WebCore {
@@ -197,16 +198,61 @@
return matrix;
}
-String WebKitCSSMatrix::toString() const
+ExceptionOr<String> WebKitCSSMatrix::toString() const
{
- // FIXME - Need to ensure valid CSS floating point values (https://bugs.webkit.org/show_bug.cgi?id=20674)
- if (m_matrix.isAffine())
- return String::format("matrix(%f, %f, %f, %f, %f, %f)", m_matrix.a(), m_matrix.b(), m_matrix.c(), m_matrix.d(), m_matrix.e(), m_matrix.f());
- return String::format("matrix3d(%f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f)",
- 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());
+ if (!m_matrix.containsOnlyFiniteValues())
+ return Exception { INVALID_STATE_ERR, ASCIILiteral("Matrix contains non-finite values") };
+
+ StringBuilder builder;
+ if (m_matrix.isAffine()) {
+ builder.appendLiteral("matrix(");
+ builder.append(String::numberToStringECMAScript(m_matrix.a()));
+ builder.appendLiteral(", ");
+ builder.append(String::numberToStringECMAScript(m_matrix.b()));
+ builder.appendLiteral(", ");
+ builder.append(String::numberToStringECMAScript(m_matrix.c()));
+ builder.appendLiteral(", ");
+ builder.append(String::numberToStringECMAScript(m_matrix.d()));
+ builder.appendLiteral(", ");
+ builder.append(String::numberToStringECMAScript(m_matrix.e()));
+ builder.appendLiteral(", ");
+ builder.append(String::numberToStringECMAScript(m_matrix.f()));
+ } else {
+ builder.appendLiteral("matrix3d(");
+ builder.append(String::numberToStringECMAScript(m_matrix.m11()));
+ builder.appendLiteral(", ");
+ builder.append(String::numberToStringECMAScript(m_matrix.m12()));
+ builder.appendLiteral(", ");
+ builder.append(String::numberToStringECMAScript(m_matrix.m13()));
+ builder.appendLiteral(", ");
+ builder.append(String::numberToStringECMAScript(m_matrix.m14()));
+ builder.appendLiteral(", ");
+ builder.append(String::numberToStringECMAScript(m_matrix.m21()));
+ builder.appendLiteral(", ");
+ builder.append(String::numberToStringECMAScript(m_matrix.m22()));
+ builder.appendLiteral(", ");
+ builder.append(String::numberToStringECMAScript(m_matrix.m23()));
+ builder.appendLiteral(", ");
+ builder.append(String::numberToStringECMAScript(m_matrix.m24()));
+ builder.appendLiteral(", ");
+ builder.append(String::numberToStringECMAScript(m_matrix.m31()));
+ builder.appendLiteral(", ");
+ builder.append(String::numberToStringECMAScript(m_matrix.m32()));
+ builder.appendLiteral(", ");
+ builder.append(String::numberToStringECMAScript(m_matrix.m33()));
+ builder.appendLiteral(", ");
+ builder.append(String::numberToStringECMAScript(m_matrix.m34()));
+ builder.appendLiteral(", ");
+ builder.append(String::numberToStringECMAScript(m_matrix.m41()));
+ builder.appendLiteral(", ");
+ builder.append(String::numberToStringECMAScript(m_matrix.m42()));
+ builder.appendLiteral(", ");
+ builder.append(String::numberToStringECMAScript(m_matrix.m43()));
+ builder.appendLiteral(", ");
+ builder.append(String::numberToStringECMAScript(m_matrix.m44()));
+ }
+ builder.append(')');
+ return builder.toString();
}
} // namespace WebCore
diff --git a/Source/WebCore/css/WebKitCSSMatrix.h b/Source/WebCore/css/WebKitCSSMatrix.h
index 84c0279..bf3c0e3 100644
--- a/Source/WebCore/css/WebKitCSSMatrix.h
+++ b/Source/WebCore/css/WebKitCSSMatrix.h
@@ -137,7 +137,7 @@
const TransformationMatrix& transform() const { return m_matrix; }
- String toString() const;
+ ExceptionOr<String> toString() const;
private:
WebKitCSSMatrix() = default;
diff --git a/Source/WebCore/css/WebKitCSSMatrix.idl b/Source/WebCore/css/WebKitCSSMatrix.idl
index 5333776..15f1f32 100644
--- a/Source/WebCore/css/WebKitCSSMatrix.idl
+++ b/Source/WebCore/css/WebKitCSSMatrix.idl
@@ -91,5 +91,5 @@
// Passing a NaN will use a value of 0.
WebKitCSSMatrix skewY(optional unrestricted double angle = NaN);
- [NotEnumerable] DOMString toString();
+ [MayThrowException] DOMString toString(); // FIXME: Should be stringifier; once we support it.
};
diff --git a/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp b/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp
index 2427b01..7a783aa 100644
--- a/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp
+++ b/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp
@@ -33,6 +33,7 @@
#include "IntRect.h"
#include "LayoutRect.h"
#include "TextStream.h"
+#include <cmath>
#include <wtf/Assertions.h>
#include <wtf/MathExtras.h>
@@ -1693,6 +1694,14 @@
return true;
}
+bool TransformationMatrix::containsOnlyFiniteValues() const
+{
+ return std::isfinite(m_matrix[0][0]) && std::isfinite(m_matrix[0][1]) && std::isfinite(m_matrix[0][2]) && std::isfinite(m_matrix[0][3])
+ && std::isfinite(m_matrix[1][0]) && std::isfinite(m_matrix[1][1]) && std::isfinite(m_matrix[1][2]) && std::isfinite(m_matrix[1][3])
+ && std::isfinite(m_matrix[2][0]) && std::isfinite(m_matrix[2][1]) && std::isfinite(m_matrix[2][2]) && std::isfinite(m_matrix[2][3])
+ && std::isfinite(m_matrix[3][0]) && std::isfinite(m_matrix[3][1]) && std::isfinite(m_matrix[3][2]) && std::isfinite(m_matrix[3][3]);
+}
+
TransformationMatrix TransformationMatrix::to2dTransform() const
{
return TransformationMatrix(m_matrix[0][0], m_matrix[0][1], 0, m_matrix[0][3],
diff --git a/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h b/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h
index 5db0c00..56f225a 100644
--- a/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h
+++ b/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h
@@ -380,6 +380,8 @@
bool isIntegerTranslation() const;
+ bool containsOnlyFiniteValues() const;
+
// Returns the matrix without 3D components.
TransformationMatrix to2dTransform() const;