Provides operations and type testing for Sass colours.
Colour operations are all piecewise, e.g. when adding two colours each
component is added independantly; Rr = R1 + R2, Gr = G1 + G2, Br = B1 + B2.
Resulting colours are returned as a named colour if possible or #rrggbb.
Transparent is a SassColour. Operations on transparent return transparent.
/** * Lex an expression into SassScript tokens. * @param string $string expression to lex * @param SassContext $context the context in which the expression is lexed * @return array tokens */ public function lex($string, $context) { // if it's already lexed, just return it as-is if (is_object($string)) { return array($string); } if (is_array($string)) { return $string; } $tokens = array(); // whilst the string is not empty, split it into it's tokens. while ($string !== false) { if (($match = $this->isWhitespace($string)) !== false) { $tokens[] = null; } elseif (($match = SassScriptFunction::isa($string)) !== false) { preg_match(SassScriptFunction::MATCH_FUNC, $match, $matches); $args = array(); foreach (SassScriptFunction::extractArgs($matches[SassScriptFunction::ARGS], false, $context) as $key => $expression) { $args[$key] = $this->parser->evaluate($expression, $context); } $tokens[] = new SassScriptFunction($matches[SassScriptFunction::NAME], $args); } elseif (($match = SassBoolean::isa($string)) !== false) { $tokens[] = new SassBoolean($match); } elseif (($match = SassColour::isa($string)) !== false) { $tokens[] = new SassColour($match); } elseif (($match = SassNumber::isa($string)) !== false) { $tokens[] = new SassNumber($match); } elseif (($match = SassString::isa($string)) !== false) { $stringed = new SassString($match); if (strlen($stringed->quote) == 0 && SassList::isa($string) !== false && !preg_match("/^\\-\\w+\\-\\w+\$/", $stringed->value)) { $tokens[] = new SassList($string); } else { $tokens[] = $stringed; } } elseif ($string == '()') { $match = $string; $tokens[] = new SassList($match); } elseif (($match = SassScriptOperation::isa($string)) !== false) { $tokens[] = new SassScriptOperation($match); } elseif (($match = SassScriptVariable::isa($string)) !== false) { $tokens[] = new SassScriptVariable($match); } else { $_string = $string; $match = ''; while (strlen($_string) && !$this->isWhitespace($_string)) { foreach (SassScriptOperation::$inStrOperators as $operator) { if (substr($_string, 0, strlen($operator)) == $operator) { break 2; } } $match .= $_string[0]; $_string = substr($_string, 1); } $tokens[] = new SassString($match); } $string = substr($string, strlen($match)); } return $tokens; }
/** * Lex an expression into SassScript tokens. * @param string expression to lex * @param SassContext the context in which the expression is lexed * @return array tokens */ public function lex($string, $context) { $tokens = array(); while ($string !== false) { if (($match = $this->isWhitespace($string)) !== false) { $tokens[] = null; } elseif (($match = SassScriptFunction::isa($string)) !== false) { preg_match(SassScriptFunction::MATCH_FUNC, $match, $matches); $args = array(); foreach (SassScriptFunction::extractArgs($matches[SassScriptFunction::ARGS]) as $expression) { $args[] = $this->parser->evaluate($expression, $context); } $tokens[] = new SassScriptFunction($matches[SassScriptFunction::NAME], $args); } elseif (($match = SassString::isa($string)) !== false) { $tokens[] = new SassString($match); } elseif (($match = SassBoolean::isa($string)) !== false) { $tokens[] = new SassBoolean($match); } elseif (($match = SassColour::isa($string)) !== false) { $tokens[] = new SassColour($match); } elseif (($match = SassNumber::isa($string)) !== false) { $tokens[] = new SassNumber($match); } elseif (($match = SassScriptOperation::isa($string)) !== false) { $tokens[] = new SassScriptOperation($match); } elseif (($match = SassScriptVariable::isa($string)) !== false) { $tokens[] = new SassScriptVariable($match); } else { $_string = $string; $match = ''; while (strlen($_string) && !$this->isWhitespace($_string)) { foreach (SassScriptOperation::$inStrOperators as $operator) { if (substr($_string, 0, strlen($operator)) == $operator) { break 2; } } $match .= $_string[0]; $_string = substr($_string, 1); } $tokens[] = new SassString($match); } $string = substr($string, strlen($match)); } return $tokens; }
/** * Returns a value indicating if a token of this type can be matched at * the start of the subject string. * @param string the subject string * @return mixed match at the start of the string or false if no match */ public static function isa($subject) { if (empty(self::$regex)) { self::$regex = str_replace('{CSS_COLOURS}', join('|', array_reverse(array_keys(self::$svgColours))), self::MATCH); } return preg_match(self::$regex, strtolower($subject), $matches) ? $matches[0] : false; }
/** * Returns the next token from the string. * @param string string to tokenise * @return mixed token. Either a SassLiteral, a SassScriptOperation * @throws SassScriptLexerException if unable to tokenise string */ private function nextToken(&$string) { if (($match = $this->isWhitespace($string)) !== false) { $string = substr($string, strlen($match)); return $this->nextToken($string); } elseif (($match = SassNumber::isa($string)) !== false) { $string = substr($string, strlen($match)); return new SassNumber($match); } elseif (($match = SassColour::isa($string)) !== false) { $string = substr($string, strlen($match)); return new SassColour($match); } elseif (($match = SassBoolean::isa($string)) !== false) { $string = substr($string, strlen($match)); return new SassBoolean($match); } elseif (($match = SassString::isa($string)) !== false) { $string = substr($string, strlen($match)); return new SassString($match); } elseif (($match = SassScriptFunction::isa($string)) !== false) { $string = substr($string, strlen($match)); return new SassScriptFunction($match); } elseif (($match = SassScriptOperation::isa($string)) !== false) { $string = substr($string, strlen($match)); return new SassScriptOperation($match); } else { throw new SassScriptLexerException("Unable to tokenise \"{$string}\""); } }
/** * Substitute variables in an expression with their values. * @param string expression to substitue variables in * @param SassContext the context for variable substitution * @return string expression with variables substitued */ private function substituteVariables($string, $context) { for ($i = 0, $n = preg_match_all(self::MATCH_VARIABLE, $string, $matches); $i < $n; $i++) { $var = $context->getVariable($matches[1][$i]); if (is_bool($var)) { $var = $var ? 'true' : 'false'; } elseif (!(SassColour::isa($var) || SassNumber::isa($var))) { $var = "\"{$var}\""; } $string = str_replace($matches[0][$i], $var, $string); } return $string; }
/** * Returns a copy of this colour with one or more channels changed. * RGB or HSL attributes may be changed, but not both at once. * @param array attributes to change */ public function with($attributes) { if ($this->assertValid($attributes, false) === 'hsl') { $colour = array_merge(array('hue' => $this->getHue(), 'saturation' => $this->getSaturation(), 'lightness' => $this->getLightness(), 'alpha' => $this->alpha), $attributes); } else { $colour = array_merge(array('red' => $this->getRed(), 'green' => $this->getGreen(), 'blue' => $this->getBlue(), 'alpha' => $this->alpha), $attributes); } $colour = new SassColour($colour); $colour->getRed(); # will get RGB and HSL return $colour; }
/** * returns an IE hex string for a color with an alpha channel * suitable for passing to IE filters. */ public static function ie_hex_str($color) { if (!$color instanceof SassColour) { $color = new SassColour($color); } $alpha = str_replace(',', '.', round($color->alpha * 255)); $alpha_str = str_pad(dechex($alpha), 2, '0', STR_PAD_LEFT); $col = $color->asHex(FALSE); return new SassString(strtoupper('#' . $alpha_str . $col)); }