Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]
1 <?php 2 /** 3 * SCSSPHP 4 * 5 * @copyright 2012-2019 Leaf Corcoran 6 * 7 * @license http://opensource.org/licenses/MIT MIT 8 * 9 * @link http://scssphp.github.io/scssphp 10 */ 11 12 namespace ScssPhp\ScssPhp\Node; 13 14 use ScssPhp\ScssPhp\Compiler; 15 use ScssPhp\ScssPhp\Node; 16 use ScssPhp\ScssPhp\Type; 17 18 /** 19 * Dimension + optional units 20 * 21 * {@internal 22 * This is a work-in-progress. 23 * 24 * The \ArrayAccess interface is temporary until the migration is complete. 25 * }} 26 * 27 * @author Anthon Pang <anthon.pang@gmail.com> 28 */ 29 class Number extends Node implements \ArrayAccess 30 { 31 /** 32 * @var integer 33 */ 34 static public $precision = 10; 35 36 /** 37 * @see http://www.w3.org/TR/2012/WD-css3-values-20120308/ 38 * 39 * @var array 40 */ 41 static protected $unitTable = [ 42 'in' => [ 43 'in' => 1, 44 'pc' => 6, 45 'pt' => 72, 46 'px' => 96, 47 'cm' => 2.54, 48 'mm' => 25.4, 49 'q' => 101.6, 50 ], 51 'turn' => [ 52 'deg' => 360, 53 'grad' => 400, 54 'rad' => 6.28318530717958647692528676, // 2 * M_PI 55 'turn' => 1, 56 ], 57 's' => [ 58 's' => 1, 59 'ms' => 1000, 60 ], 61 'Hz' => [ 62 'Hz' => 1, 63 'kHz' => 0.001, 64 ], 65 'dpi' => [ 66 'dpi' => 1, 67 'dpcm' => 2.54, 68 'dppx' => 96, 69 ], 70 ]; 71 72 /** 73 * @var integer|float 74 */ 75 public $dimension; 76 77 /** 78 * @var array 79 */ 80 public $units; 81 82 /** 83 * Initialize number 84 * 85 * @param mixed $dimension 86 * @param mixed $initialUnit 87 */ 88 public function __construct($dimension, $initialUnit) 89 { 90 $this->type = Type::T_NUMBER; 91 $this->dimension = $dimension; 92 $this->units = is_array($initialUnit) 93 ? $initialUnit 94 : ($initialUnit ? [$initialUnit => 1] 95 : []); 96 } 97 98 /** 99 * Coerce number to target units 100 * 101 * @param array $units 102 * 103 * @return \ScssPhp\ScssPhp\Node\Number 104 */ 105 public function coerce($units) 106 { 107 if ($this->unitless()) { 108 return new Number($this->dimension, $units); 109 } 110 111 $dimension = $this->dimension; 112 113 foreach (static::$unitTable['in'] as $unit => $conv) { 114 $from = isset($this->units[$unit]) ? $this->units[$unit] : 0; 115 $to = isset($units[$unit]) ? $units[$unit] : 0; 116 $factor = pow($conv, $from - $to); 117 $dimension /= $factor; 118 } 119 120 return new Number($dimension, $units); 121 } 122 123 /** 124 * Normalize number 125 * 126 * @return \ScssPhp\ScssPhp\Node\Number 127 */ 128 public function normalize() 129 { 130 $dimension = $this->dimension; 131 $units = []; 132 133 $this->normalizeUnits($dimension, $units, 'in'); 134 135 return new Number($dimension, $units); 136 } 137 138 /** 139 * {@inheritdoc} 140 */ 141 public function offsetExists($offset) 142 { 143 if ($offset === -3) { 144 return ! is_null($this->sourceColumn); 145 } 146 147 if ($offset === -2) { 148 return ! is_null($this->sourceLine); 149 } 150 151 if ($offset === -1 || 152 $offset === 0 || 153 $offset === 1 || 154 $offset === 2 155 ) { 156 return true; 157 } 158 159 return false; 160 } 161 162 /** 163 * {@inheritdoc} 164 */ 165 public function offsetGet($offset) 166 { 167 switch ($offset) { 168 case -3: 169 return $this->sourceColumn; 170 171 case -2: 172 return $this->sourceLine; 173 174 case -1: 175 return $this->sourceIndex; 176 177 case 0: 178 return $this->type; 179 180 case 1: 181 return $this->dimension; 182 183 case 2: 184 return $this->units; 185 } 186 } 187 188 /** 189 * {@inheritdoc} 190 */ 191 public function offsetSet($offset, $value) 192 { 193 if ($offset === 1) { 194 $this->dimension = $value; 195 } elseif ($offset === 2) { 196 $this->units = $value; 197 } elseif ($offset == -1) { 198 $this->sourceIndex = $value; 199 } elseif ($offset == -2) { 200 $this->sourceLine = $value; 201 } elseif ($offset == -3) { 202 $this->sourceColumn = $value; 203 } 204 } 205 206 /** 207 * {@inheritdoc} 208 */ 209 public function offsetUnset($offset) 210 { 211 if ($offset === 1) { 212 $this->dimension = null; 213 } elseif ($offset === 2) { 214 $this->units = null; 215 } elseif ($offset === -1) { 216 $this->sourceIndex = null; 217 } elseif ($offset === -2) { 218 $this->sourceLine = null; 219 } elseif ($offset === -3) { 220 $this->sourceColumn = null; 221 } 222 } 223 224 /** 225 * Returns true if the number is unitless 226 * 227 * @return boolean 228 */ 229 public function unitless() 230 { 231 return ! array_sum($this->units); 232 } 233 234 /** 235 * Returns unit(s) as the product of numerator units divided by the product of denominator units 236 * 237 * @return string 238 */ 239 public function unitStr() 240 { 241 $numerators = []; 242 $denominators = []; 243 244 foreach ($this->units as $unit => $unitSize) { 245 if ($unitSize > 0) { 246 $numerators = array_pad($numerators, count($numerators) + $unitSize, $unit); 247 continue; 248 } 249 250 if ($unitSize < 0) { 251 $denominators = array_pad($denominators, count($denominators) + $unitSize, $unit); 252 continue; 253 } 254 } 255 256 return implode('*', $numerators) . (count($denominators) ? '/' . implode('*', $denominators) : ''); 257 } 258 259 /** 260 * Output number 261 * 262 * @param \ScssPhp\ScssPhp\Compiler $compiler 263 * 264 * @return string 265 */ 266 public function output(Compiler $compiler = null) 267 { 268 $dimension = round($this->dimension, static::$precision); 269 270 $units = array_filter($this->units, function ($unitSize) { 271 return $unitSize; 272 }); 273 274 if (count($units) > 1 && array_sum($units) === 0) { 275 $dimension = $this->dimension; 276 $units = []; 277 278 $this->normalizeUnits($dimension, $units, 'in'); 279 280 $dimension = round($dimension, static::$precision); 281 $units = array_filter($units, function ($unitSize) { 282 return $unitSize; 283 }); 284 } 285 286 $unitSize = array_sum($units); 287 288 if ($compiler && ($unitSize > 1 || $unitSize < 0 || count($units) > 1)) { 289 $compiler->throwError((string) $dimension . $this->unitStr() . " isn't a valid CSS value."); 290 } 291 292 reset($units); 293 $unit = key($units); 294 $dimension = number_format($dimension, static::$precision, '.', ''); 295 296 return (static::$precision ? rtrim(rtrim($dimension, '0'), '.') : $dimension) . $unit; 297 } 298 299 /** 300 * {@inheritdoc} 301 */ 302 public function __toString() 303 { 304 return $this->output(); 305 } 306 307 /** 308 * Normalize units 309 * 310 * @param integer|float $dimension 311 * @param array $units 312 * @param string $baseUnit 313 */ 314 private function normalizeUnits(&$dimension, &$units, $baseUnit = 'in') 315 { 316 $dimension = $this->dimension; 317 $units = []; 318 319 foreach ($this->units as $unit => $exp) { 320 if (isset(static::$unitTable[$baseUnit][$unit])) { 321 $factor = pow(static::$unitTable[$baseUnit][$unit], $exp); 322 323 $unit = $baseUnit; 324 $dimension /= $factor; 325 } 326 327 $units[$unit] = $exp + (isset($units[$unit]) ? $units[$unit] : 0); 328 } 329 } 330 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body