Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
100.00% |
15 / 15 |
|
100.00% |
1 / 1 |
CRAP | |
100.00% |
1 / 1 |
| Paint | |
100.00% |
15 / 15 |
|
100.00% |
1 / 1 |
8 | |
100.00% |
1 / 1 |
| parse | |
100.00% |
15 / 15 |
|
100.00% |
1 / 1 |
8 | |||
| 1 | <?php |
| 2 | |
| 3 | declare(strict_types=1); |
| 4 | |
| 5 | namespace Phpdftk\Svg\Value; |
| 6 | |
| 7 | use Phpdftk\Svg\Value\Paint\CurrentColor; |
| 8 | use Phpdftk\Svg\Value\Paint\None_; |
| 9 | use Phpdftk\Svg\Value\Paint\SolidColor; |
| 10 | use Phpdftk\Svg\Value\Paint\Url; |
| 11 | |
| 12 | /** |
| 13 | * Parsed SVG paint value (SVG 2 ยง13.2 grammar): |
| 14 | * |
| 15 | * <paint> = none | currentColor | <color> | <url> [ none | <color> ]? |
| 16 | * |
| 17 | * The implementation set is closed: `Paint\None_`, `Paint\CurrentColor`, |
| 18 | * `Paint\SolidColor`, `Paint\Url`. The painter pattern-matches on the |
| 19 | * concrete type to choose the right PDF emit path (fill/stroke colour vs |
| 20 | * gradient/pattern reference). |
| 21 | * |
| 22 | * Color parsing delegates to `Phpdftk\Svg\Value\Color::parse()` which in |
| 23 | * turn produces a `Phpdftk\Color\ColorInterface` instance โ the SVG package |
| 24 | * depends on `phpdftk/color` for the typed colour model. |
| 25 | */ |
| 26 | abstract class Paint |
| 27 | { |
| 28 | /** |
| 29 | * Parse an SVG paint attribute value. Returns null on absent / empty / |
| 30 | * malformed input โ SVG 2's "invalid โ ignored" semantics. |
| 31 | */ |
| 32 | public static function parse(string $raw): ?self |
| 33 | { |
| 34 | $trimmed = trim($raw); |
| 35 | if ($trimmed === '') { |
| 36 | return null; |
| 37 | } |
| 38 | if (strcasecmp($trimmed, 'none') === 0) { |
| 39 | return new None_(); |
| 40 | } |
| 41 | if (strcasecmp($trimmed, 'currentColor') === 0) { |
| 42 | return new CurrentColor(); |
| 43 | } |
| 44 | // `url(#id) [fallback]` โ the fallback is itself a paint, but |
| 45 | // restricted by SVG 2 to `none | <color>`. We re-enter parse() |
| 46 | // on the tail and reject anything that comes back as a Url. |
| 47 | if (preg_match('/^url\(\s*#([^)\s]+)\s*\)\s*(.*)$/i', $trimmed, $m) === 1) { |
| 48 | $fallback = trim($m[2]); |
| 49 | $fallbackPaint = $fallback === '' ? null : self::parse($fallback); |
| 50 | if ($fallbackPaint instanceof Url) { |
| 51 | // url(#a) url(#b) isn't a legal SVG fallback chain. |
| 52 | $fallbackPaint = null; |
| 53 | } |
| 54 | return new Url($m[1], $fallbackPaint); |
| 55 | } |
| 56 | $color = Color::parse($trimmed); |
| 57 | return $color === null ? null : new SolidColor($color); |
| 58 | } |
| 59 | } |