mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-21 20:15:17 +00:00
LibWeb/CSS: Fix linear-gradient single color-stop usage
The Web::CSS::Parser's GradientParsing ignores color-stops if it is only a single one. This change allows to have color-stops with double positions against a single color. Further, also allows for `linear-gradient(black)` and similar other gradient functions
This commit is contained in:
parent
4fa372564d
commit
cfe6702767
Notes:
github-actions[bot]
2025-02-03 17:25:19 +00:00
Author: https://github.com/mehrankamal 🔰 Commit: https://github.com/LadybirdBrowser/ladybird/commit/cfe67027673 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3405 Reviewed-by: https://github.com/AtkinsSJ ✅
12 changed files with 459 additions and 7 deletions
|
@ -75,9 +75,6 @@ Optional<Vector<TElement>> Parser::parse_color_stop_list(TokenStream<ComponentVa
|
|||
if (parse_color_stop_list_element(first_element) != ElementType::ColorStop)
|
||||
return {};
|
||||
|
||||
if (!tokens.has_next_token())
|
||||
return {};
|
||||
|
||||
Vector<TElement> color_stops { first_element };
|
||||
while (tokens.has_next_token()) {
|
||||
TElement list_element {};
|
||||
|
|
|
@ -19,7 +19,7 @@ class ConicGradientStyleValue final : public AbstractImageStyleValue {
|
|||
public:
|
||||
static ValueComparingNonnullRefPtr<ConicGradientStyleValue> create(Angle from_angle, ValueComparingNonnullRefPtr<PositionStyleValue> position, Vector<AngularColorStopListElement> color_stop_list, GradientRepeating repeating)
|
||||
{
|
||||
VERIFY(color_stop_list.size() >= 2);
|
||||
VERIFY(!color_stop_list.is_empty());
|
||||
return adopt_ref(*new (nothrow) ConicGradientStyleValue(from_angle, move(position), move(color_stop_list), repeating));
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
|
||||
static ValueComparingNonnullRefPtr<LinearGradientStyleValue> create(GradientDirection direction, Vector<LinearColorStopListElement> color_stop_list, GradientType type, GradientRepeating repeating)
|
||||
{
|
||||
VERIFY(color_stop_list.size() >= 2);
|
||||
VERIFY(!color_stop_list.is_empty());
|
||||
return adopt_ref(*new (nothrow) LinearGradientStyleValue(direction, move(color_stop_list), type, repeating));
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ public:
|
|||
|
||||
static ValueComparingNonnullRefPtr<RadialGradientStyleValue> create(EndingShape ending_shape, Size size, ValueComparingNonnullRefPtr<PositionStyleValue> position, Vector<LinearColorStopListElement> color_stop_list, GradientRepeating repeating)
|
||||
{
|
||||
VERIFY(color_stop_list.size() >= 2);
|
||||
VERIFY(!color_stop_list.is_empty());
|
||||
return adopt_ref(*new (nothrow) RadialGradientStyleValue(ending_shape, size, move(position), move(color_stop_list), repeating));
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace Web::Painting {
|
|||
|
||||
static ColorStopData resolve_color_stop_positions(Layout::NodeWithStyleAndBoxModelMetrics const& node, auto const& color_stop_list, auto resolve_position_to_float, bool repeating)
|
||||
{
|
||||
VERIFY(color_stop_list.size() >= 2);
|
||||
VERIFY(!color_stop_list.is_empty());
|
||||
ColorStopList resolved_color_stops;
|
||||
|
||||
auto color_stop_length = [&](auto& stop) {
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Gradient with a single stop</title>
|
||||
<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-images-3/#color-stop-syntax">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-images-3/#coloring-gradient-line">
|
||||
<meta name="assert" content="Tests that gradient with a single color stop renders the expected solid color">
|
||||
<meta name="fuzzy" content="maxDifference=0-1; totalPixels=0-4500">
|
||||
<link rel="match" href="../../../../../expected/wpt-import//css/reference/ref-filled-green-100px-square-only.html">
|
||||
<style>
|
||||
body {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
div {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#fail {
|
||||
background: red;
|
||||
}
|
||||
|
||||
#test {
|
||||
background-image: linear-gradient(green);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>Test passes if there is a filled green square.</p>
|
||||
<div id="fail"></div>
|
||||
<div id="test"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,39 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Gradient with a single stop</title>
|
||||
<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-images-3/#color-stop-syntax">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-images-3/#coloring-gradient-line">
|
||||
<meta name="assert" content="Tests that gradient with a single color stop renders the expected solid color">
|
||||
<meta name="fuzzy" content="maxDifference=0-1; totalPixels=0-4500">
|
||||
<link rel="match" href="../../../../../expected/wpt-import//css/reference/ref-filled-green-100px-square-only.html">
|
||||
<style>
|
||||
body {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
div {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#fail {
|
||||
background: red;
|
||||
}
|
||||
|
||||
#test {
|
||||
background-image: linear-gradient(to right, green 90%);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>Test passes if there is a filled green square.</p>
|
||||
<div id="fail"></div>
|
||||
<div id="test"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,39 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Gradient with a single stop</title>
|
||||
<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-images-3/#color-stop-syntax">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-images-3/#coloring-gradient-line">
|
||||
<meta name="assert" content="Tests that gradient with a single color stop renders the expected solid color">
|
||||
<meta name="fuzzy" content="maxDifference=0-1; totalPixels=0-4500">
|
||||
<link rel="match" href="../../../../../expected/wpt-import//css/reference/ref-filled-green-100px-square-only.html">
|
||||
<style>
|
||||
body {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
div {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#fail {
|
||||
background: red;
|
||||
}
|
||||
|
||||
#test {
|
||||
background-image: radial-gradient(green);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>Test passes if there is a filled green square.</p>
|
||||
<div id="fail"></div>
|
||||
<div id="test"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,39 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Gradient with a single stop</title>
|
||||
<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-images-4/#color-stop-syntax">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-images-4/#coloring-gradient-line">
|
||||
<meta name="assert" content="Tests that gradient with a single color stop renders the expected solid color">
|
||||
<meta name="fuzzy" content="maxDifference=0-1; totalPixels=0-10000">
|
||||
<link rel="match" href="../../../../../expected/wpt-import//css/reference/ref-filled-green-100px-square-only.html">
|
||||
<style>
|
||||
body {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
div {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#fail {
|
||||
background: red;
|
||||
}
|
||||
|
||||
#test {
|
||||
background-image: conic-gradient(green);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>Test passes if there is a filled green square.</p>
|
||||
<div id="fail"></div>
|
||||
<div id="test"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,39 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Gradient with a single stop</title>
|
||||
<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-images-4/#color-stop-syntax">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-images-4/#coloring-gradient-line">
|
||||
<meta name="assert" content="Tests that gradient with a single color stop renders the expected solid color">
|
||||
<meta name="fuzzy" content="maxDifference=0-1; totalPixels=0-10000">
|
||||
<link rel="match" href="../../../../../expected/wpt-import//css/reference/ref-filled-green-100px-square-only.html">
|
||||
<style>
|
||||
body {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
div {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#fail {
|
||||
background: red;
|
||||
}
|
||||
|
||||
#test {
|
||||
background-image: conic-gradient(from 0deg at center, green);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>Test passes if there is a filled green square.</p>
|
||||
<div id="fail"></div>
|
||||
<div id="test"></div>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,92 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Color-stops parsing</title>
|
||||
<link rel="author" title="Florin Malita" href="mailto:fmalita@chromium.org">
|
||||
<link rel="help" href="http://www.w3.org/TR/css-images-4/#color-stop-syntax">
|
||||
<meta name="assert" content="General color stop parsing (applicable to all gradients) follows CSS Images 4 rules.">
|
||||
<script src="../../../resources/testharness.js"></script>
|
||||
<script src="../../../resources/testharnessreport.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
var tests = [
|
||||
// invalid stops
|
||||
{ stops: "" , parse: false },
|
||||
{ stops: "black, 25%" , parse: false },
|
||||
{ stops: "black, invalid" , parse: false },
|
||||
{ stops: "black, , white" , parse: false },
|
||||
{ stops: "black, white, 75%" , parse: false },
|
||||
{ stops: "black, 25% 50%, white" , parse: false },
|
||||
{ stops: "black, 25%, 50%, white" , parse: false },
|
||||
{ stops: "black 10% 25% 50%, white", parse: false },
|
||||
{ stops: ",black, white" , parse: false },
|
||||
{ stops: "0%, black, white" , parse: false },
|
||||
|
||||
// basic stops
|
||||
{ stops: "black" , parse: true },
|
||||
{ stops: "black 0%" , parse: true },
|
||||
{ stops: "black, white" , parse: true },
|
||||
{ stops: "black 0, white" , parse: true },
|
||||
{ stops: "black 0%, white" , parse: true },
|
||||
{ stops: "black 0%, white 100%" , parse: true },
|
||||
{ stops: "black, green, white" , parse: true },
|
||||
{ stops: "black 0%, green 50%, white 100%" , parse: true },
|
||||
{ stops: "black 50%, green 10%, white 100%", parse: true },
|
||||
|
||||
// interpolation hints
|
||||
{ stops: "black, 25%, white" , parse: true },
|
||||
{ stops: "black 0%, 25%, white 100%" , parse: true },
|
||||
{ stops: "black 0%, 15%, green 50%, 60%, white 100%", parse: true },
|
||||
|
||||
// dual-positioning
|
||||
{ stops: "black 0% 50%, white" , parse: true },
|
||||
{ stops: "black 0% 50%, white 50% 100%" , parse: true },
|
||||
{ stops: "black 0% 50%, green 25% 75%, white 50% 100%", parse: true },
|
||||
|
||||
// kitchen sink
|
||||
{ stops: "black 0% calc(100% / 5), 25%, green 30% 60%, calc(100% * 3 / 4), white calc(100% - 20%) 100%", parse: true },
|
||||
|
||||
// lots of stops
|
||||
{
|
||||
stops: (() => {
|
||||
let longGradient = "";
|
||||
for (let x = 0; x < 500; x++) {
|
||||
longGradient += `white ${x/500}%, ${(2 * x + 1) / 1000}%, `;
|
||||
}
|
||||
longGradient += "black";
|
||||
return longGradient;
|
||||
})(),
|
||||
parse: true
|
||||
}
|
||||
];
|
||||
|
||||
function check_gradient(gradient, stops, shouldParse) {
|
||||
var div = document.createElement('div');
|
||||
div.setAttribute("style", "background-image: " + gradient + "(" + stops + ")");
|
||||
|
||||
var inline_style = div.style.getPropertyValue("background-image");
|
||||
assert_equals(inline_style.startsWith(gradient), shouldParse);
|
||||
|
||||
document.body.appendChild(div);
|
||||
var computed_style = getComputedStyle(div).getPropertyValue("background-image");
|
||||
assert_equals(computed_style.startsWith(gradient), shouldParse);
|
||||
div.remove();
|
||||
}
|
||||
|
||||
[ "linear-gradient",
|
||||
"repeating-linear-gradient",
|
||||
"radial-gradient",
|
||||
"repeating-radial-gradient",
|
||||
"conic-gradient",
|
||||
"repeating-conic-gradient"
|
||||
].forEach(function(gradient) {
|
||||
tests.forEach(function(tst) {
|
||||
test(function() {
|
||||
check_gradient(gradient, tst.stops, tst.parse);
|
||||
}, gradient + "(" + tst.stops + ") " + (tst.parse ? "[ parsable ]" : "[ unparsable ]"));
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Add table
Reference in a new issue