Add support for <angle> in CSSGradientValue's ResolveLength function
The ResolveLength function has been defined to resolve calc()
expressions so that their computed style serialization matches it's
minimal form, as requested by the CSS Values specification.
We need to do the came with calc() expressions involving Angle values,
as well as ensure its computed style serialization uses canonical units.
Bug: 40620723
Change-Id: Id096956e0689b1390969f2653560959f7bbd9f86
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6881685
Reviewed-by: Anders Hartvoll Ruud <andruud@chromium.org>
Commit-Queue: Javier Fernandez <jfernandez@igalia.com>
Cr-Commit-Position: refs/heads/main@{#1507132}
diff --git a/third_party/blink/renderer/core/css/css_gradient_value.cc b/third_party/blink/renderer/core/css/css_gradient_value.cc
index 479e1a5..aa221fe 100644
--- a/third_party/blink/renderer/core/css/css_gradient_value.cc
+++ b/third_party/blink/renderer/core/css/css_gradient_value.cc
@@ -934,6 +934,13 @@
return true;
}
+ // Computed values must be serialized in their canonical form.
+ // TODO(40620723): We could implement a function in the CSSPrimitiveValue
+ // hierarchy to determine if a value is already using canonical units.
+ if (value->IsAngle()) {
+ return true;
+ }
+
return !value->IsComputationallyIndependent();
}
@@ -948,6 +955,26 @@
return value;
}
+static const CSSPrimitiveValue* ResolveAngle(
+ const CSSPrimitiveValue* value,
+ const CSSToLengthConversionData& conversion_data) {
+ if (NeedsResolution(value)) {
+ // The syntax expects an <angle-percentage>, hence <angle> | <percentage>.
+ // Percentages should be resolved against the length of the gradient line,
+ // but in terms of computed style it's serialized as the percentage value
+ // itself.
+ if (value->IsPercentage()) {
+ double percentage = value->ComputePercentage(conversion_data);
+ return CSSNumericLiteralValue::Create(
+ percentage, CSSPrimitiveValue::UnitType::kPercentage);
+ }
+ double angle = value->ComputeDegrees(conversion_data);
+ return CSSNumericLiteralValue::Create(
+ angle, CSSPrimitiveValue::UnitType::kDegrees);
+ }
+ return value;
+}
+
const CSSGradientValue* CSSGradientValue::ResolveValuesIfNeeded(
const CSSToLengthConversionData& conversion_data) const {
switch (GetClassType()) {
@@ -1363,9 +1390,7 @@
const CSSValue* first_y = ResolveLength(first_y_, conversion_data);
const CSSValue* second_x = ResolveLength(second_x_, conversion_data);
const CSSValue* second_y = ResolveLength(second_y_, conversion_data);
- // TODO(crbug.com/40620723): We may need a new Length category for degrees,
- // so it's better to skip the resolution for now.
- const CSSPrimitiveValue* angle = angle_;
+ const CSSPrimitiveValue* angle = ResolveAngle(angle_, conversion_data);
bool stops_changed = false;
HeapVector<CSSGradientColorStop> stops;
@@ -1892,10 +1917,10 @@
const CSSValue* first_y = ResolveLength(first_y_, conversion_data);
const CSSValue* second_x = ResolveLength(second_x_, conversion_data);
const CSSValue* second_y = ResolveLength(second_y_, conversion_data);
- // TODO(crbug.com/40620723): We may need a new Length category for degrees,
- // so it's better to skip the resolution for now.
- const CSSPrimitiveValue* first_radius = first_radius_;
- const CSSPrimitiveValue* second_radius = second_radius_;
+ const CSSPrimitiveValue* first_radius = DynamicTo<CSSPrimitiveValue>(
+ ResolveLength(first_radius_, conversion_data));
+ const CSSPrimitiveValue* second_radius = DynamicTo<CSSPrimitiveValue>(
+ ResolveLength(second_radius_, conversion_data));
const auto* end_horizontal_size = DynamicTo<CSSPrimitiveValue>(
ResolveLength(end_horizontal_size_, conversion_data));
const auto* end_vertical_size = DynamicTo<CSSPrimitiveValue>(
@@ -2067,18 +2092,13 @@
const CSSValue* y = ResolveLength(y_, conversion_data);
// TODO(crbug.com/40620723): We may need a new Length category for degrees,
// so it's better to skip the resolution for now.
- const CSSPrimitiveValue* from_angle = from_angle_;
+ const CSSPrimitiveValue* from_angle =
+ ResolveAngle(from_angle_, conversion_data);
bool stops_changed = false;
HeapVector<CSSGradientColorStop> stops;
for (const auto& stop : stops_) {
- // TODO(crbug.com/40620723): We may need a new Length category for degrees,
- // so it's better to skip the resolution for now.
- const CSSPrimitiveValue* offset = stop.offset_;
- if (offset && !offset->IsAngle()) {
- offset =
- DynamicTo<CSSPrimitiveValue>(ResolveLength(offset, conversion_data));
- }
+ const auto* offset = ResolveAngle(stop.offset_, conversion_data);
stops_changed = stops_changed || (offset != stop.offset_);
stops.push_back(CSSGradientColorStop(offset, stop.color_));
}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/background-image-computed.sub-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/background-image-computed.sub-expected.txt
deleted file mode 100644
index 4a51499..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/background-image-computed.sub-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] Property background-image value 'conic-gradient(red 0deg, gold 1turn)'
- assert_equals: expected "conic-gradient(rgb(255, 0, 0) 0deg, rgb(255, 215, 0) 360deg)" but got "conic-gradient(rgb(255, 0, 0) 0deg, rgb(255, 215, 0) 1turn)"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/calc-linear-radial-conic-gradient-001-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-values/calc-linear-radial-conic-gradient-001-expected.txt
deleted file mode 100644
index 7171e51..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-values/calc-linear-radial-conic-gradient-001-expected.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] testing background-image: linear-gradient(calc(90deg), rgb(0, 128, 0), rgb(0, 0, 255))
- assert_equals: expected "linear-gradient(90deg, rgb(0, 128, 0), rgb(0, 0, 255))" but got "linear-gradient(calc(90deg), rgb(0, 128, 0), rgb(0, 0, 255))"
-[FAIL] testing background-image: linear-gradient(calc(90deg), rgb(0, 128, 0) calc(0%), rgb(0, 0, 255))
- assert_equals: expected "linear-gradient(90deg, rgb(0, 128, 0) 0%, rgb(0, 0, 255))" but got "linear-gradient(calc(90deg), rgb(0, 128, 0) 0%, rgb(0, 0, 255))"
-[FAIL] testing background-image: linear-gradient(calc(0.1turn + 0.15turn), rgb(0, 128, 0), rgb(0, 0, 255))
- assert_equals: expected "linear-gradient(90deg, rgb(0, 128, 0), rgb(0, 0, 255))" but got "linear-gradient(calc(90deg), rgb(0, 128, 0), rgb(0, 0, 255))"
-[FAIL] testing background-image: linear-gradient(calc(150grad - 50grad), rgb(0, 128, 0), rgb(0, 0, 255))
- assert_equals: expected "linear-gradient(90deg, rgb(0, 128, 0), rgb(0, 0, 255))" but got "linear-gradient(calc(90deg), rgb(0, 128, 0), rgb(0, 0, 255))"
-[FAIL] testing background-image: linear-gradient(calc(200grad - 90deg), rgb(0, 128, 0), rgb(0, 0, 255))
- assert_equals: expected "linear-gradient(90deg, rgb(0, 128, 0), rgb(0, 0, 255))" but got "linear-gradient(calc(90deg), rgb(0, 128, 0), rgb(0, 0, 255))"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/fast/gradients/conic-gradient-parsing.html b/third_party/blink/web_tests/fast/gradients/conic-gradient-parsing.html
index 9b0ca92..3a510b4 100644
--- a/third_party/blink/web_tests/fast/gradients/conic-gradient-parsing.html
+++ b/third_party/blink/web_tests/fast/gradients/conic-gradient-parsing.html
@@ -49,9 +49,9 @@
{ style: "conic-gradient(black 0, white)" , computed: "conic-gradient(rgb(0, 0, 0) 0deg, rgb(255, 255, 255))" },
{ style: "conic-gradient(black 0%, white)" , computed: "conic-gradient(rgb(0, 0, 0) 0%, rgb(255, 255, 255))" },
{ style: "conic-gradient(black 0deg, white)" , computed: "conic-gradient(rgb(0, 0, 0) 0deg, rgb(255, 255, 255))" },
- { style: "conic-gradient(black 0grad, white)" , computed: "conic-gradient(rgb(0, 0, 0) 0grad, rgb(255, 255, 255))" },
- { style: "conic-gradient(black 0rad, white)" , computed: "conic-gradient(rgb(0, 0, 0) 0rad, rgb(255, 255, 255))" },
- { style: "conic-gradient(black 0turn, white)" , computed: "conic-gradient(rgb(0, 0, 0) 0turn, rgb(255, 255, 255))" },
+ { style: "conic-gradient(black 0grad, white)" , computed: "conic-gradient(rgb(0, 0, 0) 0deg, rgb(255, 255, 255))" },
+ { style: "conic-gradient(black 0rad, white)" , computed: "conic-gradient(rgb(0, 0, 0) 0deg, rgb(255, 255, 255))" },
+ { style: "conic-gradient(black 0turn, white)" , computed: "conic-gradient(rgb(0, 0, 0) 0deg, rgb(255, 255, 255))" },
{ style: "conic-gradient(black, white 50%)" , computed: "conic-gradient(rgb(0, 0, 0), rgb(255, 255, 255) 50%)" },
{ style: "conic-gradient(black 10%, white 50%)" , computed: "conic-gradient(rgb(0, 0, 0) 10%, rgb(255, 255, 255) 50%)" },
{ style: "conic-gradient(black 10%, white 180deg)", computed: "conic-gradient(rgb(0, 0, 0) 10%, rgb(255, 255, 255) 180deg)" },
@@ -75,8 +75,8 @@
{ style: "conic-gradient(from 10deg, black, white)" , computed: "conic-gradient(from 10deg, rgb(0, 0, 0), rgb(255, 255, 255))" },
{ style: "conic-gradient(from 10deg at center, black, white)", computed: "conic-gradient(from 10deg, rgb(0, 0, 0), rgb(255, 255, 255))" },
- { style: "conic-gradient(black 0%, 10%, green .5turn, 50%, white)", computed: "conic-gradient(rgb(0, 0, 0) 0%, 10%, rgb(0, 128, 0) 0.5turn, 50%, rgb(255, 255, 255))" },
- { style: "conic-gradient(black 0deg, 0%, green .5turn, 50%, white 1turn)", computed: "conic-gradient(rgb(0, 0, 0) 0deg, 0%, rgb(0, 128, 0) 0.5turn, 50%, rgb(255, 255, 255) 1turn)" },
+ { style: "conic-gradient(black 0%, 10%, green .5turn, 50%, white)", computed: "conic-gradient(rgb(0, 0, 0) 0%, 10%, rgb(0, 128, 0) 180deg, 50%, rgb(255, 255, 255))" },
+ { style: "conic-gradient(black 0deg, 0%, green .5turn, 50%, white 1turn)", computed: "conic-gradient(rgb(0, 0, 0) 0deg, 0%, rgb(0, 128, 0) 180deg, 50%, rgb(255, 255, 255) 360deg)" },
// Examples from https://drafts.csswg.org/css-images-4/#conic-gradient-examples
{ style: "conic-gradient(#f06, gold)" , computed: "conic-gradient(rgb(255, 0, 102), rgb(255, 215, 0))" },
@@ -84,7 +84,7 @@
{ style: "conic-gradient(from 0deg, #f06, gold)" , computed: "conic-gradient(rgb(255, 0, 102), rgb(255, 215, 0))" },
{ style: "conic-gradient(from 0deg at center, #f06, gold)", computed: "conic-gradient(rgb(255, 0, 102), rgb(255, 215, 0))" },
{ style: "conic-gradient(#f06 0%, gold 100%)" , computed: "conic-gradient(rgb(255, 0, 102) 0%, rgb(255, 215, 0) 100%)" },
- { style: "conic-gradient(#f06 0deg, gold 1turn)" , computed: "conic-gradient(rgb(255, 0, 102) 0deg, rgb(255, 215, 0) 1turn)" },
+ { style: "conic-gradient(#f06 0deg, gold 1turn)" , computed: "conic-gradient(rgb(255, 0, 102) 0deg, rgb(255, 215, 0) 360deg)" },
{ style: "conic-gradient(white -50%, black 150%)" , computed: "conic-gradient(rgb(255, 255, 255) -50%, rgb(0, 0, 0) 150%)" },
{ style: "conic-gradient(white -180deg, black 540deg)" , computed: "conic-gradient(rgb(255, 255, 255) -180deg, rgb(0, 0, 0) 540deg)" },
@@ -96,7 +96,7 @@
{ style: "conic-gradient(white 45deg, black 225deg, white 405deg)" , computed: "conic-gradient(rgb(255, 255, 255) 45deg, rgb(0, 0, 0) 225deg, rgb(255, 255, 255) 405deg)" },
{ style: "conic-gradient(red, yellow, lime, aqua, blue, magenta, red", computed: "conic-gradient(rgb(255, 0, 0), rgb(255, 255, 0), rgb(0, 255, 0), rgb(0, 255, 255), rgb(0, 0, 255), rgb(255, 0, 255), rgb(255, 0, 0))" },
{ style: "conic-gradient(gold, #f06 20deg)" , computed: "conic-gradient(rgb(255, 215, 0), rgb(255, 0, 102) 20deg)" },
- { style: "conic-gradient(gold calc(100% / 2), #f06 calc(360deg * 4 / 5))" , computed: "conic-gradient(rgb(255, 215, 0) 50%, rgb(255, 0, 102) calc(288deg))" },
+ { style: "conic-gradient(gold calc(100% / 2), #f06 calc(360deg * 4 / 5))" , computed: "conic-gradient(rgb(255, 215, 0) 50%, rgb(255, 0, 102) 288deg)" },
];
test(function() {