mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-28 13:18:19 +00:00
LibWeb: Skip inverted non-canonical values when simplifying product node
This matches the logic with the non-inverted children. Gains us 2 WPT tests.
This commit is contained in:
parent
cd1cf75f7b
commit
c3b1013018
Notes:
github-actions[bot]
2025-08-06 13:56:43 +00:00
Author: https://github.com/Calme1709
Commit: c3b1013018
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5716
Reviewed-by: https://github.com/AtkinsSJ ✅
17 changed files with 387 additions and 44 deletions
|
@ -3304,32 +3304,39 @@ NonnullRefPtr<CalculationNode const> simplify_a_calculation_tree(CalculationNode
|
||||||
// its child’s value), expressed in the result’s canonical unit.
|
// its child’s value), expressed in the result’s canonical unit.
|
||||||
Optional<CalculatedStyleValue::CalculationResult> accumulated_result;
|
Optional<CalculatedStyleValue::CalculationResult> accumulated_result;
|
||||||
bool is_valid = true;
|
bool is_valid = true;
|
||||||
|
|
||||||
|
auto accumulate = [&accumulated_result, &resolution_context, &context](NumericCalculationNode const& numeric_child, bool invert) {
|
||||||
|
auto child_type = numeric_child.numeric_type();
|
||||||
|
|
||||||
|
if (!child_type.has_value())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// FIXME: The spec doesn't handle unresolved percentages here, but if we don't exit when we see one,
|
||||||
|
// we'll get a wrongly-typed value after multiplying the types.
|
||||||
|
// Same goes for other numerics with non-canonical units.
|
||||||
|
// Spec bug: https://github.com/w3c/csswg-drafts/issues/11588
|
||||||
|
if ((numeric_child.value().has<Percentage>() && context.percentages_resolve_as.has_value()) || !numeric_child.is_in_canonical_unit())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto child_value = CalculatedStyleValue::CalculationResult::from_value(numeric_child.value(), resolution_context, child_type);
|
||||||
|
|
||||||
|
if (invert)
|
||||||
|
child_value.invert();
|
||||||
|
|
||||||
|
if (accumulated_result.has_value())
|
||||||
|
accumulated_result->multiply_by(child_value);
|
||||||
|
else
|
||||||
|
accumulated_result = child_value;
|
||||||
|
|
||||||
|
if (!accumulated_result->type().has_value())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
for (auto const& child : children) {
|
for (auto const& child : children) {
|
||||||
if (child->type() == CalculationNode::Type::Numeric) {
|
if (child->type() == CalculationNode::Type::Numeric) {
|
||||||
auto const& numeric_child = as<NumericCalculationNode>(*child);
|
if (!accumulate(as<NumericCalculationNode>(*child), false)) {
|
||||||
auto child_type = numeric_child.numeric_type();
|
|
||||||
if (!child_type.has_value()) {
|
|
||||||
is_valid = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: The spec doesn't handle unresolved percentages here, but if we don't exit when we see one,
|
|
||||||
// we'll get a wrongly-typed value after multiplying the types.
|
|
||||||
// Same goes for other numerics with non-canonical units.
|
|
||||||
// Spec bug: https://github.com/w3c/csswg-drafts/issues/11588
|
|
||||||
if ((numeric_child.value().has<Percentage>() && context.percentages_resolve_as.has_value())
|
|
||||||
|| !numeric_child.is_in_canonical_unit()) {
|
|
||||||
is_valid = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto child_value = CalculatedStyleValue::CalculationResult::from_value(numeric_child.value(), resolution_context, child_type);
|
|
||||||
if (accumulated_result.has_value()) {
|
|
||||||
accumulated_result->multiply_by(child_value);
|
|
||||||
} else {
|
|
||||||
accumulated_result = move(child_value);
|
|
||||||
}
|
|
||||||
if (!accumulated_result->type().has_value()) {
|
|
||||||
is_valid = false;
|
is_valid = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3337,26 +3344,7 @@ NonnullRefPtr<CalculationNode const> simplify_a_calculation_tree(CalculationNode
|
||||||
}
|
}
|
||||||
if (child->type() == CalculationNode::Type::Invert) {
|
if (child->type() == CalculationNode::Type::Invert) {
|
||||||
auto const& invert_child = as<InvertCalculationNode>(*child);
|
auto const& invert_child = as<InvertCalculationNode>(*child);
|
||||||
if (invert_child.child().type() != CalculationNode::Type::Numeric) {
|
if (invert_child.child().type() != CalculationNode::Type::Numeric || !accumulate(as<NumericCalculationNode>(invert_child.child()), true)) {
|
||||||
is_valid = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
auto const& grandchild = as<NumericCalculationNode>(invert_child.child());
|
|
||||||
|
|
||||||
auto child_type = child->numeric_type();
|
|
||||||
if (!child_type.has_value()) {
|
|
||||||
is_valid = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto child_value = CalculatedStyleValue::CalculationResult::from_value(grandchild.value(), resolution_context, grandchild.numeric_type());
|
|
||||||
child_value.invert();
|
|
||||||
if (accumulated_result.has_value()) {
|
|
||||||
accumulated_result->multiply_by(child_value);
|
|
||||||
} else {
|
|
||||||
accumulated_result = move(child_value);
|
|
||||||
}
|
|
||||||
if (!accumulated_result->type().has_value()) {
|
|
||||||
is_valid = false;
|
is_valid = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Found 12 tests
|
||||||
|
|
||||||
|
2 Pass
|
||||||
|
10 Fail
|
||||||
|
Pass box should be orange if the calc between px-em in @media was correct
|
||||||
|
Fail box should be orange if the calc between vh+em in @media was correct
|
||||||
|
Fail box should be orange if the calc between vw-em in @media was correct
|
||||||
|
Fail box should be orange if the calc between vw+vh in @media was correct
|
||||||
|
Fail box should be orange if the calc between vh+px in @media was correct
|
||||||
|
Fail box should be orange if the calc between vw+px in @media was correct
|
||||||
|
Pass box should be orange if the calc between px/em*em in @media was correct
|
||||||
|
Fail box should be orange if the calc between vh*em in @media was correct
|
||||||
|
Fail box should be orange if the calc between vh*vw/em*px/vh in @media was correct
|
||||||
|
Fail box should be orange if the calc between vw/px*vh in @media was correct
|
||||||
|
Fail box should be orange if the calc between vh*vw/em*px in @media was correct
|
||||||
|
Fail box should be orange if the calc between vw*vh*px*em/px/px/px in @media was correct
|
|
@ -0,0 +1,13 @@
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Found 7 tests
|
||||||
|
|
||||||
|
5 Pass
|
||||||
|
2 Fail
|
||||||
|
Fail testing width: calc(5px * 10lh / 1px)
|
||||||
|
Pass testing width: calc(20% * 0.5em / 1px)
|
||||||
|
Pass testing width: calc(4px * 4em / 1px)
|
||||||
|
Fail testing width: calc(400px / 4lh * 1px)
|
||||||
|
Pass testing width: calc(20% / 0.5em * 1px)
|
||||||
|
Pass testing width: calc(52px * 1px / 10%)
|
||||||
|
Pass testing width: calc(100px * 1px / 1px / 1)
|
|
@ -0,0 +1,35 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>test calc with mixed units in media queries</title>
|
||||||
|
<script src="../../resources/testharness.js"></script>
|
||||||
|
<script src="../../resources/testharnessreport.js"></script>
|
||||||
|
<link rel="help" href="https://www.w3.org/TR/css3-values/#calc-computed-value">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<iframe src="./support/mixed-units-01.html" title="px-em" frameborder="0" height="10" width="100"></iframe>
|
||||||
|
<iframe src="./support/mixed-units-02.html" title="vh+em" frameborder="0" height="10" width="100"></iframe>
|
||||||
|
<iframe src="./support/mixed-units-03.html" title="vw-em" frameborder="0" height="10" width="100"></iframe>
|
||||||
|
<iframe src="./support/mixed-units-04.html" title="vw+vh" frameborder="0" height="10" width="100"></iframe>
|
||||||
|
<iframe src="./support/mixed-units-05.html" title="vh+px" frameborder="0" height="10" width="100"></iframe>
|
||||||
|
<iframe src="./support/mixed-units-06.html" title="vw+px" frameborder="0" height="10" width="100"></iframe>
|
||||||
|
<iframe src="./support/mixed-units-07.html" title="px/em*em" frameborder="0" height="10" width="100"></iframe>
|
||||||
|
<iframe src="./support/mixed-units-08.html" title="vh*em" frameborder="0" height="10" width="100"></iframe>
|
||||||
|
<iframe src="./support/mixed-units-09.html" title="vh*vw/em*px/vh" frameborder="0" height="10" width="100"></iframe>
|
||||||
|
<iframe src="./support/mixed-units-10.html" title="vw/px*vh" frameborder="0" height="10" width="100"></iframe>
|
||||||
|
<iframe src="./support/mixed-units-11.html" title="vh*vw/em*px" frameborder="0" height="10" width="100"></iframe>
|
||||||
|
<iframe src="./support/mixed-units-12.html" title="vw*vh*px*em/px/px/px" frameborder="0" height="10" width="100"></iframe>
|
||||||
|
<script>
|
||||||
|
for (const frame of document.querySelectorAll("iframe")) {
|
||||||
|
async_test((t) => {
|
||||||
|
frame.addEventListener("load", t.step_func(() => {
|
||||||
|
const body = frame.contentWindow.document.body;
|
||||||
|
const actual = frame.contentWindow.getComputedStyle(body).getPropertyValue("background-color");
|
||||||
|
assert_equals(actual, "rgb(255, 165, 0)");
|
||||||
|
t.done();
|
||||||
|
}));
|
||||||
|
}, `box should be orange if the calc between ${frame.title} in @media was correct`);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,97 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
|
||||||
|
<title>CSS Values Test: computed value of calc() values using multiplication/division with mixed units</title>
|
||||||
|
|
||||||
|
<link rel="help" href="https://www.w3.org/TR/css-values-4/#calc-computed-value">
|
||||||
|
|
||||||
|
<meta name="flags" content="">
|
||||||
|
<meta content="This meta-test checks for the resolution and absolutization of computed values with mixed units to 'px' when multiplication/division is used." name="assert">
|
||||||
|
|
||||||
|
<script src="../../resources/testharness.js"></script>
|
||||||
|
<script src="../../resources/testharnessreport.js"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
html {
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.25; /* computed value: 20px */
|
||||||
|
width: 520px;
|
||||||
|
height: 500px;
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#target {
|
||||||
|
height: 100px;
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div id="target"></div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function startTesting() {
|
||||||
|
var targetElement = document.getElementById("target");
|
||||||
|
|
||||||
|
function verifyComputedStyle(property_name, specified_value, expected_value) {
|
||||||
|
test(function() {
|
||||||
|
targetElement.style.setProperty(property_name, "initial");
|
||||||
|
targetElement.style.setProperty(property_name, specified_value);
|
||||||
|
assert_equals(getComputedStyle(targetElement)[property_name], expected_value);
|
||||||
|
}, `testing ${property_name}: ${specified_value}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
verifyComputedStyle("width", "calc(5px * 10lh / 1px)", "1000px");
|
||||||
|
/*
|
||||||
|
10lh = 200px
|
||||||
|
5px * 200px / 1px = 1000px^2 / 1px = 1000px
|
||||||
|
Total = 1000px
|
||||||
|
*/
|
||||||
|
|
||||||
|
verifyComputedStyle("width", "calc(20% * 0.5em / 1px)", "832px");
|
||||||
|
/*
|
||||||
|
20% of 520px = 104px
|
||||||
|
0.5em = 8px
|
||||||
|
104px * 8px / 1px = 832px^2 / 1px = 832px
|
||||||
|
Total = 832px
|
||||||
|
*/
|
||||||
|
|
||||||
|
verifyComputedStyle("width", "calc(4px * 4em / 1px)", "256px");
|
||||||
|
/*
|
||||||
|
4em = 64px
|
||||||
|
4px * 64px / 1px = 256px^2 / 1px = 256px
|
||||||
|
Total = 256px
|
||||||
|
*/
|
||||||
|
|
||||||
|
verifyComputedStyle("width", "calc(400px / 4lh * 1px)", "5px");
|
||||||
|
/*
|
||||||
|
4lh = 80px
|
||||||
|
400px / 80px * 1px = 5 * 1px = 5px
|
||||||
|
Total = 5px
|
||||||
|
*/
|
||||||
|
|
||||||
|
verifyComputedStyle("width", "calc(20% / 0.5em * 1px)", "13px");
|
||||||
|
/*
|
||||||
|
20% of 520px = 104px
|
||||||
|
0.5em = 8px
|
||||||
|
104px / 8px * 1px = 13 * 1px = 13px
|
||||||
|
Total = 13px
|
||||||
|
*/
|
||||||
|
|
||||||
|
verifyComputedStyle("width", "calc(52px * 1px / 10%)", "1px");
|
||||||
|
/*
|
||||||
|
10% of 520px = 52px
|
||||||
|
52px * 1px / 52px = 1px
|
||||||
|
Total = 1px
|
||||||
|
*/
|
||||||
|
|
||||||
|
verifyComputedStyle("width", "calc(100px * 1px / 1px / 1)", "100px");
|
||||||
|
}
|
||||||
|
|
||||||
|
startTesting();
|
||||||
|
|
||||||
|
</script>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background: rgb(0, 0, 255);
|
||||||
|
}
|
||||||
|
@media (width: calc(116px - 1em)) {
|
||||||
|
body {
|
||||||
|
background: rgb(255, 165, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background: rgb(0, 0, 255);
|
||||||
|
}
|
||||||
|
@media (width: calc(200vh + 5em)) {
|
||||||
|
body {
|
||||||
|
background: rgb(255, 165, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background: rgb(0, 0, 255);
|
||||||
|
}
|
||||||
|
@media (height: calc(100vw - 5.625em)) {
|
||||||
|
body {
|
||||||
|
background: rgb(255, 165, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background: rgb(0, 0, 255);
|
||||||
|
}
|
||||||
|
@media (width: calc(10vw + 900vh)) {
|
||||||
|
body {
|
||||||
|
background: rgb(255, 165, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background: rgb(0, 0, 255);
|
||||||
|
}
|
||||||
|
@media (width: calc(900vh + 10px)) {
|
||||||
|
body {
|
||||||
|
background: rgb(255, 165, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background: rgb(0, 0, 255);
|
||||||
|
}
|
||||||
|
@media (width: calc(90vw + 10px)) {
|
||||||
|
body {
|
||||||
|
background: rgb(255, 165, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background: rgb(0, 0, 255);
|
||||||
|
}
|
||||||
|
@media (width: calc(100px / 1em * 1em)) {
|
||||||
|
body {
|
||||||
|
background: rgb(255, 165, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background: rgb(0, 0, 255);
|
||||||
|
}
|
||||||
|
@media (width: calc((50vh * 5em) / 4px)) {
|
||||||
|
body {
|
||||||
|
background: rgb(255, 165, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background: rgb(0, 0, 255);
|
||||||
|
}
|
||||||
|
@media (height: calc(50vw / 0.3125em * 10px)) {
|
||||||
|
body {
|
||||||
|
background: rgb(255, 165, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background: rgb(0, 0, 255);
|
||||||
|
}
|
||||||
|
@media (width: calc(10vw / 10px * 1000vh)) {
|
||||||
|
body {
|
||||||
|
background: rgb(255, 165, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background: rgb(0, 0, 255);
|
||||||
|
}
|
||||||
|
@media (width: calc(8000vh * 1vw / 1em * 8px / 40vh)) {
|
||||||
|
body {
|
||||||
|
background: rgb(255, 165, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background: rgb(0, 0, 255);
|
||||||
|
}
|
||||||
|
@media (width: calc(100vw * 10vh * 1px * 0.0625em / 1px / 1px / 1px)) {
|
||||||
|
body {
|
||||||
|
background: rgb(255, 165, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
Loading…
Add table
Add a link
Reference in a new issue