Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
3.33% covered (danger)
3.33%
1 / 30
33.33% covered (danger)
33.33%
1 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
RelativeColor
3.33% covered (danger)
3.33%
1 / 30
33.33% covered (danger)
33.33%
1 / 3
459.20
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 toCss
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
12
 spaceName
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
342
1<?php
2
3declare(strict_types=1);
4
5namespace Phpdftk\Css\Value;
6
7/**
8 * CSS Color 5 §4 — relative color syntax. `rgb(from <color> R G B
9 * [/ A])`, `hsl(from <color> H S L [/ A])`, `lab(from ...)`,
10 * `lch(from ...)`, `oklab(from ...)`, `oklch(from ...)`,
11 * `hwb(from ...)`, `color(from <color> <space> R G B [/ A])`.
12 *
13 * Inside the function the component identifiers `r`, `g`, `b`
14 * (or `h`, `s`, `l`, etc.) refer to the source color's components
15 * after conversion to the target color space. The component slots
16 * can also be replaced by literal values, percentages, or calc()
17 * expressions.
18 *
19 * Stored as the parsed declaration; the actual conversion runs
20 * when the 4E color engine ships.
21 */
22final readonly class RelativeColor extends Value
23{
24    public function __construct(
25        public ColorSpace $space,
26        // Source is a concrete `Color` for literal/named/function-form
27        // origins (`rgb(from red …)`), or a `Keyword` for `currentcolor`
28        // / `transparent` whose value depends on the using element and
29        // must be resolved at paint time. CSS Color 5 §4.
30        public Color|Keyword $source,
31        public Value $component1,
32        public Value $component2,
33        public Value $component3,
34        public Value $alpha,
35    ) {}
36
37    public function toCss(): string
38    {
39        // We can't perfectly reconstruct the original keyword
40        // (rgb vs hsl vs ...) without tracking the syntactic
41        // entry point, so emit color(<space> from ...) which is
42        // the canonical CSS Color 5 form.
43        $alpha = $this->alpha instanceof Number && $this->alpha->value === 1.0
44            ? ''
45            : ' / ' . $this->alpha->toCss();
46        return sprintf(
47            'color(from %s %s %s %s %s%s)',
48            $this->source->toCss(),
49            self::spaceName($this->space),
50            $this->component1->toCss(),
51            $this->component2->toCss(),
52            $this->component3->toCss(),
53            $alpha,
54        );
55    }
56
57    private static function spaceName(ColorSpace $space): string
58    {
59        return match ($space) {
60            ColorSpace::sRGB => 'srgb',
61            ColorSpace::sRGBLinear => 'srgb-linear',
62            ColorSpace::DisplayP3 => 'display-p3',
63            ColorSpace::DisplayP3Linear => 'display-p3-linear',
64            ColorSpace::A98RGB => 'a98-rgb',
65            ColorSpace::A98RGBLinear => 'a98-rgb-linear',
66            ColorSpace::ProPhotoRGB => 'prophoto-rgb',
67            ColorSpace::ProPhotoRGBLinear => 'prophoto-rgb-linear',
68            ColorSpace::Rec2020 => 'rec2020',
69            ColorSpace::Rec2020Linear => 'rec2020-linear',
70            ColorSpace::Lab => 'lab',
71            ColorSpace::Lch => 'lch',
72            ColorSpace::OKLab => 'oklab',
73            ColorSpace::OKLCH => 'oklch',
74            ColorSpace::XYZ, ColorSpace::XYZD65 => 'xyz-d65',
75            ColorSpace::XYZD50 => 'xyz-d50',
76            ColorSpace::HWB => 'hwb',
77        };
78    }
79}