Skip to content

Commit e70a55f

Browse files
committed
[BUGFIX] Render RGB functions with "modern" syntax if required
The "legacy" syntax does not allow a mixture of `percentage`s and `number`s for the red, green and blue components. So if `rgb`/`rgba` functions that have such a mixture are rendered in the "legacy" syntax, an invalid property value will result. An `OutputFormat` option to use the "modern" syntax throughout will be added later (see #801).
1 parent 1d76088 commit e70a55f

File tree

3 files changed

+65
-5
lines changed

3 files changed

+65
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Please also have a look at our
1313
- Partial support for CSS Color Module Level 4:
1414
- `rgb` and `rgba`, and `hsl` and `hsla` are now aliases (#797}
1515
- Parse color functions that use the "modern" syntax (#800)
16+
- Render RGB functions with "modern" syntax when required (#840)
1617
- Add a class diagram to the README (#482)
1718
- Add more tests (#449)
1819

src/Value/Color.php

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,8 @@ public function render(OutputFormat $outputFormat): string
231231
&& $this->allComponentsAreNumbers()
232232
) {
233233
return $this->renderAsHex();
234+
} elseif ($this->shouldRenderInModernSyntax()) {
235+
return $this->renderInModernSyntax($outputFormat);
234236
}
235237

236238
return parent::render($outputFormat);
@@ -282,4 +284,66 @@ private function renderAsHex(): string
282284

283285
return '#' . ($canUseShortVariant ? $result[0] . $result[2] . $result[4] : $result);
284286
}
287+
288+
/**
289+
* The "legacy" syntax does not allow RGB colors to have a mixture of `percentage`s and `number`s.
290+
*/
291+
private function shouldRenderInModernSyntax(): bool
292+
{
293+
$function = $this->getRealName();
294+
if ($function !== 'rgb' && $function !== 'rgba') {
295+
return false;
296+
}
297+
298+
$hasPercentage = false;
299+
$hasNumber = false;
300+
foreach ($this->aComponents as $key => $value) {
301+
if ($key === 'a') {
302+
// ALpha can have units that don't match those of the RGB components in the "legacy" syntax.
303+
// So it is not necessary to check it. It's also always last, hence `break` rather than `continue`.
304+
break;
305+
}
306+
if (!$value instanceof Size) {
307+
// Unexpected, unknown, or modified via the API
308+
return false;
309+
}
310+
$unit = $value->getUnit();
311+
// `switch` only does loose comparison
312+
if ($unit === null) {
313+
$hasNumber = true;
314+
} elseif ($unit === '%') {
315+
$hasPercentage = true;
316+
} else {
317+
// Invalid unit
318+
return false;
319+
}
320+
}
321+
322+
return $hasPercentage && $hasNumber;
323+
}
324+
325+
/**
326+
* @return non-empty-string
327+
*/
328+
private function renderInModernSyntax(OutputFormat $outputFormat): string
329+
{
330+
\end($this->aComponents);
331+
if (\key($this->aComponents) === 'a') {
332+
$alpha = $this->aComponents['a'];
333+
$componentsWithoutAlpha = \array_diff_key($this->aComponents, ['a' => 0]);
334+
} else {
335+
$componentsWithoutAlpha = $this->aComponents;
336+
}
337+
338+
$arguments = $outputFormat->implode(' ', $componentsWithoutAlpha);
339+
if (isset($alpha)) {
340+
$arguments = $outputFormat->implode(
341+
$outputFormat->spaceBeforeListArgumentSeparator('/') . '/'
342+
. $outputFormat->spaceAfterListArgumentSeparator('/'),
343+
[$arguments, $alpha]
344+
);
345+
}
346+
347+
return $this->getName() . '(' . $arguments . ')';
348+
}
285349
}

tests/Unit/Value/ColorTest.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,6 @@ public static function provideValidColorAndExpectedRendering(): array
8686
'rgb(0 119 0)',
8787
'#070',
8888
],
89-
// The "legacy" syntax currently used for rendering does not allow a mixture of percentages and numbers.
90-
/*
9189
'modern rgb with percentage R' => [
9290
'rgb(0% 119 0)',
9391
'rgb(0% 119 0)',
@@ -112,7 +110,6 @@ public static function provideValidColorAndExpectedRendering(): array
112110
'rgb(0 60% 0%)',
113111
'rgb(0 60% 0%)',
114112
],
115-
//*/
116113
'modern rgb with percentage components' => [
117114
'rgb(0% 60% 0%)',
118115
'rgb(0%,60%,0%)',
@@ -131,7 +128,6 @@ public static function provideValidColorAndExpectedRendering(): array
131128
'rgb(0 119 0 / 50%)',
132129
'rgba(0,119,0,50%)',
133130
],
134-
/*
135131
'modern rgba with percentage R' => [
136132
'rgb(0% 119 0 / 0.5)',
137133
'rgba(0% 119 0/.5)',
@@ -144,7 +140,6 @@ public static function provideValidColorAndExpectedRendering(): array
144140
'rgb(0 119 0% / 0.5)',
145141
'rgba(0 119 0%/.5)',
146142
],
147-
//*/
148143
'modern rgba with percentage RGB' => [
149144
'rgb(0% 60% 0% / 0.5)',
150145
'rgba(0%,60%,0%,.5)',

0 commit comments

Comments
 (0)