Functions.php 37 KB

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