1<?php 2 3/** 4 * Builtin functions 5 * 6 * @package Less 7 * @subpackage function 8 * @see http://lesscss.org/functions/ 9 */ 10class Less_Functions { 11 12 public $env; 13 public $currentFileInfo; 14 15 function __construct( $env, $currentFileInfo = null ) { 16 $this->env = $env; 17 $this->currentFileInfo = $currentFileInfo; 18 } 19 20 /** 21 * @param string $op 22 */ 23 public static function operate( $op, $a, $b ) { 24 switch ( $op ) { 25 case '+': 26return $a + $b; 27 case '-': 28return $a - $b; 29 case '*': 30return $a * $b; 31 case '/': 32return $a / $b; 33 } 34 } 35 36 public static function clamp( $val, $max = 1 ) { 37 return min( max( $val, 0 ), $max ); 38 } 39 40 public static function fround( $value ) { 41 if ( $value === 0 ) { 42 return $value; 43 } 44 45 if ( Less_Parser::$options['numPrecision'] ) { 46 $p = pow( 10, Less_Parser::$options['numPrecision'] ); 47 return round( $value * $p ) / $p; 48 } 49 return $value; 50 } 51 52 public static function number( $n ) { 53 if ( $n instanceof Less_Tree_Dimension ) { 54 return floatval( $n->unit->is( '%' ) ? $n->value / 100 : $n->value ); 55 } else if ( is_numeric( $n ) ) { 56 return $n; 57 } else { 58 throw new Less_Exception_Compiler( "color functions take numbers as parameters" ); 59 } 60 } 61 62 public static function scaled( $n, $size = 255 ) { 63 if ( $n instanceof Less_Tree_Dimension && $n->unit->is( '%' ) ) { 64 return (float)$n->value * $size / 100; 65 } else { 66 return Less_Functions::number( $n ); 67 } 68 } 69 70 public function rgb( $r = null, $g = null, $b = null ) { 71 if ( is_null( $r ) || is_null( $g ) || is_null( $b ) ) { 72 throw new Less_Exception_Compiler( "rgb expects three parameters" ); 73 } 74 return $this->rgba( $r, $g, $b, 1.0 ); 75 } 76 77 public function rgba( $r = null, $g = null, $b = null, $a = null ) { 78 $rgb = array( $r, $g, $b ); 79 $rgb = array_map( array( 'Less_Functions','scaled' ), $rgb ); 80 81 $a = self::number( $a ); 82 return new Less_Tree_Color( $rgb, $a ); 83 } 84 85 public function hsl( $h, $s, $l ) { 86 return $this->hsla( $h, $s, $l, 1.0 ); 87 } 88 89 public function hsla( $h, $s, $l, $a ) { 90 $h = fmod( self::number( $h ), 360 ) / 360; // Classic % operator will change float to int 91 $s = self::clamp( self::number( $s ) ); 92 $l = self::clamp( self::number( $l ) ); 93 $a = self::clamp( self::number( $a ) ); 94 95 $m2 = $l <= 0.5 ? $l * ( $s + 1 ) : $l + $s - $l * $s; 96 97 $m1 = $l * 2 - $m2; 98 99 return $this->rgba( self::hsla_hue( $h + 1 / 3, $m1, $m2 ) * 255, 100 self::hsla_hue( $h, $m1, $m2 ) * 255, 101 self::hsla_hue( $h - 1 / 3, $m1, $m2 ) * 255, 102 $a ); 103 } 104 105 /** 106 * @param double $h 107 */ 108 public function hsla_hue( $h, $m1, $m2 ) { 109 $h = $h < 0 ? $h + 1 : ( $h > 1 ? $h - 1 : $h ); 110 if ( $h * 6 < 1 ) return $m1 + ( $m2 - $m1 ) * $h * 6; else if ( $h * 2 < 1 ) return $m2; else if ( $h * 3 < 2 ) return $m1 + ( $m2 - $m1 ) * ( 2 / 3 - $h ) * 6; else return $m1; 111 } 112 113 public function hsv( $h, $s, $v ) { 114 return $this->hsva( $h, $s, $v, 1.0 ); 115 } 116 117 /** 118 * @param double $a 119 */ 120 public function hsva( $h, $s, $v, $a ) { 121 $h = ( ( Less_Functions::number( $h ) % 360 ) / 360 ) * 360; 122 $s = Less_Functions::number( $s ); 123 $v = Less_Functions::number( $v ); 124 $a = Less_Functions::number( $a ); 125 126 $i = floor( ( $h / 60 ) % 6 ); 127 $f = ( $h / 60 ) - $i; 128 129 $vs = array( $v, 130 $v * ( 1 - $s ), 131 $v * ( 1 - $f * $s ), 132 $v * ( 1 - ( 1 - $f ) * $s ) ); 133 134 $perm = array( array( 0, 3, 1 ), 135 array( 2, 0, 1 ), 136 array( 1, 0, 3 ), 137 array( 1, 2, 0 ), 138 array( 3, 1, 0 ), 139 array( 0, 1, 2 ) ); 140 141 return $this->rgba( $vs[$perm[$i][0]] * 255, 142 $vs[$perm[$i][1]] * 255, 143 $vs[$perm[$i][2]] * 255, 144 $a ); 145 } 146 147 public function hue( $color = null ) { 148 if ( !$color instanceof Less_Tree_Color ) { 149 throw new Less_Exception_Compiler( 'The first argument to hue must be a color' . ( $color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 150 } 151 152 $c = $color->toHSL(); 153 return new Less_Tree_Dimension( Less_Parser::round( $c['h'] ) ); 154 } 155 156 public function saturation( $color = null ) { 157 if ( !$color instanceof Less_Tree_Color ) { 158 throw new Less_Exception_Compiler( 'The first argument to saturation must be a color' . ( $color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 159 } 160 161 $c = $color->toHSL(); 162 return new Less_Tree_Dimension( Less_Parser::round( $c['s'] * 100 ), '%' ); 163 } 164 165 public function lightness( $color = null ) { 166 if ( !$color instanceof Less_Tree_Color ) { 167 throw new Less_Exception_Compiler( 'The first argument to lightness must be a color' . ( $color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 168 } 169 170 $c = $color->toHSL(); 171 return new Less_Tree_Dimension( Less_Parser::round( $c['l'] * 100 ), '%' ); 172 } 173 174 public function hsvhue( $color = null ) { 175 if ( !$color instanceof Less_Tree_Color ) { 176 throw new Less_Exception_Compiler( 'The first argument to hsvhue must be a color' . ( $color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 177 } 178 179 $hsv = $color->toHSV(); 180 return new Less_Tree_Dimension( Less_Parser::round( $hsv['h'] ) ); 181 } 182 183 public function hsvsaturation( $color = null ) { 184 if ( !$color instanceof Less_Tree_Color ) { 185 throw new Less_Exception_Compiler( 'The first argument to hsvsaturation must be a color' . ( $color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 186 } 187 188 $hsv = $color->toHSV(); 189 return new Less_Tree_Dimension( Less_Parser::round( $hsv['s'] * 100 ), '%' ); 190 } 191 192 public function hsvvalue( $color = null ) { 193 if ( !$color instanceof Less_Tree_Color ) { 194 throw new Less_Exception_Compiler( 'The first argument to hsvvalue must be a color' . ( $color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 195 } 196 197 $hsv = $color->toHSV(); 198 return new Less_Tree_Dimension( Less_Parser::round( $hsv['v'] * 100 ), '%' ); 199 } 200 201 public function red( $color = null ) { 202 if ( !$color instanceof Less_Tree_Color ) { 203 throw new Less_Exception_Compiler( 'The first argument to red must be a color' . ( $color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 204 } 205 206 return new Less_Tree_Dimension( $color->rgb[0] ); 207 } 208 209 public function green( $color = null ) { 210 if ( !$color instanceof Less_Tree_Color ) { 211 throw new Less_Exception_Compiler( 'The first argument to green must be a color' . ( $color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 212 } 213 214 return new Less_Tree_Dimension( $color->rgb[1] ); 215 } 216 217 public function blue( $color = null ) { 218 if ( !$color instanceof Less_Tree_Color ) { 219 throw new Less_Exception_Compiler( 'The first argument to blue must be a color' . ( $color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 220 } 221 222 return new Less_Tree_Dimension( $color->rgb[2] ); 223 } 224 225 public function alpha( $color = null ) { 226 if ( !$color instanceof Less_Tree_Color ) { 227 throw new Less_Exception_Compiler( 'The first argument to alpha must be a color' . ( $color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 228 } 229 230 $c = $color->toHSL(); 231 return new Less_Tree_Dimension( $c['a'] ); 232 } 233 234 public function luma( $color = null ) { 235 if ( !$color instanceof Less_Tree_Color ) { 236 throw new Less_Exception_Compiler( 'The first argument to luma must be a color' . ( $color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 237 } 238 239 return new Less_Tree_Dimension( Less_Parser::round( $color->luma() * $color->alpha * 100 ), '%' ); 240 } 241 242 public function luminance( $color = null ) { 243 if ( !$color instanceof Less_Tree_Color ) { 244 throw new Less_Exception_Compiler( 'The first argument to luminance must be a color' . ( $color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 245 } 246 247 $luminance = 248 ( 0.2126 * $color->rgb[0] / 255 ) 249 + ( 0.7152 * $color->rgb[1] / 255 ) 250 + ( 0.0722 * $color->rgb[2] / 255 ); 251 252 return new Less_Tree_Dimension( Less_Parser::round( $luminance * $color->alpha * 100 ), '%' ); 253 } 254 255 public function saturate( $color = null, $amount = null ) { 256 // filter: saturate(3.2); 257 // should be kept as is, so check for color 258 if ( $color instanceof Less_Tree_Dimension ) { 259 return null; 260 } 261 262 if ( !$color instanceof Less_Tree_Color ) { 263 throw new Less_Exception_Compiler( 'The first argument to saturate must be a color' . ( $color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 264 } 265 if ( !$amount instanceof Less_Tree_Dimension ) { 266 throw new Less_Exception_Compiler( 'The second argument to saturate must be a percentage' . ( $amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 267 } 268 269 $hsl = $color->toHSL(); 270 271 $hsl['s'] += $amount->value / 100; 272 $hsl['s'] = self::clamp( $hsl['s'] ); 273 274 return $this->hsla( $hsl['h'], $hsl['s'], $hsl['l'], $hsl['a'] ); 275 } 276 277 /** 278 * @param Less_Tree_Dimension $amount 279 */ 280 public function desaturate( $color = null, $amount = null ) { 281 if ( !$color instanceof Less_Tree_Color ) { 282 throw new Less_Exception_Compiler( 'The first argument to desaturate must be a color' . ( $color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 283 } 284 if ( !$amount instanceof Less_Tree_Dimension ) { 285 throw new Less_Exception_Compiler( 'The second argument to desaturate must be a percentage' . ( $amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 286 } 287 288 $hsl = $color->toHSL(); 289 290 $hsl['s'] -= $amount->value / 100; 291 $hsl['s'] = self::clamp( $hsl['s'] ); 292 293 return $this->hsla( $hsl['h'], $hsl['s'], $hsl['l'], $hsl['a'] ); 294 } 295 296 public function lighten( $color = null, $amount = null ) { 297 if ( !$color instanceof Less_Tree_Color ) { 298 throw new Less_Exception_Compiler( 'The first argument to lighten must be a color' . ( $color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 299 } 300 if ( !$amount instanceof Less_Tree_Dimension ) { 301 throw new Less_Exception_Compiler( 'The second argument to lighten must be a percentage' . ( $amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 302 } 303 304 $hsl = $color->toHSL(); 305 306 $hsl['l'] += $amount->value / 100; 307 $hsl['l'] = self::clamp( $hsl['l'] ); 308 309 return $this->hsla( $hsl['h'], $hsl['s'], $hsl['l'], $hsl['a'] ); 310 } 311 312 public function darken( $color = null, $amount = null ) { 313 if ( !$color instanceof Less_Tree_Color ) { 314 throw new Less_Exception_Compiler( 'The first argument to darken must be a color' . ( $color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 315 } 316 if ( !$amount instanceof Less_Tree_Dimension ) { 317 throw new Less_Exception_Compiler( 'The second argument to darken must be a percentage' . ( $amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 318 } 319 320 $hsl = $color->toHSL(); 321 $hsl['l'] -= $amount->value / 100; 322 $hsl['l'] = self::clamp( $hsl['l'] ); 323 324 return $this->hsla( $hsl['h'], $hsl['s'], $hsl['l'], $hsl['a'] ); 325 } 326 327 public function fadein( $color = null, $amount = null ) { 328 if ( !$color instanceof Less_Tree_Color ) { 329 throw new Less_Exception_Compiler( 'The first argument to fadein must be a color' . ( $color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 330 } 331 if ( !$amount instanceof Less_Tree_Dimension ) { 332 throw new Less_Exception_Compiler( 'The second argument to fadein must be a percentage' . ( $amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 333 } 334 335 $hsl = $color->toHSL(); 336 $hsl['a'] += $amount->value / 100; 337 $hsl['a'] = self::clamp( $hsl['a'] ); 338 return $this->hsla( $hsl['h'], $hsl['s'], $hsl['l'], $hsl['a'] ); 339 } 340 341 public function fadeout( $color = null, $amount = null ) { 342 if ( !$color instanceof Less_Tree_Color ) { 343 throw new Less_Exception_Compiler( 'The first argument to fadeout must be a color' . ( $color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 344 } 345 if ( !$amount instanceof Less_Tree_Dimension ) { 346 throw new Less_Exception_Compiler( 'The second argument to fadeout must be a percentage' . ( $amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 347 } 348 349 $hsl = $color->toHSL(); 350 $hsl['a'] -= $amount->value / 100; 351 $hsl['a'] = self::clamp( $hsl['a'] ); 352 return $this->hsla( $hsl['h'], $hsl['s'], $hsl['l'], $hsl['a'] ); 353 } 354 355 public function fade( $color = null, $amount = null ) { 356 if ( !$color instanceof Less_Tree_Color ) { 357 throw new Less_Exception_Compiler( 'The first argument to fade must be a color' . ( $color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 358 } 359 if ( !$amount instanceof Less_Tree_Dimension ) { 360 throw new Less_Exception_Compiler( 'The second argument to fade must be a percentage' . ( $amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 361 } 362 363 $hsl = $color->toHSL(); 364 365 $hsl['a'] = $amount->value / 100; 366 $hsl['a'] = self::clamp( $hsl['a'] ); 367 return $this->hsla( $hsl['h'], $hsl['s'], $hsl['l'], $hsl['a'] ); 368 } 369 370 public function spin( $color = null, $amount = null ) { 371 if ( !$color instanceof Less_Tree_Color ) { 372 throw new Less_Exception_Compiler( 'The first argument to spin must be a color' . ( $color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 373 } 374 if ( !$amount instanceof Less_Tree_Dimension ) { 375 throw new Less_Exception_Compiler( 'The second argument to spin must be a number' . ( $amount instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 376 } 377 378 $hsl = $color->toHSL(); 379 $hue = fmod( $hsl['h'] + $amount->value, 360 ); 380 381 $hsl['h'] = $hue < 0 ? 360 + $hue : $hue; 382 383 return $this->hsla( $hsl['h'], $hsl['s'], $hsl['l'], $hsl['a'] ); 384 } 385 386 // 387 // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein 388 // http://sass-lang.com 389 // 390 391 /** 392 * @param Less_Tree_Color $color1 393 */ 394 public function mix( $color1 = null, $color2 = null, $weight = null ) { 395 if ( !$color1 instanceof Less_Tree_Color ) { 396 throw new Less_Exception_Compiler( 'The first argument to mix must be a color' . ( $color1 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 397 } 398 if ( !$color2 instanceof Less_Tree_Color ) { 399 throw new Less_Exception_Compiler( 'The second argument to mix must be a color' . ( $color2 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 400 } 401 if ( !$weight ) { 402 $weight = new Less_Tree_Dimension( '50', '%' ); 403 } 404 if ( !$weight instanceof Less_Tree_Dimension ) { 405 throw new Less_Exception_Compiler( 'The third argument to contrast must be a percentage' . ( $weight instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 406 } 407 408 $p = $weight->value / 100.0; 409 $w = $p * 2 - 1; 410 $hsl1 = $color1->toHSL(); 411 $hsl2 = $color2->toHSL(); 412 $a = $hsl1['a'] - $hsl2['a']; 413 414 $w1 = ( ( ( ( $w * $a ) == -1 ) ? $w : ( $w + $a ) / ( 1 + $w * $a ) ) + 1 ) / 2; 415 $w2 = 1 - $w1; 416 417 $rgb = array( $color1->rgb[0] * $w1 + $color2->rgb[0] * $w2, 418 $color1->rgb[1] * $w1 + $color2->rgb[1] * $w2, 419 $color1->rgb[2] * $w1 + $color2->rgb[2] * $w2 ); 420 421 $alpha = $color1->alpha * $p + $color2->alpha * ( 1 - $p ); 422 423 return new Less_Tree_Color( $rgb, $alpha ); 424 } 425 426 public function greyscale( $color ) { 427 return $this->desaturate( $color, new Less_Tree_Dimension( 100, '%' ) ); 428 } 429 430 public function contrast( $color, $dark = null, $light = null, $threshold = null ) { 431 // filter: contrast(3.2); 432 // should be kept as is, so check for color 433 if ( !$color instanceof Less_Tree_Color ) { 434 return null; 435 } 436 if ( !$light ) { 437 $light = $this->rgba( 255, 255, 255, 1.0 ); 438 } 439 if ( !$dark ) { 440 $dark = $this->rgba( 0, 0, 0, 1.0 ); 441 } 442 443 if ( !$dark instanceof Less_Tree_Color ) { 444 throw new Less_Exception_Compiler( 'The second argument to contrast must be a color' . ( $dark instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 445 } 446 if ( !$light instanceof Less_Tree_Color ) { 447 throw new Less_Exception_Compiler( 'The third argument to contrast must be a color' . ( $light instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 448 } 449 450 // Figure out which is actually light and dark! 451 if ( $dark->luma() > $light->luma() ) { 452 $t = $light; 453 $light = $dark; 454 $dark = $t; 455 } 456 if ( !$threshold ) { 457 $threshold = 0.43; 458 } else { 459 $threshold = Less_Functions::number( $threshold ); 460 } 461 462 if ( $color->luma() < $threshold ) { 463 return $light; 464 } else { 465 return $dark; 466 } 467 } 468 469 public function e( $str ) { 470 if ( is_string( $str ) ) { 471 return new Less_Tree_Anonymous( $str ); 472 } 473 return new Less_Tree_Anonymous( $str instanceof Less_Tree_JavaScript ? $str->expression : $str->value ); 474 } 475 476 public function escape( $str ) { 477 $revert = array( '%21' => '!', '%2A' => '*', '%27' => "'",'%3F' => '?','%26' => '&','%2C' => ',','%2F' => '/','%40' => '@','%2B' => '+','%24' => '$' ); 478 479 return new Less_Tree_Anonymous( strtr( rawurlencode( $str->value ), $revert ) ); 480 } 481 482 /** 483 * todo: This function will need some additional work to make it work the same as less.js 484 * 485 */ 486 public function replace( $string, $pattern, $replacement, $flags = null ) { 487 $result = $string->value; 488 489 $expr = '/'.str_replace( '/', '\\/', $pattern->value ).'/'; 490 if ( $flags && $flags->value ) { 491 $expr .= self::replace_flags( $flags->value ); 492 } 493 494 $result = preg_replace( $expr, $replacement->value, $result ); 495 496 if ( property_exists( $string, 'quote' ) ) { 497 return new Less_Tree_Quoted( $string->quote, $result, $string->escaped ); 498 } 499 return new Less_Tree_Quoted( '', $result ); 500 } 501 502 public static function replace_flags( $flags ) { 503 $flags = str_split( $flags, 1 ); 504 $new_flags = ''; 505 506 foreach ( $flags as $flag ) { 507 switch ( $flag ) { 508 case 'e': 509 case 'g': 510 break; 511 512 default: 513 $new_flags .= $flag; 514 break; 515 } 516 } 517 518 return $new_flags; 519 } 520 521 public function _percent() { 522 $string = func_get_arg( 0 ); 523 524 $args = func_get_args(); 525 array_shift( $args ); 526 $result = $string->value; 527 528 foreach ( $args as $arg ) { 529 if ( preg_match( '/%[sda]/i', $result, $token ) ) { 530 $token = $token[0]; 531 $value = stristr( $token, 's' ) ? $arg->value : $arg->toCSS(); 532 $value = preg_match( '/[A-Z]$/', $token ) ? urlencode( $value ) : $value; 533 $result = preg_replace( '/%[sda]/i', $value, $result, 1 ); 534 } 535 } 536 $result = str_replace( '%%', '%', $result ); 537 538 return new Less_Tree_Quoted( $string->quote, $result, $string->escaped ); 539 } 540 541 public function unit( $val, $unit = null ) { 542 if ( !( $val instanceof Less_Tree_Dimension ) ) { 543 throw new Less_Exception_Compiler( 'The first argument to unit must be a number' . ( $val instanceof Less_Tree_Operation ? '. Have you forgotten parenthesis?' : '.' ) ); 544 } 545 546 if ( $unit ) { 547 if ( $unit instanceof Less_Tree_Keyword ) { 548 $unit = $unit->value; 549 } else { 550 $unit = $unit->toCSS(); 551 } 552 } else { 553 $unit = ""; 554 } 555 return new Less_Tree_Dimension( $val->value, $unit ); 556 } 557 558 public function convert( $val, $unit ) { 559 return $val->convertTo( $unit->value ); 560 } 561 562 public function round( $n, $f = false ) { 563 $fraction = 0; 564 if ( $f !== false ) { 565 $fraction = $f->value; 566 } 567 568 return $this->_math( 'Less_Parser::round', null, $n, $fraction ); 569 } 570 571 public function pi() { 572 return new Less_Tree_Dimension( M_PI ); 573 } 574 575 public function mod( $a, $b ) { 576 return new Less_Tree_Dimension( $a->value % $b->value, $a->unit ); 577 } 578 579 public function pow( $x, $y ) { 580 if ( is_numeric( $x ) && is_numeric( $y ) ) { 581 $x = new Less_Tree_Dimension( $x ); 582 $y = new Less_Tree_Dimension( $y ); 583 } elseif ( !( $x instanceof Less_Tree_Dimension ) || !( $y instanceof Less_Tree_Dimension ) ) { 584 throw new Less_Exception_Compiler( 'Arguments must be numbers' ); 585 } 586 587 return new Less_Tree_Dimension( pow( $x->value, $y->value ), $x->unit ); 588 } 589 590 // var mathFunctions = [{name:"ce ... 591 public function ceil( $n ) { 592 return $this->_math( 'ceil', null, $n ); 593 } 594 595 public function floor( $n ) { 596 return $this->_math( 'floor', null, $n ); 597 } 598 599 public function sqrt( $n ) { 600 return $this->_math( 'sqrt', null, $n ); 601 } 602 603 public function abs( $n ) { 604 return $this->_math( 'abs', null, $n ); 605 } 606 607 public function tan( $n ) { 608 return $this->_math( 'tan', '', $n ); 609 } 610 611 public function sin( $n ) { 612 return $this->_math( 'sin', '', $n ); 613 } 614 615 public function cos( $n ) { 616 return $this->_math( 'cos', '', $n ); 617 } 618 619 public function atan( $n ) { 620 return $this->_math( 'atan', 'rad', $n ); 621 } 622 623 public function asin( $n ) { 624 return $this->_math( 'asin', 'rad', $n ); 625 } 626 627 public function acos( $n ) { 628 return $this->_math( 'acos', 'rad', $n ); 629 } 630 631 private function _math() { 632 $args = func_get_args(); 633 $fn = array_shift( $args ); 634 $unit = array_shift( $args ); 635 636 if ( $args[0] instanceof Less_Tree_Dimension ) { 637 638 if ( $unit === null ) { 639 $unit = $args[0]->unit; 640 } else { 641 $args[0] = $args[0]->unify(); 642 } 643 $args[0] = (float)$args[0]->value; 644 return new Less_Tree_Dimension( call_user_func_array( $fn, $args ), $unit ); 645 } else if ( is_numeric( $args[0] ) ) { 646 return call_user_func_array( $fn, $args ); 647 } else { 648 throw new Less_Exception_Compiler( "math functions take numbers as parameters" ); 649 } 650 } 651 652 /** 653 * @param boolean $isMin 654 */ 655 private function _minmax( $isMin, $args ) { 656 $arg_count = count( $args ); 657 658 if ( $arg_count < 1 ) { 659 throw new Less_Exception_Compiler( 'one or more arguments required' ); 660 } 661 662 $j = null; 663 $unitClone = null; 664 $unitStatic = null; 665 666 $order = array(); // elems only contains original argument values. 667 $values = array(); // key is the unit.toString() for unified tree.Dimension values, 668 // value is the index into the order array. 669 670 for ( $i = 0; $i < $arg_count; $i++ ) { 671 $current = $args[$i]; 672 if ( !( $current instanceof Less_Tree_Dimension ) ) { 673 if ( is_array( $args[$i]->value ) ) { 674 $args[] = $args[$i]->value; 675 } 676 continue; 677 } 678 679 if ( $current->unit->toString() === '' && !$unitClone ) { 680 $temp = new Less_Tree_Dimension( $current->value, $unitClone ); 681 $currentUnified = $temp->unify(); 682 } else { 683 $currentUnified = $current->unify(); 684 } 685 686 if ( $currentUnified->unit->toString() === "" && !$unitStatic ) { 687 $unit = $unitStatic; 688 } else { 689 $unit = $currentUnified->unit->toString(); 690 } 691 692 if ( $unit !== '' && !$unitStatic || $unit !== '' && $order[0]->unify()->unit->toString() === "" ) { 693 $unitStatic = $unit; 694 } 695 696 if ( $unit != '' && !$unitClone ) { 697 $unitClone = $current->unit->toString(); 698 } 699 700 if ( isset( $values[''] ) && $unit !== '' && $unit === $unitStatic ) { 701 $j = $values['']; 702 } elseif ( isset( $values[$unit] ) ) { 703 $j = $values[$unit]; 704 } else { 705 706 if ( $unitStatic && $unit !== $unitStatic ) { 707 throw new Less_Exception_Compiler( 'incompatible types' ); 708 } 709 $values[$unit] = count( $order ); 710 $order[] = $current; 711 continue; 712 } 713 714 if ( $order[$j]->unit->toString() === "" && $unitClone ) { 715 $temp = new Less_Tree_Dimension( $order[$j]->value, $unitClone ); 716 $referenceUnified = $temp->unify(); 717 } else { 718 $referenceUnified = $order[$j]->unify(); 719 } 720 if ( ( $isMin && $currentUnified->value < $referenceUnified->value ) || ( !$isMin && $currentUnified->value > $referenceUnified->value ) ) { 721 $order[$j] = $current; 722 } 723 } 724 725 if ( count( $order ) == 1 ) { 726 return $order[0]; 727 } 728 $args = array(); 729 foreach ( $order as $a ) { 730 $args[] = $a->toCSS( $this->env ); 731 } 732 return new Less_Tree_Anonymous( ( $isMin ? 'min(' : 'max(' ) . implode( Less_Environment::$_outputMap[','], $args ).')' ); 733 } 734 735 public function min() { 736 $args = func_get_args(); 737 return $this->_minmax( true, $args ); 738 } 739 740 public function max() { 741 $args = func_get_args(); 742 return $this->_minmax( false, $args ); 743 } 744 745 public function getunit( $n ) { 746 return new Less_Tree_Anonymous( $n->unit ); 747 } 748 749 public function argb( $color ) { 750 if ( !$color instanceof Less_Tree_Color ) { 751 throw new Less_Exception_Compiler( 'The first argument to argb must be a color' . ( $color instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 752 } 753 754 return new Less_Tree_Anonymous( $color->toARGB() ); 755 } 756 757 public function percentage( $n ) { 758 return new Less_Tree_Dimension( $n->value * 100, '%' ); 759 } 760 761 public function color( $n ) { 762 if ( $n instanceof Less_Tree_Quoted ) { 763 $colorCandidate = $n->value; 764 $returnColor = Less_Tree_Color::fromKeyword( $colorCandidate ); 765 if ( $returnColor ) { 766 return $returnColor; 767 } 768 if ( preg_match( '/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/', $colorCandidate ) ) { 769 return new Less_Tree_Color( substr( $colorCandidate, 1 ) ); 770 } 771 throw new Less_Exception_Compiler( "argument must be a color keyword or 3/6 digit hex e.g. #FFF" ); 772 } else { 773 throw new Less_Exception_Compiler( "argument must be a string" ); 774 } 775 } 776 777 public function iscolor( $n ) { 778 return $this->_isa( $n, 'Less_Tree_Color' ); 779 } 780 781 public function isnumber( $n ) { 782 return $this->_isa( $n, 'Less_Tree_Dimension' ); 783 } 784 785 public function isstring( $n ) { 786 return $this->_isa( $n, 'Less_Tree_Quoted' ); 787 } 788 789 public function iskeyword( $n ) { 790 return $this->_isa( $n, 'Less_Tree_Keyword' ); 791 } 792 793 public function isurl( $n ) { 794 return $this->_isa( $n, 'Less_Tree_Url' ); 795 } 796 797 public function ispixel( $n ) { 798 return $this->isunit( $n, 'px' ); 799 } 800 801 public function ispercentage( $n ) { 802 return $this->isunit( $n, '%' ); 803 } 804 805 public function isem( $n ) { 806 return $this->isunit( $n, 'em' ); 807 } 808 809 /** 810 * @param string $unit 811 */ 812 public function isunit( $n, $unit ) { 813 if ( is_object( $unit ) && property_exists( $unit, 'value' ) ) { 814 $unit = $unit->value; 815 } 816 817 return ( $n instanceof Less_Tree_Dimension ) && $n->unit->is( $unit ) ? new Less_Tree_Keyword( 'true' ) : new Less_Tree_Keyword( 'false' ); 818 } 819 820 /** 821 * @param string $type 822 */ 823 private function _isa( $n, $type ) { 824 return is_a( $n, $type ) ? new Less_Tree_Keyword( 'true' ) : new Less_Tree_Keyword( 'false' ); 825 } 826 827 public function tint( $color, $amount = null ) { 828 return $this->mix( $this->rgb( 255, 255, 255 ), $color, $amount ); 829 } 830 831 public function shade( $color, $amount = null ) { 832 return $this->mix( $this->rgb( 0, 0, 0 ), $color, $amount ); 833 } 834 835 public function extract( $values, $index ) { 836 $index = (int)$index->value - 1; // (1-based index) 837 // handle non-array values as an array of length 1 838 // return 'undefined' if index is invalid 839 if ( property_exists( $values, 'value' ) && is_array( $values->value ) ) { 840 if ( isset( $values->value[$index] ) ) { 841 return $values->value[$index]; 842 } 843 return null; 844 845 } elseif ( (int)$index === 0 ) { 846 return $values; 847 } 848 849 return null; 850 } 851 852 public function length( $values ) { 853 $n = ( property_exists( $values, 'value' ) && is_array( $values->value ) ) ? count( $values->value ) : 1; 854 return new Less_Tree_Dimension( $n ); 855 } 856 857 public function datauri( $mimetypeNode, $filePathNode = null ) { 858 $filePath = ( $filePathNode ? $filePathNode->value : null ); 859 $mimetype = $mimetypeNode->value; 860 861 $args = 2; 862 if ( !$filePath ) { 863 $filePath = $mimetype; 864 $args = 1; 865 } 866 867 $filePath = str_replace( '\\', '/', $filePath ); 868 if ( Less_Environment::isPathRelative( $filePath ) ) { 869 870 if ( Less_Parser::$options['relativeUrls'] ) { 871 $temp = $this->currentFileInfo['currentDirectory']; 872 } else { 873 $temp = $this->currentFileInfo['entryPath']; 874 } 875 876 if ( !empty( $temp ) ) { 877 $filePath = Less_Environment::normalizePath( rtrim( $temp, '/' ).'/'.$filePath ); 878 } 879 880 } 881 882 // detect the mimetype if not given 883 if ( $args < 2 ) { 884 885 /* incomplete 886 $mime = require('mime'); 887 mimetype = mime.lookup(path); 888 889 // use base 64 unless it's an ASCII or UTF-8 format 890 var charset = mime.charsets.lookup(mimetype); 891 useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0; 892 if (useBase64) mimetype += ';base64'; 893 */ 894 895 $mimetype = Less_Mime::lookup( $filePath ); 896 897 $charset = Less_Mime::charsets_lookup( $mimetype ); 898 $useBase64 = !in_array( $charset, array( 'US-ASCII', 'UTF-8' ) ); 899 if ( $useBase64 ) { $mimetype .= ';base64'; 900 } 901 902 } else { 903 $useBase64 = preg_match( '/;base64$/', $mimetype ); 904 } 905 906 if ( file_exists( $filePath ) ) { 907 $buf = @file_get_contents( $filePath ); 908 } else { 909 $buf = false; 910 } 911 912 // IE8 cannot handle a data-uri larger than 32KB. If this is exceeded 913 // and the --ieCompat flag is enabled, return a normal url() instead. 914 $DATA_URI_MAX_KB = 32; 915 $fileSizeInKB = round( strlen( $buf ) / 1024 ); 916 if ( $fileSizeInKB >= $DATA_URI_MAX_KB ) { 917 $url = new Less_Tree_Url( ( $filePathNode ? $filePathNode : $mimetypeNode ), $this->currentFileInfo ); 918 return $url->compile( $this ); 919 } 920 921 if ( $buf ) { 922 $buf = $useBase64 ? base64_encode( $buf ) : rawurlencode( $buf ); 923 $filePath = '"data:' . $mimetype . ',' . $buf . '"'; 924 } 925 926 return new Less_Tree_Url( new Less_Tree_Anonymous( $filePath ) ); 927 } 928 929 // svg-gradient 930 public function svggradient( $direction ) { 931 $throw_message = 'svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position]'; 932 $arguments = func_get_args(); 933 934 if ( count( $arguments ) < 3 ) { 935 throw new Less_Exception_Compiler( $throw_message ); 936 } 937 938 $stops = array_slice( $arguments, 1 ); 939 $gradientType = 'linear'; 940 $rectangleDimension = 'x="0" y="0" width="1" height="1"'; 941 $useBase64 = true; 942 $directionValue = $direction->toCSS(); 943 944 switch ( $directionValue ) { 945 case "to bottom": 946 $gradientDirectionSvg = 'x1="0%" y1="0%" x2="0%" y2="100%"'; 947 break; 948 case "to right": 949 $gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="0%"'; 950 break; 951 case "to bottom right": 952 $gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="100%"'; 953 break; 954 case "to top right": 955 $gradientDirectionSvg = 'x1="0%" y1="100%" x2="100%" y2="0%"'; 956 break; 957 case "ellipse": 958 case "ellipse at center": 959 $gradientType = "radial"; 960 $gradientDirectionSvg = 'cx="50%" cy="50%" r="75%"'; 961 $rectangleDimension = 'x="-50" y="-50" width="101" height="101"'; 962 break; 963 default: 964 throw new Less_Exception_Compiler( "svg-gradient direction must be 'to bottom', 'to right', 'to bottom right', 'to top right' or 'ellipse at center'" ); 965 } 966 967 $returner = '<?xml version="1.0" ?>' . 968 '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none">' . 969 '<' . $gradientType . 'Gradient id="gradient" gradientUnits="userSpaceOnUse" ' . $gradientDirectionSvg . '>'; 970 971 for ( $i = 0; $i < count( $stops ); $i++ ) { 972 if ( is_object( $stops[$i] ) && property_exists( $stops[$i], 'value' ) ) { 973 $color = $stops[$i]->value[0]; 974 $position = $stops[$i]->value[1]; 975 } else { 976 $color = $stops[$i]; 977 $position = null; 978 } 979 980 if ( !( $color instanceof Less_Tree_Color ) || ( !( ( $i === 0 || $i + 1 === count( $stops ) ) && $position === null ) && !( $position instanceof Less_Tree_Dimension ) ) ) { 981 throw new Less_Exception_Compiler( $throw_message ); 982 } 983 if ( $position ) { 984 $positionValue = $position->toCSS(); 985 } elseif ( $i === 0 ) { 986 $positionValue = '0%'; 987 } else { 988 $positionValue = '100%'; 989 } 990 $alpha = $color->alpha; 991 $returner .= '<stop offset="' . $positionValue . '" stop-color="' . $color->toRGB() . '"' . ( $alpha < 1 ? ' stop-opacity="' . $alpha . '"' : '' ) . '/>'; 992 } 993 994 $returner .= '</' . $gradientType . 'Gradient><rect ' . $rectangleDimension . ' fill="url(#gradient)" /></svg>'; 995 996 if ( $useBase64 ) { 997 $returner = "'data:image/svg+xml;base64,".base64_encode( $returner )."'"; 998 } else { 999 $returner = "'data:image/svg+xml,".$returner."'"; 1000 } 1001 1002 return new Less_Tree_URL( new Less_Tree_Anonymous( $returner ) ); 1003 } 1004 1005 /** 1006 * Php version of javascript's `encodeURIComponent` function 1007 * 1008 * @param string $string The string to encode 1009 * @return string The encoded string 1010 */ 1011 public static function encodeURIComponent( $string ) { 1012 $revert = array( '%21' => '!', '%2A' => '*', '%27' => "'", '%28' => '(', '%29' => ')' ); 1013 return strtr( rawurlencode( $string ), $revert ); 1014 } 1015 1016 // Color Blending 1017 // ref: http://www.w3.org/TR/compositing-1 1018 1019 public function colorBlend( $mode, $color1, $color2 ) { 1020 $ab = $color1->alpha; // backdrop 1021 $as = $color2->alpha; // source 1022 $r = array(); // result 1023 1024 $ar = $as + $ab * ( 1 - $as ); 1025 for ( $i = 0; $i < 3; $i++ ) { 1026 $cb = $color1->rgb[$i] / 255; 1027 $cs = $color2->rgb[$i] / 255; 1028 $cr = call_user_func( $mode, $cb, $cs ); 1029 if ( $ar ) { 1030 $cr = ( $as * $cs + $ab * ( $cb - $as * ( $cb + $cs - $cr ) ) ) / $ar; 1031 } 1032 $r[$i] = $cr * 255; 1033 } 1034 1035 return new Less_Tree_Color( $r, $ar ); 1036 } 1037 1038 public function multiply( $color1 = null, $color2 = null ) { 1039 if ( !$color1 instanceof Less_Tree_Color ) { 1040 throw new Less_Exception_Compiler( 'The first argument to multiply must be a color' . ( $color1 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 1041 } 1042 if ( !$color2 instanceof Less_Tree_Color ) { 1043 throw new Less_Exception_Compiler( 'The second argument to multiply must be a color' . ( $color2 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 1044 } 1045 1046 return $this->colorBlend( array( $this,'colorBlendMultiply' ), $color1, $color2 ); 1047 } 1048 1049 private function colorBlendMultiply( $cb, $cs ) { 1050 return $cb * $cs; 1051 } 1052 1053 public function screen( $color1 = null, $color2 = null ) { 1054 if ( !$color1 instanceof Less_Tree_Color ) { 1055 throw new Less_Exception_Compiler( 'The first argument to screen must be a color' . ( $color1 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 1056 } 1057 if ( !$color2 instanceof Less_Tree_Color ) { 1058 throw new Less_Exception_Compiler( 'The second argument to screen must be a color' . ( $color2 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 1059 } 1060 1061 return $this->colorBlend( array( $this,'colorBlendScreen' ), $color1, $color2 ); 1062 } 1063 1064 private function colorBlendScreen( $cb, $cs ) { 1065 return $cb + $cs - $cb * $cs; 1066 } 1067 1068 public function overlay( $color1 = null, $color2 = null ) { 1069 if ( !$color1 instanceof Less_Tree_Color ) { 1070 throw new Less_Exception_Compiler( 'The first argument to overlay must be a color' . ( $color1 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 1071 } 1072 if ( !$color2 instanceof Less_Tree_Color ) { 1073 throw new Less_Exception_Compiler( 'The second argument to overlay must be a color' . ( $color2 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 1074 } 1075 1076 return $this->colorBlend( array( $this,'colorBlendOverlay' ), $color1, $color2 ); 1077 } 1078 1079 private function colorBlendOverlay( $cb, $cs ) { 1080 $cb *= 2; 1081 return ( $cb <= 1 ) 1082 ? $this->colorBlendMultiply( $cb, $cs ) 1083 : $this->colorBlendScreen( $cb - 1, $cs ); 1084 } 1085 1086 public function softlight( $color1 = null, $color2 = null ) { 1087 if ( !$color1 instanceof Less_Tree_Color ) { 1088 throw new Less_Exception_Compiler( 'The first argument to softlight must be a color' . ( $color1 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 1089 } 1090 if ( !$color2 instanceof Less_Tree_Color ) { 1091 throw new Less_Exception_Compiler( 'The second argument to softlight must be a color' . ( $color2 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 1092 } 1093 1094 return $this->colorBlend( array( $this,'colorBlendSoftlight' ), $color1, $color2 ); 1095 } 1096 1097 private function colorBlendSoftlight( $cb, $cs ) { 1098 $d = 1; 1099 $e = $cb; 1100 if ( $cs > 0.5 ) { 1101 $e = 1; 1102 $d = ( $cb > 0.25 ) ? sqrt( $cb ) 1103 : ( ( 16 * $cb - 12 ) * $cb + 4 ) * $cb; 1104 } 1105 return $cb - ( 1 - 2 * $cs ) * $e * ( $d - $cb ); 1106 } 1107 1108 public function hardlight( $color1 = null, $color2 = null ) { 1109 if ( !$color1 instanceof Less_Tree_Color ) { 1110 throw new Less_Exception_Compiler( 'The first argument to hardlight must be a color' . ( $color1 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 1111 } 1112 if ( !$color2 instanceof Less_Tree_Color ) { 1113 throw new Less_Exception_Compiler( 'The second argument to hardlight must be a color' . ( $color2 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 1114 } 1115 1116 return $this->colorBlend( array( $this,'colorBlendHardlight' ), $color1, $color2 ); 1117 } 1118 1119 private function colorBlendHardlight( $cb, $cs ) { 1120 return $this->colorBlendOverlay( $cs, $cb ); 1121 } 1122 1123 public function difference( $color1 = null, $color2 = null ) { 1124 if ( !$color1 instanceof Less_Tree_Color ) { 1125 throw new Less_Exception_Compiler( 'The first argument to difference must be a color' . ( $color1 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 1126 } 1127 if ( !$color2 instanceof Less_Tree_Color ) { 1128 throw new Less_Exception_Compiler( 'The second argument to difference must be a color' . ( $color2 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 1129 } 1130 1131 return $this->colorBlend( array( $this,'colorBlendDifference' ), $color1, $color2 ); 1132 } 1133 1134 private function colorBlendDifference( $cb, $cs ) { 1135 return abs( $cb - $cs ); 1136 } 1137 1138 public function exclusion( $color1 = null, $color2 = null ) { 1139 if ( !$color1 instanceof Less_Tree_Color ) { 1140 throw new Less_Exception_Compiler( 'The first argument to exclusion must be a color' . ( $color1 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 1141 } 1142 if ( !$color2 instanceof Less_Tree_Color ) { 1143 throw new Less_Exception_Compiler( 'The second argument to exclusion must be a color' . ( $color2 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 1144 } 1145 1146 return $this->colorBlend( array( $this,'colorBlendExclusion' ), $color1, $color2 ); 1147 } 1148 1149 private function colorBlendExclusion( $cb, $cs ) { 1150 return $cb + $cs - 2 * $cb * $cs; 1151 } 1152 1153 public function average( $color1 = null, $color2 = null ) { 1154 if ( !$color1 instanceof Less_Tree_Color ) { 1155 throw new Less_Exception_Compiler( 'The first argument to average must be a color' . ( $color1 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 1156 } 1157 if ( !$color2 instanceof Less_Tree_Color ) { 1158 throw new Less_Exception_Compiler( 'The second argument to average must be a color' . ( $color2 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 1159 } 1160 1161 return $this->colorBlend( array( $this,'colorBlendAverage' ), $color1, $color2 ); 1162 } 1163 1164 // non-w3c functions: 1165 public function colorBlendAverage( $cb, $cs ) { 1166 return ( $cb + $cs ) / 2; 1167 } 1168 1169 public function negation( $color1 = null, $color2 = null ) { 1170 if ( !$color1 instanceof Less_Tree_Color ) { 1171 throw new Less_Exception_Compiler( 'The first argument to negation must be a color' . ( $color1 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 1172 } 1173 if ( !$color2 instanceof Less_Tree_Color ) { 1174 throw new Less_Exception_Compiler( 'The second argument to negation must be a color' . ( $color2 instanceof Less_Tree_Expression ? ' (did you forgot commas?)' : '' ) ); 1175 } 1176 1177 return $this->colorBlend( array( $this,'colorBlendNegation' ), $color1, $color2 ); 1178 } 1179 1180 public function colorBlendNegation( $cb, $cs ) { 1181 return 1 - abs( $cb + $cs - 1 ); 1182 } 1183 1184 // ~ End of Color Blending 1185 1186} 1187