Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 1
<?php
2
 
3
namespace Sabberworm\CSS\Value;
4
 
5
use Sabberworm\CSS\OutputFormat;
6
use Sabberworm\CSS\Parsing\ParserState;
7
use Sabberworm\CSS\Parsing\UnexpectedEOFException;
8
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
9
 
10
/**
11
 * A `Size` consists of a numeric `size` value and a unit.
12
 */
13
class Size extends PrimitiveValue
14
{
15
    /**
16
     * vh/vw/vm(ax)/vmin/rem are absolute insofar as they don’t scale to the immediate parent (only the viewport)
17
     *
18
     * @var array<int, string>
19
     *
20
     * @internal
21
     */
22
    const ABSOLUTE_SIZE_UNITS = [
23
        'px', 'pt', 'pc',
24
        'cm', 'mm', 'mozmm', 'in',
25
        'vh', 'dvh', 'svh', 'lvh',
26
        'vw', 'vmin', 'vmax', 'rem',
27
    ];
28
 
29
    /**
30
     * @var array<int, string>
31
     *
32
     * @internal
33
     */
34
    const RELATIVE_SIZE_UNITS = ['%', 'em', 'ex', 'ch', 'fr'];
35
 
36
    /**
37
     * @var array<int, string>
38
     *
39
     * @internal
40
     */
41
    const NON_SIZE_UNITS = ['deg', 'grad', 'rad', 's', 'ms', 'turn', 'Hz', 'kHz'];
42
 
43
    /**
44
     * @var array<int, array<string, string>>|null
45
     */
46
    private static $SIZE_UNITS = null;
47
 
48
    /**
49
     * @var float
50
     */
51
    private $fSize;
52
 
53
    /**
54
     * @var string|null
55
     */
56
    private $sUnit;
57
 
58
    /**
59
     * @var bool
60
     */
61
    private $bIsColorComponent;
62
 
63
    /**
64
     * @param float|int|string $fSize
65
     * @param string|null $sUnit
66
     * @param bool $bIsColorComponent
67
     * @param int $iLineNo
68
     */
69
    public function __construct($fSize, $sUnit = null, $bIsColorComponent = false, $iLineNo = 0)
70
    {
71
        parent::__construct($iLineNo);
72
        $this->fSize = (float)$fSize;
73
        $this->sUnit = $sUnit;
74
        $this->bIsColorComponent = $bIsColorComponent;
75
    }
76
 
77
    /**
78
     * @param bool $bIsColorComponent
79
     *
80
     * @return Size
81
     *
82
     * @throws UnexpectedEOFException
83
     * @throws UnexpectedTokenException
84
     */
85
    public static function parse(ParserState $oParserState, $bIsColorComponent = false)
86
    {
87
        $sSize = '';
88
        if ($oParserState->comes('-')) {
89
            $sSize .= $oParserState->consume('-');
90
        }
91
        while (is_numeric($oParserState->peek()) || $oParserState->comes('.') || $oParserState->comes('e', true)) {
92
            if ($oParserState->comes('.')) {
93
                $sSize .= $oParserState->consume('.');
94
            } elseif ($oParserState->comes('e', true)) {
95
                $sLookahead = $oParserState->peek(1, 1);
96
                if (is_numeric($sLookahead) || $sLookahead === '+' || $sLookahead === '-') {
97
                    $sSize .= $oParserState->consume(2);
98
                } else {
99
                    break; // Reached the unit part of the number like "em" or "ex"
100
                }
101
            } else {
102
                $sSize .= $oParserState->consume(1);
103
            }
104
        }
105
 
106
        $sUnit = null;
107
        $aSizeUnits = self::getSizeUnits();
108
        foreach ($aSizeUnits as $iLength => &$aValues) {
109
            $sKey = strtolower($oParserState->peek($iLength));
110
            if (array_key_exists($sKey, $aValues)) {
111
                if (($sUnit = $aValues[$sKey]) !== null) {
112
                    $oParserState->consume($iLength);
113
                    break;
114
                }
115
            }
116
        }
117
        return new Size((float)$sSize, $sUnit, $bIsColorComponent, $oParserState->currentLine());
118
    }
119
 
120
    /**
121
     * @return array<int, array<string, string>>
122
     */
123
    private static function getSizeUnits()
124
    {
125
        if (!is_array(self::$SIZE_UNITS)) {
126
            self::$SIZE_UNITS = [];
127
            foreach (array_merge(self::ABSOLUTE_SIZE_UNITS, self::RELATIVE_SIZE_UNITS, self::NON_SIZE_UNITS) as $val) {
128
                $iSize = strlen($val);
129
                if (!isset(self::$SIZE_UNITS[$iSize])) {
130
                    self::$SIZE_UNITS[$iSize] = [];
131
                }
132
                self::$SIZE_UNITS[$iSize][strtolower($val)] = $val;
133
            }
134
 
135
            krsort(self::$SIZE_UNITS, SORT_NUMERIC);
136
        }
137
 
138
        return self::$SIZE_UNITS;
139
    }
140
 
141
    /**
142
     * @param string $sUnit
143
     *
144
     * @return void
145
     */
146
    public function setUnit($sUnit)
147
    {
148
        $this->sUnit = $sUnit;
149
    }
150
 
151
    /**
152
     * @return string|null
153
     */
154
    public function getUnit()
155
    {
156
        return $this->sUnit;
157
    }
158
 
159
    /**
160
     * @param float|int|string $fSize
161
     */
162
    public function setSize($fSize)
163
    {
164
        $this->fSize = (float)$fSize;
165
    }
166
 
167
    /**
168
     * @return float
169
     */
170
    public function getSize()
171
    {
172
        return $this->fSize;
173
    }
174
 
175
    /**
176
     * @return bool
177
     */
178
    public function isColorComponent()
179
    {
180
        return $this->bIsColorComponent;
181
    }
182
 
183
    /**
184
     * Returns whether the number stored in this Size really represents a size (as in a length of something on screen).
185
     *
186
     * @return false if the unit an angle, a duration, a frequency or the number is a component in a Color object.
187
     */
188
    public function isSize()
189
    {
190
        if (in_array($this->sUnit, self::NON_SIZE_UNITS, true)) {
191
            return false;
192
        }
193
        return !$this->isColorComponent();
194
    }
195
 
196
    /**
197
     * @return bool
198
     */
199
    public function isRelative()
200
    {
201
        if (in_array($this->sUnit, self::RELATIVE_SIZE_UNITS, true)) {
202
            return true;
203
        }
204
        if ($this->sUnit === null && $this->fSize != 0) {
205
            return true;
206
        }
207
        return false;
208
    }
209
 
210
    /**
211
     * @return string
212
     */
213
    public function __toString()
214
    {
215
        return $this->render(new OutputFormat());
216
    }
217
 
218
    /**
219
     * @param OutputFormat|null $oOutputFormat
220
     *
221
     * @return string
222
     */
223
    public function render($oOutputFormat)
224
    {
225
        $l = localeconv();
226
        $sPoint = preg_quote($l['decimal_point'], '/');
227
        $sSize = preg_match("/[\d\.]+e[+-]?\d+/i", (string)$this->fSize)
228
            ? preg_replace("/$sPoint?0+$/", "", sprintf("%f", $this->fSize)) : (string)$this->fSize;
229
        return preg_replace(["/$sPoint/", "/^(-?)0\./"], ['.', '$1.'], $sSize)
230
            . ($this->sUnit === null ? '' : $this->sUnit);
231
    }
232
}