Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401]

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