Functions.php 38 KB

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