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 Color extends CSSFunction
  11  {
  12      /**
  13       * @param array<int, RuleValueList|CSSFunction|CSSString|LineName|Size|URL|string> $aColor
  14       * @param int $iLineNo
  15       */
  16      public function __construct(array $aColor, $iLineNo = 0)
  17      {
  18          parent::__construct(implode('', array_keys($aColor)), $aColor, ',', $iLineNo);
  19      }
  20  
  21      /**
  22       * @return Color|CSSFunction
  23       *
  24       * @throws UnexpectedEOFException
  25       * @throws UnexpectedTokenException
  26       */
  27      public static function parse(ParserState $oParserState)
  28      {
  29          $aColor = [];
  30          if ($oParserState->comes('#')) {
  31              $oParserState->consume('#');
  32              $sValue = $oParserState->parseIdentifier(false);
  33              if ($oParserState->strlen($sValue) === 3) {
  34                  $sValue = $sValue[0] . $sValue[0] . $sValue[1] . $sValue[1] . $sValue[2] . $sValue[2];
  35              } elseif ($oParserState->strlen($sValue) === 4) {
  36                  $sValue = $sValue[0] . $sValue[0] . $sValue[1] . $sValue[1] . $sValue[2] . $sValue[2] . $sValue[3]
  37                      . $sValue[3];
  38              }
  39  
  40              if ($oParserState->strlen($sValue) === 8) {
  41                  $aColor = [
  42                      'r' => new Size(intval($sValue[0] . $sValue[1], 16), null, true, $oParserState->currentLine()),
  43                      'g' => new Size(intval($sValue[2] . $sValue[3], 16), null, true, $oParserState->currentLine()),
  44                      'b' => new Size(intval($sValue[4] . $sValue[5], 16), null, true, $oParserState->currentLine()),
  45                      'a' => new Size(
  46                          round(self::mapRange(intval($sValue[6] . $sValue[7], 16), 0, 255, 0, 1), 2),
  47                          null,
  48                          true,
  49                          $oParserState->currentLine()
  50                      ),
  51                  ];
  52              } else {
  53                  $aColor = [
  54                      'r' => new Size(intval($sValue[0] . $sValue[1], 16), null, true, $oParserState->currentLine()),
  55                      'g' => new Size(intval($sValue[2] . $sValue[3], 16), null, true, $oParserState->currentLine()),
  56                      'b' => new Size(intval($sValue[4] . $sValue[5], 16), null, true, $oParserState->currentLine()),
  57                  ];
  58              }
  59          } else {
  60              $sColorMode = $oParserState->parseIdentifier(true);
  61              $oParserState->consumeWhiteSpace();
  62              $oParserState->consume('(');
  63  
  64              $bContainsVar = false;
  65              $iLength = $oParserState->strlen($sColorMode);
  66              for ($i = 0; $i < $iLength; ++$i) {
  67                  $oParserState->consumeWhiteSpace();
  68                  if ($oParserState->comes('var')) {
  69                      $aColor[$sColorMode[$i]] = CSSFunction::parseIdentifierOrFunction($oParserState);
  70                      $bContainsVar = true;
  71                  } else {
  72                      $aColor[$sColorMode[$i]] = Size::parse($oParserState, true);
  73                  }
  74  
  75                  if ($bContainsVar && $oParserState->comes(')')) {
  76                      // With a var argument the function can have fewer arguments
  77                      break;
  78                  }
  79  
  80                  $oParserState->consumeWhiteSpace();
  81                  if ($i < ($iLength - 1)) {
  82                      $oParserState->consume(',');
  83                  }
  84              }
  85              $oParserState->consume(')');
  86  
  87              if ($bContainsVar) {
  88                  return new CSSFunction($sColorMode, array_values($aColor), ',', $oParserState->currentLine());
  89              }
  90          }
  91          return new Color($aColor, $oParserState->currentLine());
  92      }
  93  
  94      /**
  95       * @param float $fVal
  96       * @param float $fFromMin
  97       * @param float $fFromMax
  98       * @param float $fToMin
  99       * @param float $fToMax
 100       *
 101       * @return float
 102       */
 103      private static function mapRange($fVal, $fFromMin, $fFromMax, $fToMin, $fToMax)
 104      {
 105          $fFromRange = $fFromMax - $fFromMin;
 106          $fToRange = $fToMax - $fToMin;
 107          $fMultiplier = $fToRange / $fFromRange;
 108          $fNewVal = $fVal - $fFromMin;
 109          $fNewVal *= $fMultiplier;
 110          return $fNewVal + $fToMin;
 111      }
 112  
 113      /**
 114       * @return array<int, RuleValueList|CSSFunction|CSSString|LineName|Size|URL|string>
 115       */
 116      public function getColor()
 117      {
 118          return $this->aComponents;
 119      }
 120  
 121      /**
 122       * @param array<int, RuleValueList|CSSFunction|CSSString|LineName|Size|URL|string> $aColor
 123       *
 124       * @return void
 125       */
 126      public function setColor(array $aColor)
 127      {
 128          $this->setName(implode('', array_keys($aColor)));
 129          $this->aComponents = $aColor;
 130      }
 131  
 132      /**
 133       * @return string
 134       */
 135      public function getColorDescription()
 136      {
 137          return $this->getName();
 138      }
 139  
 140      /**
 141       * @return string
 142       */
 143      public function __toString()
 144      {
 145          return $this->render(new OutputFormat());
 146      }
 147  
 148      /**
 149       * @return string
 150       */
 151      public function render(OutputFormat $oOutputFormat)
 152      {
 153          // Shorthand RGB color values
 154          if ($oOutputFormat->getRGBHashNotation() && implode('', array_keys($this->aComponents)) === 'rgb') {
 155              $sResult = sprintf(
 156                  '%02x%02x%02x',
 157                  $this->aComponents['r']->getSize(),
 158                  $this->aComponents['g']->getSize(),
 159                  $this->aComponents['b']->getSize()
 160              );
 161              return '#' . (($sResult[0] == $sResult[1]) && ($sResult[2] == $sResult[3]) && ($sResult[4] == $sResult[5])
 162                      ? "$sResult[0]$sResult[2]$sResult[4]" : $sResult);
 163          }
 164          return parent::render($oOutputFormat);
 165      }
 166  }