[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/lib/lessphp/ -> Functions.php (source)

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


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1