LibWeb/Geometry: Implement "other than none" keyword check

This commit is contained in:
tanner.drake 2024-12-26 16:32:16 -05:00 committed by Jelle Raaijmakers
parent 5ba847b1c4
commit fe25f77bcf
Notes: github-actions[bot] 2024-12-28 06:52:15 +00:00
4 changed files with 431 additions and 1 deletions

View file

@ -10,6 +10,7 @@
#include <LibWeb/Bindings/DOMMatrixReadOnlyPrototype.h>
#include <LibWeb/CSS/ComputedProperties.h>
#include <LibWeb/CSS/Parser/Parser.h>
#include <LibWeb/CSS/StyleValues/CSSKeywordValue.h>
#include <LibWeb/CSS/StyleValues/ShorthandStyleValue.h>
#include <LibWeb/Geometry/DOMMatrix.h>
#include <LibWeb/Geometry/DOMMatrixReadOnly.h>
@ -947,7 +948,7 @@ WebIDL::ExceptionOr<ParsedMatrix> parse_dom_matrix_init_string(JS::Realm& realm,
// The result will be a <transform-list>, the keyword none, or failure.
// If parsedValue is failure, or any <transform-function> has <length> values without absolute length units, or any keyword other than none is used, then return failure. [CSS3-SYNTAX] [CSS3-TRANSFORMS]
auto transform_style_value = parse_css_value(CSS::Parser::ParsingContext {}, transform_list, CSS::PropertyID::Transform);
if (!transform_style_value)
if (!transform_style_value || (transform_style_value->is_keyword() && transform_style_value->to_keyword() != CSS::Keyword::None))
return WebIDL::SyntaxError::create(realm, "Failed to parse CSS transform string."_string);
auto parsed_value = CSS::ComputedProperties::transformations_for_style_value(*transform_style_value);

View file

@ -0,0 +1,132 @@
Harness status: OK
Found 126 tests
122 Pass
4 Fail
Pass new DOMMatrix()
Pass new DOMMatrix(undefined)
Pass new DOMMatrix(new DOMMatrix())
Pass new DOMMatrix("none")
Pass new DOMMatrix(" none")
Pass new DOMMatrix("none ")
Pass new DOMMatrix("NONE")
Pass new DOMMatrix("none/**/")
Pass new DOMMatrix("/**/none")
Pass new DOMMatrix("")
Pass new DOMMatrix(float32Array) 16 elements
Pass new DOMMatrix(float32Array) 6 elements
Pass new DOMMatrix(float64Array) 16 elements
Pass new DOMMatrix((float64Array) 6 elements
Pass new DOMMatrix(sequence) 16 elements
Pass new DOMMatrix(sequence) 6 elements
Pass new DOMMatrix("scale(2) translateX(5px) translateY(5px)")
Pass new DOMMatrix("scale(2, 2) translateX(5px) translateY(5px)")
Pass new DOMMatrix("scale(2)translateX(5px)translateY(5px)")
Fail new DOMMatrix("scale(2) translateX(calc(2 * 2.5px)) translateY(5px)")
Pass new DOMMatrix("scale(2) translateX(5px) translateY(5px) rotate(5deg) rotate(-5deg)")
Pass new DOMMatrix("translateX (5px)")
Pass new DOMMatrix("scale(2 2) translateX(5) translateY(5)")
Pass new DOMMatrix("scale(2, 2), translateX(5) ,translateY(5)")
Pass new DOMMatrix("translateX(5em)")
Pass new DOMMatrix("translateX(5ex)")
Pass new DOMMatrix("translateX(5ch)")
Pass new DOMMatrix("translateX(5rem)")
Pass new DOMMatrix("translateX(5cqw)")
Pass new DOMMatrix("translateX(5cqh)")
Pass new DOMMatrix("translateX(5cqb)")
Pass new DOMMatrix("translateX(5cqi)")
Pass new DOMMatrix("translateX(5cqmin)")
Pass new DOMMatrix("translateX(5cqmax)")
Pass new DOMMatrix("translateX(5vw)")
Pass new DOMMatrix("translateX(5vh)")
Pass new DOMMatrix("translateX(5vb)")
Pass new DOMMatrix("translateX(5vi)")
Pass new DOMMatrix("translateX(5vmin)")
Pass new DOMMatrix("translateX(5vmax)")
Pass new DOMMatrix("translateX(5%)")
Pass new DOMMatrix("rotate(5)")
Pass new DOMMatrix("rotate(5, 5, 5)")
Pass new DOMMatrix("rotate(5, 5px, 5px)")
Pass new DOMMatrix("rotate(5deg, 5px, 5px)")
Pass new DOMMatrix(" ")
Pass new DOMMatrix("/**/")
Pass new DOMMatrix("\0")
Pass new DOMMatrix(";")
Fail new DOMMatrix("none;")
Pass new DOMMatrix("null")
Pass new DOMMatrix(null)
Pass new DOMMatrix("undefined")
Pass new DOMMatrix("inherit")
Pass new DOMMatrix("initial")
Pass new DOMMatrix("unset")
Pass new DOMMatrix(sequence)
Pass new DOMMatrix(matrix)
Pass new DOMMatrix("scale(2, 2), translateX(5px) translateY(5px)")
Pass new DOMMatrix(sequence) 17 elements
Pass new DOMMatrix(sequence) 15 elements
Pass new DOMMatrix(sequence) 5 elements
Pass new DOMMatrix(sequence) 0 elements
Pass new DOMMatrixReadOnly()
Pass new DOMMatrixReadOnly(undefined)
Pass new DOMMatrixReadOnly(new DOMMatrixReadOnly())
Pass new DOMMatrixReadOnly("none")
Pass new DOMMatrixReadOnly(" none")
Pass new DOMMatrixReadOnly("none ")
Pass new DOMMatrixReadOnly("NONE")
Pass new DOMMatrixReadOnly("none/**/")
Pass new DOMMatrixReadOnly("/**/none")
Pass new DOMMatrixReadOnly("")
Pass new DOMMatrixReadOnly(float32Array) 16 elements
Pass new DOMMatrixReadOnly(float32Array) 6 elements
Pass new DOMMatrixReadOnly(float64Array) 16 elements
Pass new DOMMatrixReadOnly((float64Array) 6 elements
Pass new DOMMatrixReadOnly(sequence) 16 elements
Pass new DOMMatrixReadOnly(sequence) 6 elements
Pass new DOMMatrixReadOnly("scale(2) translateX(5px) translateY(5px)")
Pass new DOMMatrixReadOnly("scale(2, 2) translateX(5px) translateY(5px)")
Pass new DOMMatrixReadOnly("scale(2)translateX(5px)translateY(5px)")
Fail new DOMMatrixReadOnly("scale(2) translateX(calc(2 * 2.5px)) translateY(5px)")
Pass new DOMMatrixReadOnly("scale(2) translateX(5px) translateY(5px) rotate(5deg) rotate(-5deg)")
Pass new DOMMatrixReadOnly("translateX (5px)")
Pass new DOMMatrixReadOnly("scale(2 2) translateX(5) translateY(5)")
Pass new DOMMatrixReadOnly("scale(2, 2), translateX(5) ,translateY(5)")
Pass new DOMMatrixReadOnly("translateX(5em)")
Pass new DOMMatrixReadOnly("translateX(5ex)")
Pass new DOMMatrixReadOnly("translateX(5ch)")
Pass new DOMMatrixReadOnly("translateX(5rem)")
Pass new DOMMatrixReadOnly("translateX(5cqw)")
Pass new DOMMatrixReadOnly("translateX(5cqh)")
Pass new DOMMatrixReadOnly("translateX(5cqb)")
Pass new DOMMatrixReadOnly("translateX(5cqi)")
Pass new DOMMatrixReadOnly("translateX(5cqmin)")
Pass new DOMMatrixReadOnly("translateX(5cqmax)")
Pass new DOMMatrixReadOnly("translateX(5vw)")
Pass new DOMMatrixReadOnly("translateX(5vh)")
Pass new DOMMatrixReadOnly("translateX(5vb)")
Pass new DOMMatrixReadOnly("translateX(5vi)")
Pass new DOMMatrixReadOnly("translateX(5vmin)")
Pass new DOMMatrixReadOnly("translateX(5vmax)")
Pass new DOMMatrixReadOnly("translateX(5%)")
Pass new DOMMatrixReadOnly("rotate(5)")
Pass new DOMMatrixReadOnly("rotate(5, 5, 5)")
Pass new DOMMatrixReadOnly("rotate(5, 5px, 5px)")
Pass new DOMMatrixReadOnly("rotate(5deg, 5px, 5px)")
Pass new DOMMatrixReadOnly(" ")
Pass new DOMMatrixReadOnly("/**/")
Pass new DOMMatrixReadOnly("\0")
Pass new DOMMatrixReadOnly(";")
Fail new DOMMatrixReadOnly("none;")
Pass new DOMMatrixReadOnly("null")
Pass new DOMMatrixReadOnly(null)
Pass new DOMMatrixReadOnly("undefined")
Pass new DOMMatrixReadOnly("inherit")
Pass new DOMMatrixReadOnly("initial")
Pass new DOMMatrixReadOnly("unset")
Pass new DOMMatrixReadOnly(sequence)
Pass new DOMMatrixReadOnly(matrix)
Pass new DOMMatrixReadOnly("scale(2, 2), translateX(5px) translateY(5px)")
Pass new DOMMatrixReadOnly(sequence) 17 elements
Pass new DOMMatrixReadOnly(sequence) 15 elements
Pass new DOMMatrixReadOnly(sequence) 5 elements
Pass new DOMMatrixReadOnly(sequence) 0 elements

View file

@ -0,0 +1,212 @@
<!DOCTYPE html>
<html>
<head>
<title>Geometry Interfaces: DOMMatrix and DOMMatrixReadOnly constructors</title>
<link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com" />
<link rel="help" href="https://drafts.fxtf.org/geometry/#DOMMatrix">
<link rel="help" href="https://drafts.fxtf.org/geometry/#dommatrix-constructors">
<link rel="help" href="https://drafts.fxtf.org/geometry/#dom-dommatrix-dommatrix">
<script src="support/dommatrix-test-util.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
var initial = {
m11: 1, m21: 0, m31: 0, m41: 0,
m12: 0, m22: 1, m32: 0, m42: 0,
m13: 0, m23: 0, m33: 1, m43: 0,
m14: 0, m24: 0, m34: 0, m44: 1,
is2D: true,
isIdentity: true
};
var scaleTranslate2D = {
m11: 2, m21: 0, m31: 0, m41: 10,
m12: 0, m22: 2, m32: 0, m42: 10,
m13: 0, m23: 0, m33: 1, m43: 0,
m14: 0, m24: 0, m34: 0, m44: 1,
is2D: true,
isIdentity: false
};
["DOMMatrix", "DOMMatrixReadOnly"].forEach(function(constr) {
test(function() {
checkDOMMatrix(new self[constr](), initial);
}, `new ${constr}()`);
test(function() {
checkDOMMatrix(new self[constr](undefined), initial);
}, `new ${constr}(undefined)`);
test(function() {
checkDOMMatrix(new self[constr](new self[constr]()), initial);
}, `new ${constr}(new ${constr}())`);
['none',
' none',
'none ',
'NONE',
'none/**/',
'/**/none',
'',
].forEach(function(string) {
test(function() {
checkDOMMatrix(new self[constr](string), initial);
}, `new ${constr}(${format_value(string)})`);
});
test(function() {
var float32Array = new Float32Array([
2.0, 0.0, 0.0, 0.0,
0.0, 2.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
10.0, 10.0, 0.0, 1.0]);
checkDOMMatrix(new self[constr](float32Array), scaleTranslate2D, false);
}, `new ${constr}(float32Array) 16 elements`);
test(function() {
var float32Array = new Float32Array([2.0, 0.0, 0.0, 2.0, 10.0, 10.0]);
checkDOMMatrix(new self[constr](float32Array), scaleTranslate2D);
}, `new ${constr}(float32Array) 6 elements`);
test(function() {
var float64Array = new Float64Array([
2.0, 0.0, 0.0, 0.0,
0.0, 2.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
10.0, 10.0, 0.0, 1.0]);
checkDOMMatrix(new self[constr](float64Array), scaleTranslate2D, false);
}, `new ${constr}(float64Array) 16 elements`);
test(function() {
var float64Array = new Float64Array([2.0, 0.0, 0.0, 2.0, 10.0, 10.0]);
checkDOMMatrix(new self[constr](float64Array), scaleTranslate2D);
}, `new ${constr}((float64Array) 6 elements`);
[
[2.0, 0.0, 0.0, 0.0,
0.0, 2.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
10.0, 10.0, 0.0, 1.0],
[2.0, 0.0, 0.0, 2.0, 10.0, 10.0],
].forEach(function(sequence) {
test(function() {
checkDOMMatrix(new self[constr](sequence), scaleTranslate2D,
sequence.length == 6);
}, `new ${constr}(sequence) ${sequence.length} elements`);
});
{
const epsilon = 0.0000000005;
['scale(2) translateX(5px) translateY(5px)',
'scale(2, 2) translateX(5px) translateY(5px)',
'scale(2)translateX(5px)translateY(5px)',
'scale(2) translateX(calc(2 * 2.5px)) translateY(5px)',
'scale(2) translateX(5px) translateY(5px) rotate(5deg) rotate(-5deg)',
].forEach(function(string) {
test(function() {
checkMatrix(new self[constr](string), scaleTranslate2D, { epsilon });
}, `new ${constr}(${format_value(string)})`);
});
}
['translateX (5px)',
'scale(2 2) translateX(5) translateY(5)',
'scale(2, 2), translateX(5) ,translateY(5)',
'translateX(5em)',
'translateX(5ex)',
'translateX(5ch)',
'translateX(5rem)',
'translateX(5cqw)',
'translateX(5cqh)',
'translateX(5cqb)',
'translateX(5cqi)',
'translateX(5cqmin)',
'translateX(5cqmax)',
'translateX(5vw)',
'translateX(5vh)',
'translateX(5vb)',
'translateX(5vi)',
'translateX(5vmin)',
'translateX(5vmax)',
'translateX(5%)',
'rotate(5)',
'rotate(5, 5, 5)',
'rotate(5, 5px, 5px)',
'rotate(5deg, 5px, 5px)',
' ',
'/**/',
'\0',
';',
'none;',
'null',
null, // is converted to 'null' by IDL
'undefined',
'inherit',
'initial',
'unset',
].forEach(function(string) {
test(function() {
assert_throws_dom('SyntaxError', function() { new self[constr](string); });
}, `new ${constr}(${format_value(string)})`);
});
test(function() {
var sequence = [
2.0, 1.0, 0.0, 0.0,
1.0, 2.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
10.0, 10.0, 0.0, 1.0];
checkDOMMatrix(new self[constr](sequence), {
m11: 2, m21: 1, m31: 0, m41: 10,
m12: 1, m22: 2, m32: 0, m42: 10,
m13: 0, m23: 0, m33: 1, m43: 0,
m14: 0, m24: 0, m34: 0, m44: 1,
is2D: false,
isIdentity: false
});
}, `new ${constr}(sequence)`);
test(function() {
var matrix = new self[constr]([
2.0, 1.0, 0.0, 0.0,
1.0, 2.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
10.0, 10.0, 0.0, 1.0]);
checkDOMMatrix(new self[constr](matrix), {
m11: 2, m21: 1, m31: 0, m41: 10,
m12: 1, m22: 2, m32: 0, m42: 10,
m13: 0, m23: 0, m33: 1, m43: 0,
m14: 0, m24: 0, m34: 0, m44: 1,
is2D: false,
isIdentity: false
});
}, `new ${constr}(matrix)`);
['scale(2, 2), translateX(5px) translateY(5px)',
].forEach(function(string) {
test(function() {
assert_throws_dom("SyntaxError", function() { new self[constr](string); });
}, `new ${constr}(${format_value(string)})`);
});
[
[2.0, 0.0, 0.0, 0.0,
0.0, 2.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
10.0, 10.0, 0.0, 2.0, 0.0], // 17 elements
[2.0, 0.0, 0.0, 0.0,
0.0, 2.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
10.0, 10.0, 0.0], // 15 elements
[2.0, 0.0, 0.0, 2.0, 10.0], // 5 elements
[], // 0 elements
].forEach(function(sequence) {
test(function() {
assert_throws_js(TypeError, function() { new self[constr](sequence); });
}, `new ${constr}(sequence) ${sequence.length} elements`);
});
});
</script>
</body>
</html>

View file

@ -0,0 +1,85 @@
// This formats dict as a string suitable as test name.
// format_value() is provided by testharness.js,
// which also preserves sign for -0.
function format_dict(dict) {
const props = [];
for (let prop in dict) {
props.push(`${prop}: ${format_value(dict[prop])}`);
}
return `{${props.join(', ')}}`;
}
// Create a normal JS object with the expected properties
// from a dict with only m11..m44 specified (not a..f).
function matrix3D(dict) {
const matrix = {m11: 1, m12: 0, m13: 0, m14: 0,
m21: 0, m22: 1, m23: 0, m24: 0,
m31: 0, m32: 0, m33: 1, m34: 0,
m41: 0, m42: 0, m43: 0, m44: 1}
matrix.is2D = false;
for (let member in dict) {
matrix[member] = dict[member];
}
matrix.a = matrix.m11;
matrix.b = matrix.m12;
matrix.c = matrix.m21;
matrix.d = matrix.m22;
matrix.e = matrix.m41;
matrix.f = matrix.m42;
return matrix;
}
function matrix2D(dict) {
const matrix = matrix3D(dict);
matrix.is2D = true;
return matrix;
}
function checkMatrix(actual, expected, { epsilon = Number.MIN_VALUE } = {}) {
for (let member in expected) {
if (epsilon && typeof expected[member] === "number") {
assert_approx_equals(actual[member], expected[member], epsilon, member);
} else {
assert_equals(actual[member], expected[member], member);
}
}
}
// checkMatrix and checkDOMMatrix should probably be merged...
function checkDOMMatrix(m, exp, is2D) {
if (is2D === undefined) {
is2D = exp.is2D;
}
assert_equals(m.m11, exp.m11, "Expected value for m11 is " + exp.m11);
assert_equals(m.m12, exp.m12, "Expected value for m12 is " + exp.m12);
assert_equals(m.m13, exp.m13, "Expected value for m13 is " + exp.m13);
assert_equals(m.m14, exp.m14, "Expected value for m14 is " + exp.m14);
assert_equals(m.m21, exp.m21, "Expected value for m21 is " + exp.m21);
assert_equals(m.m22, exp.m22, "Expected value for m22 is " + exp.m22);
assert_equals(m.m23, exp.m23, "Expected value for m23 is " + exp.m23);
assert_equals(m.m24, exp.m24, "Expected value for m24 is " + exp.m24);
assert_equals(m.m31, exp.m31, "Expected value for m31 is " + exp.m31);
assert_equals(m.m32, exp.m32, "Expected value for m32 is " + exp.m32);
assert_equals(m.m33, exp.m33, "Expected value for m33 is " + exp.m33);
assert_equals(m.m34, exp.m34, "Expected value for m34 is " + exp.m34);
assert_equals(m.m41, exp.m41, "Expected value for m41 is " + exp.m41);
assert_equals(m.m42, exp.m42, "Expected value for m42 is " + exp.m42);
assert_equals(m.m43, exp.m43, "Expected value for m43 is " + exp.m43);
assert_equals(m.m44, exp.m44, "Expected value for m44 is " + exp.m44);
assert_equals(m.is2D, is2D, "Expected value for is2D is " + is2D);
assert_equals(m.isIdentity, exp.isIdentity, "Expected value for isIdentity is " + exp.isIdentity);
}
function identity() {
return new DOMMatrix(
[1, 0, 0, 0,
0, 1, 0 ,0,
0, 0, 1, 0,
0, 0, 0, 1]);
}
function update(matrix, f) {
f(matrix);
return matrix;
}