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