: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
list($color, $delta) = $args[2];
$color = $this->assertColor($color);
$delta = floatval($delta[1]);
protected function lib_darken($args) {
list($color, $delta) = $this->colorArgs($args);
$hsl = $this->toHSL($color);
$hsl[3] = $this->clamp($hsl[3] - $delta, 100);
return $this->toRGB($hsl);
protected function lib_lighten($args) {
list($color, $delta) = $this->colorArgs($args);
$hsl = $this->toHSL($color);
$hsl[3] = $this->clamp($hsl[3] + $delta, 100);
return $this->toRGB($hsl);
protected function lib_saturate($args) {
list($color, $delta) = $this->colorArgs($args);
$hsl = $this->toHSL($color);
$hsl[2] = $this->clamp($hsl[2] + $delta, 100);
return $this->toRGB($hsl);
protected function lib_desaturate($args) {
list($color, $delta) = $this->colorArgs($args);
$hsl = $this->toHSL($color);
$hsl[2] = $this->clamp($hsl[2] - $delta, 100);
return $this->toRGB($hsl);
protected function lib_spin($args) {
list($color, $delta) = $this->colorArgs($args);
$hsl = $this->toHSL($color);
$hsl[1] = $hsl[1] + $delta % 360;
if ($hsl[1] < 0) $hsl[1] += 360;
return $this->toRGB($hsl);
protected function lib_fadeout($args) {
list($color, $delta) = $this->colorArgs($args);
$color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) - $delta / 100);
protected function lib_fadein($args) {
list($color, $delta) = $this->colorArgs($args);
$color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) + $delta / 100);
protected function lib_hue($color) {
$hsl = $this->toHSL($this->assertColor($color));
protected function lib_saturation($color) {
$hsl = $this->toHSL($this->assertColor($color));
protected function lib_lightness($color) {
$hsl = $this->toHSL($this->assertColor($color));
// get the alpha of a color
// defaults to 1 for non-colors or colors without an alpha
protected function lib_alpha($value) {
if (!is_null($color = $this->coerceColor($value))) {
return isset($color[4]) ? $color[4] : 1;
// set the alpha of the color
protected function lib_fade($args) {
list($color, $alpha) = $this->colorArgs($args);
$color[4] = $this->clamp($alpha / 100.0);
protected function lib_percentage($arg) {
$num = $this->assertNumber($arg);
// mixes two colors by weight
// mix(@color1, @color2, @weight);
// http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html#mix-instance_method
protected function lib_mix($args) {
if ($args[0] != "list" || count($args[2]) < 3) $this->throwError("mix expects (color1, color2, weight)");
list($first, $second, $weight) = $args[2];
$first = $this->assertColor($first);
$second = $this->assertColor($second);
$first_a = $this->lib_alpha($first);
$second_a = $this->lib_alpha($second);
$weight = $weight[1] / 100.0;
$a = $first_a - $second_a;
$w1 = (($w * $a == -1 ? $w : ($w + $a) / (1 + $w * $a)) + 1) / 2.0;
$w1 * $first[1] + $w2 * $second[1],
$w1 * $first[2] + $w2 * $second[2],
$w1 * $first[3] + $w2 * $second[3],
if ($first_a != 1.0 || $second_a != 1.0) {
$new[] = $first_a * $weight + $second_a * ($weight - 1);
return $this->fixColor($new);
protected function lib_contrast($args) {
if ($args[0] != 'list' || count($args[2]) < 3) {
list($inputColor, $darkColor, $lightColor) = $args[2];
$inputColor = $this->assertColor($inputColor);
$darkColor = $this->assertColor($darkColor);
$lightColor = $this->assertColor($lightColor);
$hsl = $this->toHSL($inputColor);
protected function assertColor($value, $error = "expected color value") {
$color = $this->coerceColor($value);
if (is_null($color)) $this->throwError($error);
protected function assertNumber($value, $error = "expecting number") {
if ($value[0] == "number") return $value[1];
$this->throwError($error);
protected function toHSL($color) {
if ($color[0] == 'hsl') return $color;
if ($L < 0.5) $S = ($max - $min) / ($max + $min); else
$S = ($max - $min) / (2.0 - $max - $min);
if ($r == $max) $H = ($g - $b) / ($max - $min); elseif ($g == $max) $H = 2.0 + ($b - $r) / ($max - $min);
elseif ($b == $max) $H = 4.0 + ($r - $g) / ($max - $min);
($H < 0 ? $H + 6 : $H) * 60,
if (count($color) > 4) $out[] = $color[4]; // copy alpha
protected function toRGB_helper($comp, $temp1, $temp2) {
if ($comp < 0) $comp += 1.0; elseif ($comp > 1) $comp -= 1.0;
if (6 * $comp < 1) return $temp1 + ($temp2 - $temp1) * 6 * $comp;
if (2 * $comp < 1) return $temp2;
if (3 * $comp < 2) return $temp1 + ($temp2 - $temp1) * ((2 / 3) - $comp) * 6;
* Converts a hsl array into a color value in rgb.
* Expects H to be in range of 0 to 360, S and L in 0 to 100
protected function toRGB($color) {
if ($color == 'color') return $color;
$temp2 = $L < 0.5 ? $L * (1.0 + $S) : $L + $S - $L * $S;
$temp1 = 2.0 * $L - $temp2;
$r = $this->toRGB_helper($H + 1 / 3, $temp1, $temp2);
$g = $this->toRGB_helper($H, $temp1, $temp2);
$b = $this->toRGB_helper($H - 1 / 3, $temp1, $temp2);
// $out = array('color', round($r*255), round($g*255), round($b*255));
if (count($color) > 4) $out[] = $color[4]; // copy alpha
protected function clamp($v, $max = 1, $min = 0) {
return min($max, max($min, $v));
* Convert the rgb, rgba, hsl color literals of function type
* as returned by the parser into values of color type.
protected function funcToColor($func) {
if ($func[2][0] != 'list') return false; // need a list of arguments
$rawComponents = $func[2][2];
if ($fname == 'hsl' || $fname == 'hsla') {
foreach ($rawComponents as $c) {
$val = $this->reduce($c);
$val = isset($val[1]) ? floatval($val[1]) : 0;
if ($i == 0) $clamp = 360; elseif ($i < 3) $clamp = 100;
$hsl[] = $this->clamp($val, $clamp);
while (count($hsl) < 4) $hsl[] = 0;
return $this->toRGB($hsl);
} elseif ($fname == 'rgb' || $fname == 'rgba') {
foreach ($rawComponents as $c) {
if ($c[0] == "number" && $c[2] == "%") {
$components[] = 255 * ($c[1] / 100);
$components[] = floatval($c[1]);
if ($c[0] == "number" && $c[2] == "%") {
$components[] = 1.0 * ($c[1] / 100);
$components[] = floatval($c[1]);
while (count($components) < 3) $components[] = 0;
array_unshift($components, 'color');
return $this->fixColor($components);
protected function reduce($value, $forExpression = false) {
$reduced = $this->reduce($value[1]);
$var = $this->compileValue($reduced);
$res = $this->reduce(array(
if (empty($value[2])) $res = $this->lib_e($res);
$key = $this->reduce($key);
$key = $this->vPrefix . $this->compileValue($this->lib_e($key));
$seen =& $this->env->seenNames;
if (!empty($seen[$key])) {
$this->throwError("infinite loop detected: $key");
$out = $this->reduce($this->get($key, self::$defaultValue));
foreach ($value[2] as &$item) {
$item = $this->reduce($item, $forExpression);
return $this->evaluate($value);
foreach ($value[2] as &$part) {
$strip = $part[0] == "variable";
$part = $this->reduce($part);
if ($strip) $part = $this->lib_e($part);
return $this->lib_e($this->reduce($inner));
$color = $this->funcToColor($value);
if ($color) return $color;
list(, $name, $args) = $value;
if ($name == "%") $name = "_sprintf";
$f = isset($this->libFunctions[$name]) ? $this->libFunctions[$name] : array(
if ($args[0] == 'list') $args = self::compressList($args[2], $args[1]);
$ret = call_user_func($f, $this->reduce($args, true), $this);
// convert to a typed value if the result is a php primitive
if (is_numeric($ret)) $ret = array(
); elseif (!is_array($ret)) $ret = array(
// plain function, reduce args
$value[2] = $this->reduce($value[2]);
list(, $op, $exp) = $value;
$exp = $this->reduce($exp);
if ($exp[0] == "number") {
if ($color = $this->coerceColor($value)) {
return $this->coerceColor($value);
// coerce a value for use in color operation
protected function coerceColor($value) {
$colorStr = substr($value[1], 1);
$num = hexdec($colorStr);
$width = strlen($colorStr) == 3 ? 16 : 256;
for ($i = 3; $i > 0; $i--) { // 3 2 1
$c[$i] = $t * (256 / $width) + $t * floor(16 / $width);
if (isset(self::$cssColors[$name])) {
$rgba = explode(',', self::$cssColors[$name]);
if (isset($rgba[3])) return array(