This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /* |
||
4 | * This file is part of the ILess |
||
5 | * |
||
6 | * For the full copyright and license information, please view the LICENSE |
||
7 | * file that was distributed with this source code. |
||
8 | */ |
||
9 | |||
10 | namespace ILess; |
||
11 | |||
12 | use Exception; |
||
13 | use ILess\Exception\CompilerException; |
||
14 | use ILess\Exception\FunctionException; |
||
15 | use ILess\Exception\IOException; |
||
16 | use ILess\Node\AnonymousNode; |
||
17 | use ILess\Node\ColorNode; |
||
18 | use ILess\Node\CommentNode; |
||
19 | use ILess\Node\DimensionNode; |
||
20 | use ILess\Node\ExpressionNode; |
||
21 | use ILess\Node\KeywordNode; |
||
22 | use ILess\Node\UrlNode; |
||
23 | use ILess\Node\UnitNode; |
||
24 | use ILess\Node\ToColorConvertibleInterface; |
||
25 | use ILess\Node\QuotedNode; |
||
26 | use ILess\Node\OperationNode; |
||
27 | use ILess\Util\Mime; |
||
28 | use InvalidArgumentException; |
||
29 | use RuntimeException; |
||
30 | |||
31 | /** |
||
32 | * Function registry. |
||
33 | * |
||
34 | * @see http://lesscss.org/#reference |
||
35 | */ |
||
36 | class FunctionRegistry |
||
37 | { |
||
38 | /** |
||
39 | * Maximum allowed size of data uri for IE8. |
||
40 | */ |
||
41 | const IE8_DATA_URI_MAX = 32768; |
||
42 | |||
43 | /** |
||
44 | * Less environment. |
||
45 | * |
||
46 | * @var Context |
||
47 | */ |
||
48 | protected $context; |
||
49 | |||
50 | /** |
||
51 | * Array of function aliases. |
||
52 | * |
||
53 | * @var array |
||
54 | */ |
||
55 | protected $aliases = [ |
||
56 | '%' => 'template', |
||
57 | 'data-uri' => 'dataUri', |
||
58 | 'get-unit' => 'getunit', |
||
59 | 'svg-gradient' => 'svggradient', |
||
60 | 'default' => 'defaultFunc', |
||
61 | 'image-size' => 'imageSize', |
||
62 | 'image-width' => 'imageWidth', |
||
63 | 'image-height' => 'imageHeight', |
||
64 | ]; |
||
65 | |||
66 | /** |
||
67 | * @var FileInfo |
||
68 | */ |
||
69 | protected $currentFileInfo; |
||
70 | |||
71 | /** |
||
72 | * @var FunctionRegistry |
||
73 | */ |
||
74 | private $parent; |
||
75 | |||
76 | /** |
||
77 | * Array of callable functions. |
||
78 | * |
||
79 | * @var array |
||
80 | */ |
||
81 | private $functions = [ |
||
82 | 'abs' => true, |
||
83 | 'acos' => true, |
||
84 | 'alpha' => true, |
||
85 | 'argb' => true, |
||
86 | 'asin' => true, |
||
87 | 'atan' => true, |
||
88 | 'average' => true, |
||
89 | 'blue' => true, |
||
90 | 'call' => true, |
||
91 | 'ceil' => true, |
||
92 | 'clamp' => true, |
||
93 | 'color' => true, |
||
94 | 'contrast' => true, |
||
95 | 'convert' => true, |
||
96 | 'cos' => true, |
||
97 | 'darken' => true, |
||
98 | 'dataUri' => true, |
||
99 | 'desaturate' => true, |
||
100 | 'difference' => true, |
||
101 | 'e' => true, |
||
102 | 'escape' => true, |
||
103 | 'exclusion' => true, |
||
104 | 'extract' => true, |
||
105 | 'fade' => true, |
||
106 | 'fadein' => true, |
||
107 | 'fadeout' => true, |
||
108 | 'floor' => true, |
||
109 | 'green' => true, |
||
110 | 'greyscale' => true, |
||
111 | 'hardlight' => true, |
||
112 | 'hsl' => true, |
||
113 | 'hsla' => true, |
||
114 | 'hsv' => true, |
||
115 | 'hsva' => true, |
||
116 | 'hsvhue' => true, |
||
117 | 'hsvsaturation' => true, |
||
118 | 'hsvvalue' => true, |
||
119 | 'hue' => true, |
||
120 | 'iscolor' => true, |
||
121 | 'isem' => true, |
||
122 | 'iskeyword' => true, |
||
123 | 'isnumber' => true, |
||
124 | 'ispercentage' => true, |
||
125 | 'ispixel' => true, |
||
126 | 'isstring' => true, |
||
127 | 'isunit' => true, |
||
128 | 'isurl' => true, |
||
129 | 'isruleset' => true, |
||
130 | 'length' => true, |
||
131 | 'lighten' => true, |
||
132 | 'lightness' => true, |
||
133 | 'luma' => true, |
||
134 | 'luminance' => true, |
||
135 | 'max' => true, |
||
136 | 'min' => true, |
||
137 | 'mix' => true, |
||
138 | 'mod' => true, |
||
139 | 'multiply' => true, |
||
140 | 'negation' => true, |
||
141 | 'number' => true, |
||
142 | 'overlay' => true, |
||
143 | 'percentage' => true, |
||
144 | 'pi' => true, |
||
145 | 'pow' => true, |
||
146 | 'red' => true, |
||
147 | 'replace' => true, |
||
148 | 'rgb' => true, |
||
149 | 'rgba' => true, |
||
150 | 'round' => true, |
||
151 | 'saturate' => true, |
||
152 | 'saturation' => true, |
||
153 | 'screen' => true, |
||
154 | 'shade' => true, |
||
155 | 'sin' => true, |
||
156 | 'softlight' => true, |
||
157 | 'spin' => true, |
||
158 | 'sqrt' => true, |
||
159 | 'svggradient' => true, |
||
160 | 'tan' => true, |
||
161 | 'template' => true, |
||
162 | 'tint' => true, |
||
163 | 'unit' => true, |
||
164 | 'getunit' => true, |
||
165 | 'defaultFunc' => true, |
||
166 | 'imageSize' => true, |
||
167 | 'imageWidth' => true, |
||
168 | 'imageHeight' => true, |
||
169 | ]; |
||
170 | |||
171 | /** |
||
172 | * Constructor. |
||
173 | * |
||
174 | * @param array $aliases Array of function aliases in the format array(alias => function) |
||
175 | * @param Context $context The context |
||
176 | */ |
||
177 | public function __construct($aliases = [], Context $context = null) |
||
178 | { |
||
179 | $this->context = $context; |
||
180 | $this->addAliases($aliases); |
||
181 | } |
||
182 | |||
183 | /** |
||
184 | * @param FileInfo $file |
||
185 | * |
||
186 | * @return $this |
||
187 | */ |
||
188 | public function setCurrentFile(FileInfo $file) |
||
189 | { |
||
190 | $this->currentFileInfo = $file; |
||
191 | |||
192 | return $this; |
||
193 | } |
||
194 | |||
195 | /** |
||
196 | * Adds a function to the functions. |
||
197 | * |
||
198 | * @param string $functionName |
||
199 | * @param callable $callable |
||
200 | * @param string|array $aliases The array of aliases |
||
201 | * |
||
202 | * @return FunctionRegistry |
||
203 | * |
||
204 | * @throws InvalidArgumentException If the callable is not valid |
||
205 | */ |
||
206 | public function addFunction($functionName, $callable, $aliases = []) |
||
207 | { |
||
208 | if (!is_callable($callable, null, $callableName)) { |
||
209 | throw new InvalidArgumentException( |
||
210 | sprintf('The callable "%s" for function "%s" is not valid.', $callableName, $functionName) |
||
211 | ); |
||
212 | } |
||
213 | |||
214 | // all functions are case insensitive |
||
215 | $functionName = strtolower($functionName); |
||
216 | |||
217 | $this->functions[$functionName] = $callable; |
||
218 | |||
219 | if (!is_array($aliases)) { |
||
220 | $aliases = [$aliases]; |
||
221 | } |
||
222 | |||
223 | foreach ($aliases as $alias) { |
||
224 | $this->addAlias($alias, $functionName); |
||
225 | } |
||
226 | |||
227 | return $this; |
||
228 | } |
||
229 | |||
230 | /** |
||
231 | * Adds functions. |
||
232 | * |
||
233 | * <pre> |
||
234 | * $registry->addFunctions(array('name' => function() {})); |
||
235 | * $registry->addFunctions(array(array('name' => 'load', 'callable' => 'load')); |
||
236 | * $registry->addFunctions(array(array('name' => 'load', 'callable' => 'load', 'alias' => 'l')); |
||
237 | * </pre> |
||
238 | * |
||
239 | * @param array $functions Array of functions |
||
240 | * |
||
241 | * @return FunctionRegistry |
||
242 | */ |
||
243 | public function addFunctions(array $functions) |
||
244 | { |
||
245 | foreach ($functions as $key => $function) { |
||
246 | if (is_numeric($key)) { |
||
247 | $this->addFunction( |
||
248 | $function['name'], |
||
249 | $function['callable'], |
||
250 | isset($function['alias']) ? $function['alias'] : [] |
||
251 | ); |
||
252 | } else { |
||
253 | // alternative syntax without aliases |
||
254 | $this->addFunction($key, $function); |
||
255 | } |
||
256 | } |
||
257 | |||
258 | return $this; |
||
259 | } |
||
260 | |||
261 | /** |
||
262 | * Sets the parent registry. |
||
263 | * |
||
264 | * @param FunctionRegistry $parent |
||
265 | * |
||
266 | * @return $this |
||
267 | */ |
||
268 | public function setParent(FunctionRegistry $parent) |
||
269 | { |
||
270 | // verify |
||
271 | if ($parent === $this) { |
||
272 | throw new RuntimeException('Invalid parent registry. The parent is the same object.'); |
||
273 | } |
||
274 | |||
275 | $this->parent = $parent; |
||
276 | |||
277 | return $this; |
||
278 | } |
||
279 | |||
280 | /** |
||
281 | * Loads a plugin from given path. |
||
282 | * |
||
283 | * @param string $path |
||
284 | * |
||
285 | * @return $this |
||
286 | * |
||
287 | * @throws RuntimeException |
||
288 | */ |
||
289 | public function loadPlugin($path) |
||
290 | { |
||
291 | if (!is_readable($path)) { |
||
292 | throw new RuntimeException( |
||
293 | sprintf('The plugin cannot be loaded. The given file "%s" does not exist or is not readable', $path) |
||
294 | ); |
||
295 | } |
||
296 | |||
297 | // FIXME: what about security? |
||
298 | // FIXME: php syntax check? |
||
299 | require $path; |
||
300 | |||
301 | return $this; |
||
302 | } |
||
303 | |||
304 | /** |
||
305 | * Clones the registry and setups the parent. |
||
306 | * |
||
307 | * @return FunctionRegistry |
||
308 | */ |
||
309 | public function inherit() |
||
310 | { |
||
311 | $new = clone $this; |
||
312 | |||
313 | $new->setParent($this); |
||
314 | |||
315 | return $new; |
||
316 | } |
||
317 | |||
318 | /** |
||
319 | * Returns names of registered functions. |
||
320 | * |
||
321 | * @return array |
||
322 | */ |
||
323 | public function getFunctions() |
||
324 | { |
||
325 | return array_keys($this->functions); |
||
326 | } |
||
327 | |||
328 | /** |
||
329 | * Does the function exist? |
||
330 | * |
||
331 | * @param string $name |
||
332 | * |
||
333 | * @return bool |
||
334 | */ |
||
335 | public function hasFunction($name) |
||
336 | { |
||
337 | $name = strtolower($name); |
||
338 | |||
339 | return isset($this->functions[$name]) || isset($this->aliases[$name]); |
||
340 | } |
||
341 | |||
342 | /** |
||
343 | * Returns aliases for registered functions. |
||
344 | * |
||
345 | * @param bool $withFunctions Include function names? |
||
346 | * |
||
347 | * @return array |
||
348 | */ |
||
349 | public function getAliases($withFunctions = false) |
||
350 | { |
||
351 | return $withFunctions ? $this->aliases : array_keys($this->aliases); |
||
352 | } |
||
353 | |||
354 | /** |
||
355 | * Adds a function alias. |
||
356 | * |
||
357 | * @param string $alias The alias name |
||
358 | * @param string $function The function name |
||
359 | * |
||
360 | * @return FunctionRegistry |
||
361 | */ |
||
362 | public function addAlias($alias, $function) |
||
363 | { |
||
364 | $functionLower = strtolower($function); |
||
365 | if (!isset($this->functions[$functionLower])) { |
||
366 | throw new InvalidArgumentException( |
||
367 | sprintf('Invalid alias "%s" for "%s" given. The "%s" does not exist.', $alias, $function) |
||
368 | ); |
||
369 | } |
||
370 | $this->aliases[strtolower($alias)] = $functionLower; |
||
371 | |||
372 | return $this; |
||
373 | } |
||
374 | |||
375 | /** |
||
376 | * Adds aliases. |
||
377 | * |
||
378 | * @param array $aliases |
||
379 | * |
||
380 | * @return FunctionRegistry |
||
381 | */ |
||
382 | public function addAliases(array $aliases) |
||
383 | { |
||
384 | foreach ($aliases as $alias => $function) { |
||
385 | $this->addAlias($alias, $function); |
||
386 | } |
||
387 | |||
388 | return $this; |
||
389 | } |
||
390 | |||
391 | /** |
||
392 | * Sets The context. |
||
393 | * |
||
394 | * @param Context $context |
||
395 | */ |
||
396 | public function setEnvironment(Context $context) |
||
397 | { |
||
398 | $this->context = $context; |
||
399 | } |
||
400 | |||
401 | /** |
||
402 | * Returns the context instance. |
||
403 | * |
||
404 | * @return mixed |
||
405 | */ |
||
406 | public function getContext() |
||
407 | { |
||
408 | return $this->context; |
||
409 | } |
||
410 | |||
411 | /** |
||
412 | * Calls a method with given arguments. |
||
413 | * |
||
414 | * @param string $methodName |
||
415 | * @param array $arguments |
||
416 | * |
||
417 | * @return mixed |
||
418 | * |
||
419 | * @throws FunctionException If the method does not exist |
||
420 | */ |
||
421 | public function call($methodName, $arguments = []) |
||
422 | { |
||
423 | $methodName = strtolower($methodName); |
||
424 | |||
425 | if (isset($this->aliases[$methodName])) { |
||
426 | $methodName = $this->aliases[$methodName]; |
||
427 | } |
||
428 | |||
429 | if (isset($this->functions[$methodName])) { |
||
430 | $arguments = $this->prepareArguments($arguments); |
||
431 | |||
432 | if ($this->functions[$methodName] === true) { |
||
433 | // built in function |
||
434 | return call_user_func_array([$this, $methodName], $arguments); |
||
435 | } else { |
||
436 | // this is a external callable |
||
437 | // provide access to function registry (pass as first parameter) |
||
438 | array_unshift($arguments, $this); |
||
439 | |||
440 | return call_user_func_array($this->functions[$methodName], $arguments); |
||
441 | } |
||
442 | } else { |
||
443 | if ($this->parent) { |
||
444 | return $this->parent->call($methodName, $arguments); |
||
445 | } |
||
446 | } |
||
447 | } |
||
448 | |||
449 | /** |
||
450 | * Prepares the arguments before function calls. |
||
451 | * This does the same as in less.js's functionCaller object. |
||
452 | * |
||
453 | * @param array $arguments |
||
454 | * |
||
455 | * @return array |
||
456 | */ |
||
457 | protected function prepareArguments(array $arguments) |
||
458 | { |
||
459 | $return = array_filter( |
||
460 | $arguments, |
||
461 | function ($item) { |
||
462 | if ($item instanceof CommentNode) { |
||
463 | return false; |
||
464 | } |
||
465 | |||
466 | return true; |
||
467 | } |
||
468 | ); |
||
469 | |||
470 | $return = array_map( |
||
471 | function (&$item) { |
||
472 | if ($item instanceof ExpressionNode) { |
||
473 | $subNodes = array_filter( |
||
474 | $item->value, |
||
475 | function ($i) { |
||
476 | if ($i instanceof CommentNode) { |
||
477 | return false; |
||
478 | } |
||
479 | |||
480 | return true; |
||
481 | } |
||
482 | ); |
||
483 | if (count($subNodes) === 1) { |
||
484 | return $subNodes[0]; |
||
485 | } else { |
||
486 | return new ExpressionNode($subNodes); |
||
487 | } |
||
488 | } |
||
489 | |||
490 | return $item; |
||
491 | }, |
||
492 | $return |
||
493 | ); |
||
494 | |||
495 | return $return; |
||
496 | } |
||
497 | |||
498 | /** |
||
499 | * Applies URL-encoding to special characters found in the input string. |
||
500 | * |
||
501 | * * Following characters are exceptions and not encoded: `,, /, ?, @, &, +, ', ~, ! $` |
||
502 | * * Most common encoded characters are: `<space>`, #, ^, (, ), {, }, |, :, >, <, ;, ], [ =` |
||
503 | * |
||
504 | * @param Node $string A string to escape |
||
505 | * |
||
506 | * @return AnonymousNode Escaped string content without quotes. |
||
507 | */ |
||
508 | public function escape(Node $string) |
||
509 | { |
||
510 | return new AnonymousNode(urlencode((string) $string)); |
||
511 | } |
||
512 | |||
513 | /** |
||
514 | * CSS escaping similar to ~"value" syntax. It expects string as a parameter and return |
||
515 | * its content as is, but without quotes. It can be used to output CSS value which is either not valid CSS syntax, |
||
516 | * or uses proprietary syntax which LESS doesn't recognize. |
||
517 | * |
||
518 | * @param string $string A string to escape |
||
519 | * |
||
520 | * @return AnonymousNode Content without quotes. |
||
521 | */ |
||
522 | public function e(Node $string) |
||
523 | { |
||
524 | return new AnonymousNode(str_replace(['~"', '"'], '', (string) $string)); |
||
525 | } |
||
526 | |||
527 | /** |
||
528 | * Returns the number of items. |
||
529 | * |
||
530 | * @param Node $values |
||
531 | * |
||
532 | * @return DimensionNode |
||
533 | */ |
||
534 | public function length(Node $values) |
||
535 | { |
||
536 | return new DimensionNode(is_array($values->value) ? count($values->value) : 1); |
||
537 | } |
||
538 | |||
539 | /** |
||
540 | * Min. |
||
541 | * |
||
542 | * @return DimensionNode |
||
543 | */ |
||
544 | public function min() |
||
545 | { |
||
546 | return $this->doMinmax(true, func_get_args()); |
||
547 | } |
||
548 | |||
549 | /** |
||
550 | * Max. |
||
551 | * |
||
552 | * @return DimensionNode |
||
553 | */ |
||
554 | public function max() |
||
555 | { |
||
556 | return $this->doMinmax(false, func_get_args()); |
||
557 | } |
||
558 | |||
559 | /** |
||
560 | * Extract. |
||
561 | * |
||
562 | * @param Node $node |
||
563 | * @param Node $index |
||
564 | * |
||
565 | * @return null|Node |
||
566 | */ |
||
567 | public function extract(Node $node, Node $index) |
||
568 | { |
||
569 | $index = (int) $index->value - 1; // (1-based index) |
||
570 | $values = $this->getItemsFromNode($node); |
||
571 | if (isset($values[$index])) { |
||
572 | return $values[$index]; |
||
573 | } |
||
574 | |||
575 | return; |
||
576 | } |
||
577 | |||
578 | /** |
||
579 | * @param Node $node |
||
580 | * |
||
581 | * @return array |
||
582 | */ |
||
583 | private function getItemsFromNode(Node $node) |
||
584 | { |
||
585 | // handle non-array values as an array of length 1 |
||
586 | // return 'undefined' if index is invalid |
||
587 | if (is_array($node->value)) { |
||
588 | $items = $node->value; |
||
589 | } else { |
||
590 | $items = [$node]; |
||
591 | } |
||
592 | |||
593 | // reset array keys! |
||
594 | return array_values($items); |
||
595 | } |
||
596 | |||
597 | /** |
||
598 | * Formats a string. Less equivalent is: `%`. |
||
599 | * The first argument is string with placeholders. |
||
600 | * All placeholders start with percentage symbol % followed by letter s,S,d,D,a, or A. |
||
601 | * Remaining arguments contain expressions to replace placeholders. |
||
602 | * If you need to print the percentage symbol, escape it by another percentage %%.*. |
||
603 | * |
||
604 | * @param Node $string |
||
605 | * |
||
606 | * @return QuotedNode |
||
607 | */ |
||
608 | public function template(Node $string /* , $value1, $value2, ... */) |
||
609 | { |
||
610 | $args = func_get_args(); |
||
611 | array_shift($args); |
||
612 | |||
613 | $result = $string->value; |
||
614 | foreach ($args as $arg) { |
||
615 | if (preg_match('/%[sda]/i', $result, $token)) { |
||
616 | $token = $token[0]; |
||
617 | |||
618 | if ($arg instanceof QuotedNode && stristr($token, 's')) { |
||
619 | $value = $arg->value; |
||
620 | } else { |
||
621 | $value = $arg->toCSS($this->context); |
||
622 | } |
||
623 | |||
624 | $value = preg_match('/[A-Z]$/', $token) ? Util::encodeURIComponent($value) : $value; |
||
625 | $result = preg_replace('/%[sda]/i', $value, $result, 1); |
||
626 | } |
||
627 | } |
||
628 | $result = str_replace('%%', '%', $result); |
||
629 | |||
630 | return new QuotedNode( |
||
631 | isset($string->quote) ? $string->quote : '', |
||
632 | $result, |
||
633 | isset($string->escaped) ? $string->escaped : true |
||
634 | ); |
||
635 | } |
||
636 | |||
637 | /** |
||
638 | * Replaces a string or regexp pattern within a string. |
||
639 | * |
||
640 | * @param Node $string The string to search and replace in. |
||
641 | * @param Node $pattern A string or regular expression pattern to search for. |
||
642 | * @param Node $replacement The string to replace the matched pattern with. |
||
643 | * @param Node $flags (Optional) regular expression flags. |
||
644 | * |
||
645 | * @return QuotedNode |
||
646 | * |
||
647 | * @see http://lesscss.org/functions/#string-functions-replace |
||
648 | */ |
||
649 | public function replace(Node $string, Node $pattern, Node $replacement, Node $flags = null) |
||
650 | { |
||
651 | $result = $string->value; |
||
652 | |||
653 | if ($replacement instanceof QuotedNode) { |
||
654 | $replacement = $replacement->value; |
||
655 | } else { |
||
656 | $replacement = $replacement->toCSS($this->context); |
||
657 | } |
||
658 | |||
659 | $limit = 1; |
||
660 | // we have some flags |
||
661 | if ($flags) { |
||
662 | $flags = $flags->value; |
||
663 | // global replacement |
||
664 | $global = strpos($flags, 'g') !== false; |
||
665 | // strip js php non compatible flags |
||
666 | $flags = str_replace('g', '', $flags); |
||
667 | if ($global) { |
||
668 | $limit = -1; |
||
669 | } |
||
670 | } else { |
||
671 | $flags = ''; |
||
672 | } |
||
673 | |||
674 | // we cannot use preg_quote here, since the expression is already quoted in less.js |
||
675 | $regexp = str_replace('/', '\\/', $pattern->value); |
||
676 | $result = preg_replace('/' . $regexp . '/' . $flags, $replacement, $result, $limit); |
||
677 | |||
678 | return new QuotedNode( |
||
679 | isset($string->quote) ? $string->quote : '', |
||
680 | $result, |
||
0 ignored issues
–
show
|
|||
681 | isset($string->escaped) ? $string->escaped : true |
||
682 | ); |
||
683 | } |
||
684 | |||
685 | /** |
||
686 | * Inlines a resource and falls back to url() if the ieCompat option is on |
||
687 | * and the resource is too large, or if you use the function in the browser. |
||
688 | * If the mime is not given then node uses the mime package to determine the correct mime type. |
||
689 | * |
||
690 | * @param Node $mimeType A mime type string |
||
691 | * @param Node $url The URL of the file to inline. |
||
692 | * |
||
693 | * @return UrlNode |
||
694 | * |
||
695 | * @throws IOException |
||
696 | */ |
||
697 | public function dataUri(Node $mimeType, Node $filePath = null) |
||
698 | { |
||
699 | if (func_num_args() < 2) { |
||
700 | $path = $mimeType->value; |
||
701 | $mime = false; // we will detect it later |
||
702 | } else { |
||
703 | $path = $filePath->value; |
||
704 | $mime = $mimeType->value; |
||
705 | } |
||
706 | |||
707 | $path = $this->getFilePath($path); |
||
708 | list($fragment, $path) = Util::getFragmentAndPath($path); |
||
709 | |||
710 | if ($mime === false) { |
||
711 | $mime = Mime::lookup($path); |
||
712 | if ($mime === 'image/svg+xml') { |
||
713 | $useBase64 = false; |
||
714 | } else { |
||
715 | // use base 64 unless it's an ASCII or UTF-8 format |
||
716 | $charset = Mime::charsetsLookup($mime); |
||
717 | $useBase64 = !in_array($charset, ['US-ASCII', 'UTF-8']); |
||
718 | } |
||
719 | if ($useBase64) { |
||
720 | $mime .= ';base64'; |
||
721 | } |
||
722 | } else { |
||
723 | $useBase64 = (bool) preg_match('/;base64$/', $mime); |
||
724 | } |
||
725 | |||
726 | // the file was not found |
||
727 | // FIXME: warn |
||
728 | if (!is_readable($path)) { |
||
729 | $url = new UrlNode( |
||
730 | ($filePath ? $filePath : $mimeType), |
||
731 | 0, // FIXME: we don't have access to current index here! |
||
732 | $this->context->currentFileInfo |
||
733 | ); |
||
734 | |||
735 | return $url->compile($this->context); |
||
736 | } |
||
737 | |||
738 | $buffer = file_get_contents($path); |
||
739 | $buffer = $useBase64 ? base64_encode($buffer) : Util::encodeURIComponent($buffer); |
||
740 | |||
741 | $uri = 'data:' . $mime . ',' . $buffer . $fragment; |
||
742 | |||
743 | // IE8 cannot handle a data-uri larger than 32KB. If this is exceeded |
||
744 | // and the ieCompat option is enabled, return normal url() instead. |
||
745 | if ($this->context->ieCompat) { |
||
746 | if (strlen($uri) >= self::IE8_DATA_URI_MAX) { |
||
747 | // FIXME: warn that we cannot use data uri here |
||
748 | // FIXME: we don't have access to current index here! |
||
749 | $url = new UrlNode(($filePath ? $filePath : $mimeType)); |
||
750 | |||
751 | return $url->compile($this->context); |
||
752 | } |
||
753 | } |
||
754 | |||
755 | // FIXME: we don't have any information about current index here! |
||
756 | return new UrlNode(new QuotedNode('"' . $uri . '"', $uri, false)); |
||
757 | } |
||
758 | |||
759 | /** |
||
760 | * Rounds up to an integer. |
||
761 | * |
||
762 | * @param Node $number |
||
763 | * |
||
764 | * @return DimensionNode |
||
765 | */ |
||
766 | public function ceil($number) |
||
767 | { |
||
768 | return new DimensionNode(ceil($this->number($number)), $number->unit); |
||
0 ignored issues
–
show
$number is of type object<ILess\Node> , but the function expects a object<ILess\Node\DimensionNode>|integer|double .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
769 | } |
||
770 | |||
771 | /** |
||
772 | * Rounds down to an integer. |
||
773 | * |
||
774 | * @param Node $number |
||
775 | * |
||
776 | * @return Node |
||
777 | */ |
||
778 | public function floor($number) |
||
779 | { |
||
780 | return $this->doMath('floor', $number); |
||
781 | } |
||
782 | |||
783 | /** |
||
784 | * Converts to a %, e.g. 0.5 -> 50%. |
||
785 | * |
||
786 | * @param Node $number |
||
787 | * |
||
788 | * @return DimensionNode |
||
789 | */ |
||
790 | public function percentage(Node $number) |
||
791 | { |
||
792 | return $this->doMath(function ($n) { |
||
793 | return $n * 100; |
||
794 | }, $number, '%'); |
||
795 | } |
||
796 | |||
797 | /** |
||
798 | * Rounds a number to a number of places. |
||
799 | * |
||
800 | * @param string|Node $number The number to round |
||
801 | * @param int $places The precision |
||
802 | * |
||
803 | * @return DimensionNode |
||
804 | */ |
||
805 | public function round($number, DimensionNode $places = null) |
||
806 | { |
||
807 | if ($number instanceof DimensionNode) { |
||
808 | $unit = $number->unit; |
||
809 | $number = $number->value; |
||
810 | } else { |
||
811 | $unit = null; |
||
812 | } |
||
813 | |||
814 | $rounded = round(floatval($number), $places ? $places->value : 0); |
||
815 | |||
816 | return new DimensionNode($rounded, $unit); |
||
817 | } |
||
818 | |||
819 | /** |
||
820 | * Calculates square root of a number. |
||
821 | * |
||
822 | * @param mixed $number |
||
823 | * |
||
824 | * @return mixed |
||
825 | */ |
||
826 | public function sqrt($number) |
||
827 | { |
||
828 | return $this->doMath('sqrt', $number); |
||
829 | } |
||
830 | |||
831 | /** |
||
832 | * Absolute value of a number. |
||
833 | * |
||
834 | * @param mixed $number The number |
||
835 | * |
||
836 | * @return mixed |
||
837 | */ |
||
838 | public function abs($number) |
||
839 | { |
||
840 | return $this->doMath('abs', $number); |
||
841 | } |
||
842 | |||
843 | /** |
||
844 | * Sine function. |
||
845 | * |
||
846 | * @param string $number The number |
||
847 | * |
||
848 | * @return mixed |
||
849 | */ |
||
850 | public function sin($number) |
||
851 | { |
||
852 | return $this->doMath('sin', $number, ''); |
||
853 | } |
||
854 | |||
855 | /** |
||
856 | * Arcsine - inverse of sine function. |
||
857 | * |
||
858 | * @param string $number |
||
859 | * |
||
860 | * @return mixed |
||
861 | */ |
||
862 | public function asin($number) |
||
863 | { |
||
864 | return $this->doMath('asin', $number, 'rad'); |
||
865 | } |
||
866 | |||
867 | /** |
||
868 | * Cosine function. |
||
869 | * |
||
870 | * @param string $number |
||
871 | * |
||
872 | * @return mixed |
||
873 | */ |
||
874 | public function cos($number) |
||
875 | { |
||
876 | return $this->doMath('cos', $number, ''); |
||
877 | } |
||
878 | |||
879 | /** |
||
880 | * Arc cosine - inverse of cosine function. |
||
881 | * |
||
882 | * @param string $number |
||
883 | * |
||
884 | * @return mixed |
||
885 | */ |
||
886 | public function acos($number) |
||
887 | { |
||
888 | return $this->doMath('acos', $number, 'rad'); |
||
889 | } |
||
890 | |||
891 | /** |
||
892 | * Tangent function. |
||
893 | * |
||
894 | * @param mixed $number |
||
895 | * |
||
896 | * @return mixed |
||
897 | */ |
||
898 | public function tan($number) |
||
899 | { |
||
900 | return $this->doMath('tan', $number, ''); |
||
901 | } |
||
902 | |||
903 | /** |
||
904 | * Arc tangent - inverse of tangent function. |
||
905 | * |
||
906 | * @param mixed $number |
||
907 | * |
||
908 | * @return mixed |
||
909 | */ |
||
910 | public function atan($number) |
||
911 | { |
||
912 | return $this->doMath('atan', $number, 'rad'); |
||
913 | } |
||
914 | |||
915 | /** |
||
916 | * Does the math using Math. |
||
917 | * |
||
918 | * @param string $func The math function like sqrt, floor... |
||
919 | * @param DimensionNode|int $number The number |
||
920 | * @param UnitNode|string $unit The unit |
||
921 | * @param mixed ...$argument1 Argument for the mathematical function |
||
922 | * @param mixed ...$argument2 Argument for the mathematical function |
||
923 | * |
||
924 | * @return mixed |
||
925 | * |
||
926 | * @throws CompilerException |
||
927 | */ |
||
928 | protected function doMath($func, $number, $unit = null /*, $arguments...*/) |
||
929 | { |
||
930 | $arguments = []; |
||
931 | if (func_num_args() > 3) { |
||
932 | foreach (func_get_args() as $i => $arg) { |
||
933 | // skip first 3 arguments |
||
934 | if ($i < 3) { |
||
935 | continue; |
||
936 | } |
||
937 | $arguments[] = $arg; |
||
938 | } |
||
939 | } |
||
940 | |||
941 | if ($number instanceof DimensionNode) { |
||
942 | if ($unit === null) { |
||
943 | $unit = $number->unit; |
||
944 | } else { |
||
945 | $number = $number->unify(); |
||
946 | } |
||
947 | $number = floatval($number->value); |
||
948 | |||
949 | array_unshift($arguments, $number); |
||
950 | |||
951 | return new DimensionNode(call_user_func_array($func, $arguments), $unit); |
||
952 | } elseif (is_numeric($number)) { |
||
953 | array_unshift($arguments, $number); |
||
954 | |||
955 | return call_user_func_array($func, $arguments); |
||
956 | } |
||
957 | |||
958 | throw new CompilerException('argument must be a number'); |
||
959 | } |
||
960 | |||
961 | /** |
||
962 | * Returns pi. |
||
963 | * |
||
964 | * @return DimensionNode |
||
965 | */ |
||
966 | public function pi() |
||
967 | { |
||
968 | return new DimensionNode(M_PI); |
||
969 | } |
||
970 | |||
971 | /** |
||
972 | * First argument raised to the power of the second argument. |
||
973 | * |
||
974 | * @param Node $number |
||
975 | * @param Node $exponent |
||
976 | * |
||
977 | * @throws CompilerException |
||
978 | * |
||
979 | * @return DimensionNode |
||
980 | */ |
||
981 | public function pow($number, $exponent) |
||
982 | { |
||
983 | if (is_numeric($number) && is_numeric($exponent)) { |
||
984 | $number = new DimensionNode($number); |
||
985 | $exponent = new DimensionNode($exponent); |
||
986 | } elseif (!($number instanceof DimensionNode) |
||
987 | || !($exponent instanceof DimensionNode) |
||
988 | ) { |
||
989 | throw new CompilerException('Arguments must be numbers.'); |
||
990 | } |
||
991 | |||
992 | return new DimensionNode(pow($number->value, $exponent->value), $number->unit); |
||
993 | } |
||
994 | |||
995 | /** |
||
996 | * First argument modulus second argument. |
||
997 | * |
||
998 | * @param DimensionNode $number1 |
||
999 | * @param DimensionNode $number2 |
||
1000 | * |
||
1001 | * @return DimensionNode |
||
1002 | */ |
||
1003 | public function mod(DimensionNode $number1, DimensionNode $number2) |
||
1004 | { |
||
1005 | return new DimensionNode($number1->value % $number2->value, $number1->unit); |
||
1006 | } |
||
1007 | |||
1008 | /** |
||
1009 | * Converts between number types. |
||
1010 | * |
||
1011 | * @param DimensionNode $number |
||
1012 | * @param Node $units |
||
1013 | * |
||
1014 | * @return DimensionNode|null |
||
1015 | */ |
||
1016 | public function convert(Node $number, Node $units) |
||
1017 | { |
||
1018 | if (!$number instanceof DimensionNode) { |
||
1019 | return; |
||
1020 | } |
||
1021 | |||
1022 | return $number->convertTo($units->value); |
||
0 ignored issues
–
show
It seems like
$units->value can also be of type object<ILess\Node> ; however, ILess\Node\DimensionNode::convertTo() does only seem to accept array|string , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
1023 | } |
||
1024 | |||
1025 | /** |
||
1026 | * Changes number units without converting it. |
||
1027 | * |
||
1028 | * @param Node $number The dimension |
||
1029 | * @param Node $unit The unit |
||
1030 | * |
||
1031 | * @throws CompilerException |
||
1032 | * |
||
1033 | * @return DimensionNode |
||
1034 | */ |
||
1035 | public function unit(Node $number, Node $unit = null) |
||
1036 | { |
||
1037 | if (!$number instanceof DimensionNode) { |
||
1038 | throw new CompilerException( |
||
1039 | sprintf( |
||
1040 | 'The first argument to unit must be a number%s', |
||
1041 | ($number instanceof OperationNode ? '. Have you forgotten parenthesis?' : '.') |
||
1042 | ) |
||
1043 | ); |
||
1044 | } |
||
1045 | |||
1046 | if ($unit) { |
||
1047 | if ($unit instanceof KeywordNode) { |
||
1048 | $unit = $unit->value; |
||
1049 | } else { |
||
1050 | $unit = $unit->toCSS($this->context); |
||
1051 | } |
||
1052 | } else { |
||
1053 | $unit = ''; |
||
1054 | } |
||
1055 | |||
1056 | return new DimensionNode($number->value, $unit); |
||
0 ignored issues
–
show
It seems like
$number->value can also be of type object<ILess\Node> ; however, ILess\Node\DimensionNode::__construct() does only seem to accept string , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() It seems like
$unit defined by $unit->value on line 1048 can also be of type object<ILess\Node> ; however, ILess\Node\DimensionNode::__construct() does only seem to accept object<ILess\Node\UnitNode>|string|null , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
1057 | } |
||
1058 | |||
1059 | /** |
||
1060 | * Returns units of a number. |
||
1061 | * |
||
1062 | * @param DimensionNode $node |
||
1063 | * |
||
1064 | * @return AnonymousNode |
||
1065 | * |
||
1066 | * @see http://lesscss.org/functions/#misc-functions-get-unit |
||
1067 | */ |
||
1068 | public function getunit(DimensionNode $node) |
||
1069 | { |
||
1070 | return new AnonymousNode($node->unit); |
||
1071 | } |
||
1072 | |||
1073 | /** |
||
1074 | * Converts string or escaped value into color. |
||
1075 | * |
||
1076 | * @param Node $string |
||
1077 | * |
||
1078 | * @throws CompilerException |
||
1079 | * @returns ColorNode |
||
1080 | */ |
||
1081 | public function color(Node $string) |
||
1082 | { |
||
1083 | if ($string instanceof QuotedNode && |
||
1084 | preg_match('/^#([a-f0-9]{6}|[a-f0-9]{3})$/i', $string->value) |
||
1085 | ) { |
||
1086 | return new ColorNode(substr($string->value, 1)); |
||
1087 | } |
||
1088 | |||
1089 | if ($string instanceof ColorNode) { |
||
1090 | // remove keyword, so the color is not output as `plum` but in hex code |
||
1091 | $string->value->keyword = null; |
||
1092 | |||
1093 | return $string; |
||
1094 | } else { |
||
1095 | if (Color::isNamedColor($string->value)) { |
||
0 ignored issues
–
show
It seems like
$string->value can also be of type object<ILess\Node> ; however, ILess\Color::isNamedColor() does only seem to accept string , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
1096 | return new ColorNode(Color::color($string->value)); |
||
0 ignored issues
–
show
It seems like
$string->value can also be of type object<ILess\Node> ; however, ILess\Color::color() does only seem to accept string , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
1097 | } |
||
1098 | } |
||
1099 | |||
1100 | throw new CompilerException('Argument must be a color keyword or 3/6 digit hex e.g. #FFF'); |
||
1101 | } |
||
1102 | |||
1103 | /** |
||
1104 | * Converts to a color. |
||
1105 | * |
||
1106 | * @param Node|int $red The red component of a color |
||
1107 | * @param Node|int $green The green component of a color |
||
1108 | * @param Node|int $blue The blue component of a color |
||
1109 | * |
||
1110 | * @return ColorNode |
||
1111 | */ |
||
1112 | public function rgb($red, $green, $blue) |
||
1113 | { |
||
1114 | return $this->rgba($red, $green, $blue, 1); |
||
0 ignored issues
–
show
It seems like
$red defined by parameter $red on line 1112 can also be of type integer ; however, ILess\FunctionRegistry::rgba() does only seem to accept object<ILess\Node> , maybe add an additional type check?
This check looks at variables that have been passed in as parameters and are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() It seems like
$green defined by parameter $green on line 1112 can also be of type integer ; however, ILess\FunctionRegistry::rgba() does only seem to accept object<ILess\Node> , maybe add an additional type check?
This check looks at variables that have been passed in as parameters and are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() It seems like
$blue defined by parameter $blue on line 1112 can also be of type integer ; however, ILess\FunctionRegistry::rgba() does only seem to accept object<ILess\Node> , maybe add an additional type check?
This check looks at variables that have been passed in as parameters and are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
1115 | } |
||
1116 | |||
1117 | /** |
||
1118 | * Converts to a color. |
||
1119 | * |
||
1120 | * @param Node $red The red component of a color |
||
1121 | * @param Node $green The green component of a color |
||
1122 | * @param Node $blue The blue component of a color |
||
1123 | * @param Node|float $alpha The alpha channel |
||
1124 | * |
||
1125 | * @return ColorNode |
||
1126 | */ |
||
1127 | public function rgba($red, $green, $blue, $alpha) |
||
1128 | { |
||
1129 | $rgb = array_map([$this, 'scaled'], [$red, $green, $blue]); |
||
1130 | |||
1131 | return new ColorNode($rgb, $this->number($alpha)); |
||
0 ignored issues
–
show
It seems like
$alpha defined by parameter $alpha on line 1127 can also be of type object<ILess\Node> ; however, ILess\FunctionRegistry::number() does only seem to accept object<ILess\Node\DimensionNode>|integer|double , maybe add an additional type check?
This check looks at variables that have been passed in as parameters and are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
1132 | } |
||
1133 | |||
1134 | /** |
||
1135 | * Scales the number to percentage. |
||
1136 | * |
||
1137 | * @param DimensionNode $n The number |
||
1138 | * @param int $size |
||
1139 | * |
||
1140 | * @return float |
||
1141 | */ |
||
1142 | protected function scaled($n, $size = 255) |
||
1143 | { |
||
1144 | if ($n instanceof DimensionNode && $n->unit->is('%')) { |
||
1145 | return $n->value * $size / 100; |
||
1146 | } else { |
||
1147 | return $this->number($n); |
||
1148 | } |
||
1149 | } |
||
1150 | |||
1151 | /** |
||
1152 | * Converts the $number to "real" number. |
||
1153 | * |
||
1154 | * @param DimensionNode|int|float $number |
||
1155 | * |
||
1156 | * @return float |
||
1157 | * |
||
1158 | * @throws InvalidArgumentException |
||
1159 | */ |
||
1160 | public function number($number) |
||
1161 | { |
||
1162 | if ($number instanceof DimensionNode) { |
||
1163 | return $number->unit->is('%') ? $number->value / 100 : $number->value; |
||
1164 | } elseif (is_numeric($number)) { |
||
1165 | return $number; |
||
1166 | } else { |
||
1167 | throw new InvalidArgumentException( |
||
1168 | sprintf('Color functions take numbers as parameters. "%s" given.', gettype($number)) |
||
1169 | ); |
||
1170 | } |
||
1171 | } |
||
1172 | |||
1173 | /** |
||
1174 | * Creates a `#AARRGGBB`. |
||
1175 | * |
||
1176 | * @param Color $color The color |
||
1177 | * |
||
1178 | * @return AnonymousNode |
||
1179 | */ |
||
1180 | public function argb(Node $color) |
||
1181 | { |
||
1182 | if (!$color instanceof ColorNode) { |
||
1183 | return $color; |
||
1184 | } |
||
1185 | |||
1186 | return new AnonymousNode($color->toARGB()); |
||
1187 | } |
||
1188 | |||
1189 | /** |
||
1190 | * Creates a color. |
||
1191 | * |
||
1192 | * @param Node $hue The hue |
||
1193 | * @param Node $saturation The saturation |
||
1194 | * @param Node $lightness The lightness |
||
1195 | * |
||
1196 | * @return ColorNode |
||
1197 | */ |
||
1198 | public function hsl($hue, $saturation, $lightness) |
||
1199 | { |
||
1200 | return $this->hsla($hue, $saturation, $lightness, 1); |
||
1201 | } |
||
1202 | |||
1203 | /** |
||
1204 | * Creates a color from hsla color namespace. |
||
1205 | * |
||
1206 | * @param mixed $hue |
||
1207 | * @param mixed $saturation |
||
1208 | * @param mixed $lightness |
||
1209 | * @param mixed $alpha |
||
1210 | * |
||
1211 | * @return ColorNode |
||
1212 | */ |
||
1213 | public function hsla($hue, $saturation, $lightness, $alpha) |
||
1214 | { |
||
1215 | $hue = fmod($this->number($hue), 360) / 360; // Classic % operator will change float to int |
||
1216 | $saturation = $this->clamp($this->number($saturation)); |
||
1217 | $lightness = $this->clamp($this->number($lightness)); |
||
1218 | $alpha = $this->clamp($this->number($alpha)); |
||
1219 | |||
1220 | $m2 = $lightness <= 0.5 ? $lightness * ($saturation + 1) : $lightness + $saturation - $lightness * $saturation; |
||
1221 | $m1 = $lightness * 2 - $m2; |
||
1222 | |||
1223 | return $this->rgba( |
||
1224 | $this->hslaHue($hue + 1 / 3, $m1, $m2) * 255, |
||
0 ignored issues
–
show
$this->hslaHue($hue + 1 / 3, $m1, $m2) * 255 is of type double , but the function expects a object<ILess\Node> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
1225 | $this->hslaHue($hue, $m1, $m2) * 255, |
||
0 ignored issues
–
show
$this->hslaHue($hue, $m1, $m2) * 255 is of type double , but the function expects a object<ILess\Node> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
1226 | $this->hslaHue($hue - 1 / 3, $m1, $m2) * 255, |
||
0 ignored issues
–
show
$this->hslaHue($hue - 1 / 3, $m1, $m2) * 255 is of type double , but the function expects a object<ILess\Node> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
1227 | $alpha |
||
1228 | ); |
||
1229 | } |
||
1230 | |||
1231 | /** |
||
1232 | * Helper for hsla(). |
||
1233 | * |
||
1234 | * @param float $h |
||
1235 | * @param float $m1 |
||
1236 | * @param float $m2 |
||
1237 | * |
||
1238 | * @return float |
||
1239 | */ |
||
1240 | protected function hslaHue($h, $m1, $m2) |
||
1241 | { |
||
1242 | $h = $h < 0 ? $h + 1 : ($h > 1 ? $h - 1 : $h); |
||
1243 | if ($h * 6 < 1) { |
||
1244 | return $m1 + ($m2 - $m1) * $h * 6; |
||
1245 | } elseif ($h * 2 < 1) { |
||
1246 | return $m2; |
||
1247 | } elseif ($h * 3 < 2) { |
||
1248 | return $m1 + ($m2 - $m1) * (2 / 3 - $h) * 6; |
||
1249 | } |
||
1250 | |||
1251 | return $m1; |
||
1252 | } |
||
1253 | |||
1254 | /** |
||
1255 | * Creates a color. |
||
1256 | * |
||
1257 | * @param int $hue The hue |
||
1258 | * @param int $saturation The saturation |
||
1259 | * @param int $value The value |
||
1260 | */ |
||
1261 | public function hsv($hue, $saturation, $value) |
||
1262 | { |
||
1263 | return $this->hsva($hue, $saturation, $value, 1); |
||
1264 | } |
||
1265 | |||
1266 | /** |
||
1267 | * Creates a color. |
||
1268 | * |
||
1269 | * @param int $hue The hue |
||
1270 | * @param int $saturation The saturation |
||
1271 | * @param int $value The value |
||
1272 | * @param int $alpha The alpha channel |
||
1273 | */ |
||
1274 | public function hsva($hue, $saturation, $value, $alpha) |
||
1275 | { |
||
1276 | $hue = (($this->number($hue) % 360) / 360) * 360; |
||
1277 | $saturation = $this->number($saturation); |
||
1278 | $value = $this->number($value); |
||
1279 | $alpha = $this->number($alpha); |
||
1280 | |||
1281 | $i = floor(($hue / 60) % 6); |
||
1282 | $f = ($hue / 60) - $i; |
||
1283 | |||
1284 | $vs = [ |
||
1285 | $value, |
||
1286 | $value * (1 - $saturation), |
||
1287 | $value * (1 - $f * $saturation), |
||
1288 | $value * (1 - (1 - $f) * $saturation), |
||
1289 | ]; |
||
1290 | |||
1291 | $perm = [ |
||
1292 | [0, 3, 1], |
||
1293 | [2, 0, 1], |
||
1294 | [1, 0, 3], |
||
1295 | [1, 2, 0], |
||
1296 | [3, 1, 0], |
||
1297 | [0, 1, 2], |
||
1298 | ]; |
||
1299 | |||
1300 | return $this->rgba( |
||
1301 | $vs[$perm[$i][0]] * 255, |
||
0 ignored issues
–
show
$vs[$perm[$i][0]] * 255 is of type integer|double , but the function expects a object<ILess\Node> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
1302 | $vs[$perm[$i][1]] * 255, |
||
0 ignored issues
–
show
$vs[$perm[$i][1]] * 255 is of type integer|double , but the function expects a object<ILess\Node> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
1303 | $vs[$perm[$i][2]] * 255, |
||
0 ignored issues
–
show
$vs[$perm[$i][2]] * 255 is of type integer|double , but the function expects a object<ILess\Node> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
1304 | $alpha |
||
1305 | ); |
||
1306 | } |
||
1307 | |||
1308 | /** |
||
1309 | * Returns the `hue` channel of the $color in the HSL space. |
||
1310 | * |
||
1311 | * @param ColorNode $color |
||
1312 | * |
||
1313 | * @return DimensionNode |
||
1314 | */ |
||
1315 | public function hue(ColorNode $color) |
||
1316 | { |
||
1317 | return $color->getHue(); |
||
1318 | } |
||
1319 | |||
1320 | /** |
||
1321 | * Returns the `saturation` channel of the $color in the HSL space. |
||
1322 | * |
||
1323 | * @param ColorNode $color |
||
1324 | * |
||
1325 | * @return DimensionNode |
||
1326 | */ |
||
1327 | public function saturation(ColorNode $color) |
||
1328 | { |
||
1329 | return $color->getSaturation(); |
||
1330 | } |
||
1331 | |||
1332 | /** |
||
1333 | * Returns the 'lightness' channel of @color in the HSL space. |
||
1334 | * |
||
1335 | * @param ColorNode $color |
||
1336 | * |
||
1337 | * @return DimensionNode |
||
1338 | */ |
||
1339 | public function lightness(ColorNode $color) |
||
1340 | { |
||
1341 | return $color->getLightness(); |
||
1342 | } |
||
1343 | |||
1344 | /** |
||
1345 | * Returns the `hue` channel of @color in the HSV space. |
||
1346 | * |
||
1347 | * @param ColorNode $color |
||
1348 | * |
||
1349 | * @return string |
||
1350 | */ |
||
1351 | public function hsvhue(Node $color) |
||
1352 | { |
||
1353 | if (!$color instanceof ColorNode) { |
||
1354 | return $color; |
||
1355 | } |
||
1356 | $hsv = $color->toHSV(); |
||
1357 | |||
1358 | return new DimensionNode(Math::round($hsv['h'])); |
||
1359 | } |
||
1360 | |||
1361 | /** |
||
1362 | * Returns the `saturation` channel of @color in the HSV space. |
||
1363 | * |
||
1364 | * @param ColorNode $color |
||
1365 | * |
||
1366 | * @return string |
||
1367 | */ |
||
1368 | public function hsvsaturation(Node $color) |
||
1369 | { |
||
1370 | if (!$color instanceof ColorNode) { |
||
1371 | return $color; |
||
1372 | } |
||
1373 | $hsv = $color->toHSV(); |
||
1374 | |||
1375 | return new DimensionNode(Math::round($hsv['s'] * 100), '%'); |
||
1376 | } |
||
1377 | |||
1378 | /** |
||
1379 | * Returns the 'value' channel of @color in the HSV space. |
||
1380 | * |
||
1381 | * @param ColorNode $color |
||
1382 | * |
||
1383 | * @return string |
||
1384 | */ |
||
1385 | public function hsvvalue(Node $color) |
||
1386 | { |
||
1387 | if (!$color instanceof ColorNode) { |
||
1388 | return $color; |
||
1389 | } |
||
1390 | $hsv = $color->toHSV(); |
||
1391 | |||
1392 | return new DimensionNode(Math::round($hsv['v'] * 100), '%'); |
||
1393 | } |
||
1394 | |||
1395 | /** |
||
1396 | * Returns the 'red' channel of @color. |
||
1397 | * |
||
1398 | * @param ColorNode $color |
||
1399 | * |
||
1400 | * @return string |
||
1401 | */ |
||
1402 | public function red(ColorNode $color) |
||
1403 | { |
||
1404 | return $color->getRed(); |
||
1405 | } |
||
1406 | |||
1407 | /** |
||
1408 | * Returns the 'green' channel of @color. |
||
1409 | * |
||
1410 | * @param ColorNode $color |
||
1411 | * |
||
1412 | * @return string |
||
1413 | */ |
||
1414 | public function green(ColorNode $color) |
||
1415 | { |
||
1416 | return $color->getGreen(); |
||
1417 | } |
||
1418 | |||
1419 | /** |
||
1420 | * Returns the 'blue' channel of @color. |
||
1421 | * |
||
1422 | * @param ColorNode $color |
||
1423 | * |
||
1424 | * @return DimensionNode |
||
1425 | */ |
||
1426 | public function blue(ColorNode $color) |
||
1427 | { |
||
1428 | return $color->getBlue(); |
||
1429 | } |
||
1430 | |||
1431 | /** |
||
1432 | * Returns the 'alpha' channel of the $color. |
||
1433 | * |
||
1434 | * @param ColorNode $color The color |
||
1435 | * |
||
1436 | * @return DimensionNode |
||
1437 | */ |
||
1438 | public function alpha(Node $color) |
||
1439 | { |
||
1440 | if (!$color instanceof ColorNode) { |
||
1441 | return $color; |
||
1442 | } |
||
1443 | |||
1444 | return $color->getAlpha(); |
||
1445 | } |
||
1446 | |||
1447 | /** |
||
1448 | * Returns the 'luma' value (perceptual brightness) of the $color. |
||
1449 | * |
||
1450 | * @param ColorNode $color |
||
1451 | * |
||
1452 | * @return DimensionNode |
||
1453 | */ |
||
1454 | public function luma(ColorNode $color) |
||
1455 | { |
||
1456 | return $color->getLuma(); |
||
1457 | } |
||
1458 | |||
1459 | /** |
||
1460 | * Returns the luminance of the color. |
||
1461 | * |
||
1462 | * @param ColorNode $color |
||
1463 | * |
||
1464 | * @return DimensionNode |
||
1465 | */ |
||
1466 | public function luminance(ColorNode $color) |
||
1467 | { |
||
1468 | return $color->getLuminance(); |
||
1469 | } |
||
1470 | |||
1471 | /** |
||
1472 | * Return a color 10% points *more* saturated. |
||
1473 | * |
||
1474 | * @param ColorNode $color |
||
1475 | * @param Node $percentage The percentage |
||
1476 | * @param Node $method The color method |
||
1477 | * |
||
1478 | * @throws InvalidArgumentException |
||
1479 | * |
||
1480 | * @return ColorNode* |
||
1481 | */ |
||
1482 | public function saturate(Node $color, Node $percentage = null, Node $method = null) |
||
1483 | { |
||
1484 | // filter: saturate(3.2); |
||
1485 | // should be kept as is, so check for color |
||
1486 | if ($color instanceof DimensionNode) { |
||
1487 | return; |
||
1488 | } |
||
1489 | |||
1490 | $color = $this->getColorNode($color, 'Cannot saturate the color'); |
||
1491 | |||
1492 | $hsl = $color->toHSL(); |
||
1493 | $percentage = $percentage ? $percentage->value / 100 : 10; |
||
1494 | |||
1495 | // relative |
||
1496 | if ($method && $method->value === 'relative') { |
||
1497 | $hsl['s'] += $hsl['s'] * $percentage; |
||
1498 | } else { |
||
1499 | $hsl['s'] += $percentage; |
||
1500 | } |
||
1501 | |||
1502 | return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $color->getAlpha()); |
||
1503 | } |
||
1504 | |||
1505 | /** |
||
1506 | * Return a color 10% points *less* saturated. |
||
1507 | * |
||
1508 | * @param ColorNode $color |
||
1509 | * @param Node $percentage The percentage |
||
1510 | * @param Node $method The color method |
||
1511 | * |
||
1512 | * @throws InvalidArgumentException |
||
1513 | * |
||
1514 | * @return ColorNode |
||
1515 | */ |
||
1516 | public function desaturate(ColorNode $color, Node $percentage = null, Node $method = null) |
||
1517 | { |
||
1518 | $color = $this->getColorNode($color, 'Cannot desaturate the color'); |
||
1519 | |||
1520 | $hsl = $color->toHSL(); |
||
1521 | $percentage = $percentage ? $percentage->value / 100 : 10; |
||
1522 | |||
1523 | // relative |
||
1524 | if ($method && $method->value === 'relative') { |
||
1525 | $hsl['s'] -= $hsl['s'] * $percentage; |
||
1526 | } else { |
||
1527 | $hsl['s'] -= $percentage; |
||
1528 | } |
||
1529 | |||
1530 | return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $color->getAlpha()); |
||
1531 | } |
||
1532 | |||
1533 | /** |
||
1534 | * Return a color 10% points *lighter*. |
||
1535 | * |
||
1536 | * @param Node $color |
||
1537 | * @param Node $percentage The percentage (Default to 10%) |
||
1538 | * @param Node $method The color method |
||
1539 | * |
||
1540 | * @throws InvalidArgumentException |
||
1541 | * |
||
1542 | * @return ColorNode |
||
1543 | */ |
||
1544 | public function lighten(Node $color, Node $percentage = null, Node $method = null) |
||
1545 | { |
||
1546 | $color = $this->getColorNode($color, 'Cannot lighten the color'); |
||
1547 | $hsl = $color->toHSL(); |
||
1548 | $percentage = $percentage ? $percentage->value / 100 : 10; |
||
1549 | |||
1550 | // relative |
||
1551 | if ($method && $method->value === 'relative') { |
||
1552 | $hsl['l'] += $hsl['l'] * $percentage; |
||
1553 | } else { |
||
1554 | $hsl['l'] += $percentage; |
||
1555 | } |
||
1556 | |||
1557 | return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $color->getAlpha()); |
||
1558 | } |
||
1559 | |||
1560 | /** |
||
1561 | * Return a color 10% points *darker*. |
||
1562 | * |
||
1563 | * @param Node $color |
||
1564 | * @param DimensionNode $percentage The percentage (Default to 10%) |
||
1565 | * @param Node $method The method |
||
1566 | * |
||
1567 | * @return ColorNode |
||
1568 | * |
||
1569 | * @throws InvalidArgumentException |
||
1570 | */ |
||
1571 | public function darken(Node $color, DimensionNode $percentage = null, Node $method = null) |
||
1572 | { |
||
1573 | $color = $this->getColorNode($color, 'Cannot darken the color'); |
||
1574 | $hsl = $color->toHSL(); |
||
1575 | $percentage = $percentage ? $percentage->value / 100 : 10; |
||
1576 | |||
1577 | // relative |
||
1578 | if ($method && $method->value === 'relative') { |
||
1579 | $hsl['l'] -= $hsl['l'] * $percentage; |
||
1580 | } else { |
||
1581 | $hsl['l'] -= $percentage; |
||
1582 | } |
||
1583 | |||
1584 | return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $color->getAlpha()); |
||
1585 | } |
||
1586 | |||
1587 | /** |
||
1588 | * Return a color 10% points *less* transparent. |
||
1589 | * |
||
1590 | * @param ColorNode $color |
||
1591 | * @param DimensionNode $percentage The percentage (Default to 10%) |
||
1592 | * @param Node $method The method |
||
1593 | * |
||
1594 | * @return ColorNode |
||
1595 | * |
||
1596 | * @throws InvalidArgumentException |
||
1597 | */ |
||
1598 | public function fadein(ColorNode $color, DimensionNode $percentage = null, Node $method = null) |
||
1599 | { |
||
1600 | $color = $this->getColorNode($color, 'Cannot fade in the color'); |
||
1601 | $hsl = $color->toHSL(); |
||
1602 | $percentage = $percentage ? $percentage->value / 100 : 10; |
||
1603 | |||
1604 | // relative |
||
1605 | if ($method && $method->value === 'relative') { |
||
1606 | $hsl['a'] += $hsl['a'] * $percentage; |
||
1607 | } else { |
||
1608 | $hsl['a'] += $percentage; |
||
1609 | } |
||
1610 | |||
1611 | return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']); |
||
1612 | } |
||
1613 | |||
1614 | /** |
||
1615 | * Return a color 10% points *more* transparent. |
||
1616 | * |
||
1617 | * @param ColorNode $color |
||
1618 | * @param DimensionNode $percentage The percentage (Default to 10%) |
||
1619 | * @param Node $method The method |
||
1620 | * |
||
1621 | * @return ColorNode |
||
1622 | * |
||
1623 | * @throws InvalidArgumentException |
||
1624 | */ |
||
1625 | public function fadeout(ColorNode $color, DimensionNode $percentage = null, Node $method = null) |
||
1626 | { |
||
1627 | $color = $this->getColorNode($color, 'Cannot fade in the color'); |
||
1628 | $hsl = $color->toHSL(); |
||
1629 | $percentage = $percentage ? $percentage->value / 100 : 10; |
||
1630 | |||
1631 | // relative |
||
1632 | if ($method && $method->value === 'relative') { |
||
1633 | $hsl['a'] -= $hsl['a'] * $percentage; |
||
1634 | } else { |
||
1635 | $hsl['a'] -= $percentage; |
||
1636 | } |
||
1637 | |||
1638 | return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']); |
||
1639 | } |
||
1640 | |||
1641 | /** |
||
1642 | * Return $color with 50% transparency. |
||
1643 | * |
||
1644 | * @param ColorNode $color |
||
1645 | * @param DimensionNode $percentage |
||
1646 | * |
||
1647 | * @return string |
||
1648 | */ |
||
1649 | public function fade(ColorNode $color, DimensionNode $percentage = null) |
||
1650 | { |
||
1651 | $hsl = $color->toHSL(); |
||
1652 | |||
1653 | if ($percentage && $percentage->unit->is('%')) { |
||
1654 | $hsl['a'] = $percentage->value / 100; |
||
1655 | } else { |
||
1656 | $hsl['a'] = $percentage ? $percentage->value : 50; |
||
1657 | } |
||
1658 | |||
1659 | $hsl['a'] = $this->clamp($hsl['a']); |
||
1660 | |||
1661 | return $this->hsla($hsl['h'], $hsl['s'], $hsl['l'], $hsl['a']); |
||
1662 | } |
||
1663 | |||
1664 | /** |
||
1665 | * Return a color with a 10 degree larger in hue. |
||
1666 | * |
||
1667 | * @param ColorNode $color |
||
1668 | * @param DimensionNode $degrees |
||
1669 | * |
||
1670 | * @return ColorNode |
||
1671 | */ |
||
1672 | public function spin(ColorNode $color, DimensionNode $degrees = null) |
||
1673 | { |
||
1674 | $degrees = $degrees ? $degrees->value : 10; |
||
1675 | $hue = (string) fmod($color->getHue(true) + $degrees, 360); |
||
1676 | $hue = $hue < 0 ? 360 + $hue : $hue; |
||
1677 | |||
1678 | return $this->hsla($hue, $color->getSaturation(true), $color->getLightness(true), $color->getAlpha()); |
||
1679 | } |
||
1680 | |||
1681 | /** |
||
1682 | * Return a mix of $color1 and $color2 with given $weightPercentage (defaults to 50%). |
||
1683 | * |
||
1684 | * @param Node $color1 |
||
1685 | * @param Node $color2 |
||
1686 | * @param DimensionNode $weightPercentage |
||
1687 | * |
||
1688 | * @return ColorNode |
||
1689 | * |
||
1690 | * @link http://sass-lang.com |
||
1691 | * |
||
1692 | * @copyright 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein |
||
1693 | */ |
||
1694 | public function mix(Node $color1, Node $color2, DimensionNode $weightPercentage = null) |
||
1695 | { |
||
1696 | if (!$color1 instanceof ColorNode) { |
||
1697 | return $color1; |
||
1698 | } elseif (!$color2 instanceof ColorNode) { |
||
1699 | return $color1; |
||
1700 | } |
||
1701 | |||
1702 | if (!$weightPercentage) { |
||
1703 | $weightPercentage = new DimensionNode(50); |
||
1704 | } |
||
1705 | |||
1706 | $p = $weightPercentage->value / 100.0; |
||
1707 | $w = $p * 2 - 1; |
||
1708 | $a = $color1->getAlpha(true) - $color2->getAlpha(true); |
||
1709 | |||
1710 | $w1 = (((($w * $a) == -1) ? $w : ($w + $a) / (1 + $w * $a)) + 1) / 2; |
||
1711 | $w2 = 1 - $w1; |
||
1712 | |||
1713 | $color1Rgb = $color1->getRGB(); |
||
1714 | $color2Rgb = $color2->getRGB(); |
||
1715 | |||
1716 | $rgb = [ |
||
1717 | $color1Rgb[0] * $w1 + $color2Rgb[0] * $w2, |
||
1718 | $color1Rgb[1] * $w1 + $color2Rgb[1] * $w2, |
||
1719 | $color1Rgb[2] * $w1 + $color2Rgb[2] * $w2, |
||
1720 | ]; |
||
1721 | |||
1722 | $alpha = $color1->getAlpha(true) * $p + $color2->getAlpha(true) * (1 - $p); |
||
1723 | |||
1724 | return new ColorNode($rgb, $alpha); |
||
1725 | } |
||
1726 | |||
1727 | /** |
||
1728 | * Return a color mixed 10% with white. |
||
1729 | * |
||
1730 | * @param Node $color |
||
1731 | * |
||
1732 | * @return string |
||
1733 | */ |
||
1734 | public function tint(Node $color, Node $percentage = null) |
||
1735 | { |
||
1736 | return $this->mix($this->rgb(255, 255, 255), $color, $percentage); |
||
0 ignored issues
–
show
It seems like
$percentage defined by parameter $percentage on line 1734 can also be of type object<ILess\Node> ; however, ILess\FunctionRegistry::mix() does only seem to accept null|object<ILess\Node\DimensionNode> , maybe add an additional type check?
This check looks at variables that have been passed in as parameters and are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
1737 | } |
||
1738 | |||
1739 | /** |
||
1740 | * Return a color mixed 10% with black. |
||
1741 | * |
||
1742 | * @param Node $color |
||
1743 | * @param Node $percentage |
||
1744 | * |
||
1745 | * @return string |
||
1746 | */ |
||
1747 | public function shade(Node $color, Node $percentage = null) |
||
1748 | { |
||
1749 | return $this->mix($this->rgb(0, 0, 0), $color, $percentage); |
||
0 ignored issues
–
show
It seems like
$percentage defined by parameter $percentage on line 1747 can also be of type object<ILess\Node> ; however, ILess\FunctionRegistry::mix() does only seem to accept null|object<ILess\Node\DimensionNode> , maybe add an additional type check?
This check looks at variables that have been passed in as parameters and are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
1750 | } |
||
1751 | |||
1752 | /** |
||
1753 | * Returns a grey, 100% desaturated color. |
||
1754 | * |
||
1755 | * @param ColorNode $color |
||
1756 | * |
||
1757 | * @return string |
||
1758 | */ |
||
1759 | public function greyscale(ColorNode $color) |
||
1760 | { |
||
1761 | return $this->desaturate($color, new DimensionNode(100)); |
||
1762 | } |
||
1763 | |||
1764 | /** |
||
1765 | * Return @darkColor if @color is > 43% luma otherwise return @lightColor, see notes. |
||
1766 | * |
||
1767 | * @param Node $color |
||
1768 | * @param ColorNode|null $darkColor |
||
1769 | * @param ColorNode|null $lightColor |
||
1770 | * @param DimensionNode|null $thresholdPercentage |
||
1771 | * |
||
1772 | * @return ColorNode |
||
1773 | */ |
||
1774 | public function contrast( |
||
1775 | Node $color, |
||
1776 | ColorNode $darkColor = null, |
||
1777 | ColorNode $lightColor = null, |
||
1778 | DimensionNode $thresholdPercentage = null |
||
1779 | ) { |
||
1780 | // ping pong back |
||
1781 | // filter: contrast(3.2); |
||
1782 | // should be kept as is, so check for color |
||
1783 | if (!$color instanceof ColorNode) { |
||
1784 | if ($color instanceof DimensionNode || |
||
1785 | !$color instanceof ToColorConvertibleInterface |
||
1786 | ) { |
||
1787 | return; |
||
1788 | } |
||
1789 | $color = $color->toColor(); |
||
1790 | } |
||
1791 | |||
1792 | if (!$lightColor) { |
||
1793 | $lightColor = $this->rgba(255, 255, 255, 1); |
||
0 ignored issues
–
show
255 is of type integer , but the function expects a object<ILess\Node> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
1794 | } |
||
1795 | |||
1796 | if (!$darkColor) { |
||
1797 | $darkColor = $this->rgba(0, 0, 0, 1); |
||
0 ignored issues
–
show
0 is of type integer , but the function expects a object<ILess\Node> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
1798 | } |
||
1799 | |||
1800 | //Figure out which is actually light and dark! |
||
1801 | if ($darkColor->getLuma(true) > $lightColor->getLuma(true)) { |
||
1802 | $t = $lightColor; |
||
1803 | $lightColor = $darkColor; |
||
1804 | $darkColor = $t; |
||
1805 | } |
||
1806 | |||
1807 | if (!$thresholdPercentage) { |
||
1808 | $thresholdPercentage = 0.43; |
||
1809 | } else { |
||
1810 | $thresholdPercentage = $this->number($thresholdPercentage); |
||
1811 | } |
||
1812 | |||
1813 | if (($color->getLuma(true)) < $thresholdPercentage) { |
||
1814 | return $lightColor; |
||
1815 | } else { |
||
1816 | return $darkColor; |
||
1817 | } |
||
1818 | } |
||
1819 | |||
1820 | /** |
||
1821 | * Multiplies the $color1 with $color2. |
||
1822 | * |
||
1823 | * @param ColorNode $color1 The first color |
||
1824 | * @param ColorNode $color2 The second color |
||
1825 | * |
||
1826 | * @return ColorNode |
||
1827 | */ |
||
1828 | public function multiply(ColorNode $color1, ColorNode $color2) |
||
1829 | { |
||
1830 | return $this->colorBlend([$this, 'colorBlendMultiply'], $color1->getColor(), $color2->getColor()); |
||
0 ignored issues
–
show
$color1->getColor() is of type object<ILess\Node>|string , but the function expects a object<ILess\Color> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() $color2->getColor() is of type object<ILess\Node>|string , but the function expects a object<ILess\Color> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
1831 | } |
||
1832 | |||
1833 | /** |
||
1834 | * Screen. |
||
1835 | * |
||
1836 | * @param ColorNode $color1 The first color |
||
1837 | * @param ColorNode $color2 The second color |
||
1838 | * |
||
1839 | * @return ColorNode |
||
1840 | */ |
||
1841 | public function screen(ColorNode $color1, ColorNode $color2) |
||
1842 | { |
||
1843 | return $this->colorBlend([$this, 'colorBlendScreen'], $color1->getColor(), $color2->getColor()); |
||
0 ignored issues
–
show
$color1->getColor() is of type object<ILess\Node>|string , but the function expects a object<ILess\Color> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() $color2->getColor() is of type object<ILess\Node>|string , but the function expects a object<ILess\Color> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
1844 | } |
||
1845 | |||
1846 | /** |
||
1847 | * Combines the effects of both multiply and screen. Conditionally make light channels lighter |
||
1848 | * and dark channels darker. Note: The results of the conditions are determined by the |
||
1849 | * first color parameter. |
||
1850 | * |
||
1851 | * @param ColorNode $color1 A base color object. Also the determinant color to make the result lighter or darker. |
||
1852 | * @param ColorNode $color2 A color object to overlay. |
||
1853 | * |
||
1854 | * @return ColorNode |
||
1855 | * |
||
1856 | * @see http://lesscss.org/functions/#color-blending-overlay |
||
1857 | */ |
||
1858 | public function overlay(ColorNode $color1, ColorNode $color2) |
||
1859 | { |
||
1860 | return $this->colorBlend([$this, 'colorBlendOverlay'], $color1->getColor(), $color2->getColor()); |
||
0 ignored issues
–
show
$color1->getColor() is of type object<ILess\Node>|string , but the function expects a object<ILess\Color> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() $color2->getColor() is of type object<ILess\Node>|string , but the function expects a object<ILess\Color> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
1861 | } |
||
1862 | |||
1863 | /** |
||
1864 | * Softlight - Similar to overlay but avoids pure black resulting in pure black, |
||
1865 | * and pure white resulting in pure white. |
||
1866 | * |
||
1867 | * @param ColorNode $color1 The first color |
||
1868 | * @param ColorNode $color2 The second color |
||
1869 | * |
||
1870 | * @return ColorNode |
||
1871 | * |
||
1872 | * @see http://lesscss.org/functions/#color-blending-softlight |
||
1873 | */ |
||
1874 | public function softlight(ColorNode $color1, ColorNode $color2) |
||
1875 | { |
||
1876 | return $this->colorBlend([$this, 'colorBlendSoftlight'], $color1->getColor(), $color2->getColor()); |
||
0 ignored issues
–
show
$color1->getColor() is of type object<ILess\Node>|string , but the function expects a object<ILess\Color> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() $color2->getColor() is of type object<ILess\Node>|string , but the function expects a object<ILess\Color> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
1877 | } |
||
1878 | |||
1879 | /** |
||
1880 | * Hardlight filter. |
||
1881 | * |
||
1882 | * @param ColorNode $color1 The first color |
||
1883 | * @param ColorNode $color2 The second color |
||
1884 | * |
||
1885 | * @return ColorNode |
||
1886 | */ |
||
1887 | public function hardlight(ColorNode $color1, ColorNode $color2) |
||
1888 | { |
||
1889 | return $this->colorBlend([$this, 'colorBlendHardlight'], $color1->getColor(), $color2->getColor()); |
||
0 ignored issues
–
show
$color1->getColor() is of type object<ILess\Node>|string , but the function expects a object<ILess\Color> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() $color2->getColor() is of type object<ILess\Node>|string , but the function expects a object<ILess\Color> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
1890 | } |
||
1891 | |||
1892 | /** |
||
1893 | * Difference. |
||
1894 | * |
||
1895 | * @param ColorNode $color1 The first color |
||
1896 | * @param ColorNode $color2 The second color |
||
1897 | * |
||
1898 | * @return ColorNode |
||
1899 | */ |
||
1900 | public function difference(ColorNode $color1, ColorNode $color2) |
||
1901 | { |
||
1902 | return $this->colorBlend([$this, 'colorBlendDifference'], $color1->getColor(), $color2->getColor()); |
||
0 ignored issues
–
show
$color1->getColor() is of type object<ILess\Node>|string , but the function expects a object<ILess\Color> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() $color2->getColor() is of type object<ILess\Node>|string , but the function expects a object<ILess\Color> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
1903 | } |
||
1904 | |||
1905 | /** |
||
1906 | * Exclusion. |
||
1907 | * |
||
1908 | * @param ColorNode $color1 The first color |
||
1909 | * @param ColorNode $color2 The second color |
||
1910 | * |
||
1911 | * @return ColorNode |
||
1912 | */ |
||
1913 | public function exclusion(ColorNode $color1, ColorNode $color2) |
||
1914 | { |
||
1915 | return $this->colorBlend([$this, 'colorBlendExclusion'], $color1->getColor(), $color2->getColor()); |
||
0 ignored issues
–
show
$color1->getColor() is of type object<ILess\Node>|string , but the function expects a object<ILess\Color> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() $color2->getColor() is of type object<ILess\Node>|string , but the function expects a object<ILess\Color> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
1916 | } |
||
1917 | |||
1918 | /** |
||
1919 | * Average. |
||
1920 | * |
||
1921 | * @param ColorNode $color1 The first color |
||
1922 | * @param ColorNode $color2 The second color |
||
1923 | * |
||
1924 | * @return ColorNode |
||
1925 | */ |
||
1926 | public function average(ColorNode $color1, ColorNode $color2) |
||
1927 | { |
||
1928 | return $this->colorBlend([$this, 'colorBlendAverage'], $color1->getColor(), $color2->getColor()); |
||
0 ignored issues
–
show
$color1->getColor() is of type object<ILess\Node>|string , but the function expects a object<ILess\Color> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() $color2->getColor() is of type object<ILess\Node>|string , but the function expects a object<ILess\Color> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
1929 | } |
||
1930 | |||
1931 | /** |
||
1932 | * Negation. |
||
1933 | * |
||
1934 | * @param ColorNode $color1 The first color |
||
1935 | * @param ColorNode $color2 The second color |
||
1936 | * |
||
1937 | * @return ColorNode |
||
1938 | */ |
||
1939 | public function negation(ColorNode $color1, ColorNode $color2) |
||
1940 | { |
||
1941 | return $this->colorBlend([$this, 'colorBlendNegation'], $color1->getColor(), $color2->getColor()); |
||
0 ignored issues
–
show
$color1->getColor() is of type object<ILess\Node>|string , but the function expects a object<ILess\Color> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() $color2->getColor() is of type object<ILess\Node>|string , but the function expects a object<ILess\Color> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
1942 | } |
||
1943 | |||
1944 | /** |
||
1945 | * Returns true if passed a color, including keyword colors. |
||
1946 | * |
||
1947 | * @param Node $colorOrAnything |
||
1948 | * |
||
1949 | * @return KeywordNode |
||
1950 | */ |
||
1951 | public function iscolor(Node $colorOrAnything) |
||
1952 | { |
||
1953 | return $this->isA($colorOrAnything, 'ILess\Node\ColorNode'); |
||
1954 | } |
||
1955 | |||
1956 | /** |
||
1957 | * Returns true if a number of any unit. |
||
1958 | * |
||
1959 | * @param Node $numberOrAnything |
||
1960 | * |
||
1961 | * @return KeywordNode |
||
1962 | */ |
||
1963 | public function isnumber(Node $numberOrAnything) |
||
1964 | { |
||
1965 | return $this->isA($numberOrAnything, 'ILess\Node\DimensionNode'); |
||
1966 | } |
||
1967 | |||
1968 | /** |
||
1969 | * Returns true if it is passed a string. |
||
1970 | * |
||
1971 | * @param Node $stringOrAnything |
||
1972 | * |
||
1973 | * @return KeywordNode |
||
1974 | */ |
||
1975 | public function isstring(Node $stringOrAnything) |
||
1976 | { |
||
1977 | return $this->isA($stringOrAnything, 'ILess\Node\QuotedNode'); |
||
1978 | } |
||
1979 | |||
1980 | /** |
||
1981 | * Returns true if it is passed keyword. |
||
1982 | * |
||
1983 | * @param Node $numberOrAnything |
||
1984 | * |
||
1985 | * @return KeywordNode |
||
1986 | */ |
||
1987 | public function iskeyword(Node $keywordOrAnything) |
||
1988 | { |
||
1989 | return $this->isA($keywordOrAnything, 'ILess\Node\KeywordNode'); |
||
1990 | } |
||
1991 | |||
1992 | /** |
||
1993 | * Returns true if it is a string and a url. |
||
1994 | * |
||
1995 | * @param mixed $urlOrAnything |
||
1996 | * |
||
1997 | * @return bool |
||
1998 | */ |
||
1999 | public function isurl(Node $urlOrAnything) |
||
2000 | { |
||
2001 | return $this->isA($urlOrAnything, 'ILess\Node\UrlNode'); |
||
2002 | } |
||
2003 | |||
2004 | /** |
||
2005 | * Returns true if it is a number and a px. |
||
2006 | * |
||
2007 | * @param Node $urlOrAnything The node to check |
||
2008 | * |
||
2009 | * @return KeywordNode |
||
2010 | */ |
||
2011 | public function ispixel(Node $pixelOrAnything) |
||
2012 | { |
||
2013 | if ($this->isA($pixelOrAnything, 'ILess\Node\DimensionNode') && $pixelOrAnything->unit->is('px')) { |
||
2014 | return new KeywordNode('true'); |
||
2015 | } |
||
2016 | |||
2017 | return new KeywordNode('false'); |
||
2018 | } |
||
2019 | |||
2020 | /** |
||
2021 | * Returns true if it is a number and a %. |
||
2022 | * |
||
2023 | * @param Node $percentageOrAnything |
||
2024 | * |
||
2025 | * @return KeywordNode |
||
2026 | */ |
||
2027 | public function ispercentage(Node $percentageOrAnything) |
||
2028 | { |
||
2029 | if ($this->isA($percentageOrAnything, 'ILess\Node\DimensionNode') && $percentageOrAnything->unit->is('%')) { |
||
2030 | return new KeywordNode('true'); |
||
2031 | } |
||
2032 | |||
2033 | return new KeywordNode('false'); |
||
2034 | } |
||
2035 | |||
2036 | /** |
||
2037 | * Returns true if it is a number and an em. |
||
2038 | * |
||
2039 | * @param Node $emOrAnything |
||
2040 | * |
||
2041 | * @return KeywordNode |
||
2042 | */ |
||
2043 | public function isem(Node $emOrAnything) |
||
2044 | { |
||
2045 | if ($this->isA($emOrAnything, 'ILess\Node\DimensionNode') && $emOrAnything->unit->is('em')) { |
||
2046 | return new KeywordNode('true'); |
||
2047 | } |
||
2048 | |||
2049 | return new KeywordNode('false'); |
||
2050 | } |
||
2051 | |||
2052 | /** |
||
2053 | * returns if a parameter is a number and is in a particular unit. |
||
2054 | * |
||
2055 | * @param Node $node |
||
2056 | * @param Node $unit The unit to check |
||
2057 | * |
||
2058 | * @return bool |
||
2059 | */ |
||
2060 | public function isunit(Node $node, Node $unit = null) |
||
2061 | { |
||
2062 | if ($this->isA($node, 'ILess\Node\DimensionNode') |
||
2063 | && $node->unit->is((property_exists($unit, 'value') ? $unit->value : $unit)) |
||
2064 | ) { |
||
2065 | return new KeywordNode('true'); |
||
2066 | } |
||
2067 | |||
2068 | return new KeywordNode('false'); |
||
2069 | } |
||
2070 | |||
2071 | /** |
||
2072 | * Returns true if the node is detached ruleset. |
||
2073 | * |
||
2074 | * @param Node $node |
||
2075 | * |
||
2076 | * @return bool |
||
2077 | */ |
||
2078 | public function isruleset(Node $node) |
||
2079 | { |
||
2080 | return $this->isA($node, 'ILess\Node\DetachedRulesetNode'); |
||
2081 | } |
||
2082 | |||
2083 | /** |
||
2084 | * Creates a SVG gradient. |
||
2085 | * |
||
2086 | * @param Node $direction |
||
2087 | * @param Node ...$stop1 |
||
2088 | * |
||
2089 | * @return UrlNode |
||
2090 | * |
||
2091 | * @throws CompilerException If the arguments are invalid |
||
2092 | */ |
||
2093 | public function svggradient(Node $direction /* $stop1, $stop2, ... */) |
||
2094 | { |
||
2095 | $numArgs = func_num_args(); |
||
2096 | $arguments = func_get_args(); |
||
2097 | |||
2098 | if ($numArgs === 2) { |
||
2099 | // a list of colors |
||
2100 | if (is_array($arguments[1]->value) && count($arguments[1]->value) < 2) { |
||
2101 | throw new CompilerException( |
||
2102 | 'svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position]' |
||
2103 | ); |
||
2104 | } |
||
2105 | $stops = $arguments[1]->value; |
||
2106 | } elseif ($numArgs < 3) { |
||
2107 | throw new CompilerException( |
||
2108 | 'svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position]' |
||
2109 | ); |
||
2110 | } else { |
||
2111 | $stops = array_slice($arguments, 1); |
||
2112 | } |
||
2113 | |||
2114 | $gradientType = 'linear'; |
||
2115 | $rectangleDimension = 'x="0" y="0" width="1" height="1"'; |
||
2116 | $renderEnv = new Context([ |
||
2117 | 'compress' => false, |
||
2118 | ]); |
||
2119 | $directionValue = $direction->toCSS($renderEnv); |
||
2120 | |||
2121 | switch ($directionValue) { |
||
2122 | case 'to bottom': |
||
2123 | $gradientDirectionSvg = 'x1="0%" y1="0%" x2="0%" y2="100%"'; |
||
2124 | break; |
||
2125 | case 'to right': |
||
2126 | $gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="0%"'; |
||
2127 | break; |
||
2128 | case 'to bottom right': |
||
2129 | $gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="100%"'; |
||
2130 | break; |
||
2131 | case 'to top right': |
||
2132 | $gradientDirectionSvg = 'x1="0%" y1="100%" x2="100%" y2="0%"'; |
||
2133 | break; |
||
2134 | case 'ellipse': |
||
2135 | case 'ellipse at center': |
||
2136 | $gradientType = 'radial'; |
||
2137 | $gradientDirectionSvg = 'cx="50%" cy="50%" r="75%"'; |
||
2138 | $rectangleDimension = 'x="-50" y="-50" width="101" height="101"'; |
||
2139 | break; |
||
2140 | default: |
||
2141 | throw new CompilerException( |
||
2142 | "svg-gradient direction must be 'to bottom', 'to right', 'to bottom right', 'to top right' or 'ellipse at center'" |
||
2143 | ); |
||
2144 | } |
||
2145 | |||
2146 | $returner = '<?xml version="1.0" ?>' . |
||
2147 | '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none">' . |
||
2148 | '<' . $gradientType . 'Gradient id="gradient" gradientUnits="userSpaceOnUse" ' . $gradientDirectionSvg . '>'; |
||
2149 | |||
2150 | for ($i = 0; $i < count($stops); ++$i) { |
||
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
![]() |
|||
2151 | if ($stops[$i] instanceof ExpressionNode) { |
||
2152 | $color = $stops[$i]->value[0]; |
||
2153 | $position = $stops[$i]->value[1]; |
||
2154 | } else { |
||
2155 | $color = $stops[$i]; |
||
2156 | $position = null; |
||
2157 | } |
||
2158 | |||
2159 | if (!($color instanceof ColorNode) |
||
2160 | || (!(($i === 0 || $i + 1 === count($stops)) && $position === null) |
||
2161 | && !($position instanceof DimensionNode)) |
||
2162 | ) { |
||
2163 | throw new CompilerException( |
||
2164 | 'svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position] or direction, color list' |
||
2165 | ); |
||
2166 | } |
||
2167 | |||
2168 | if ($position) { |
||
2169 | $positionValue = $position->toCSS($renderEnv); |
||
2170 | } elseif ($i === 0) { |
||
2171 | $positionValue = '0%'; |
||
2172 | } else { |
||
2173 | $positionValue = '100%'; |
||
2174 | } |
||
2175 | |||
2176 | $colorValue = $color->getColor()->toRGB(); |
||
0 ignored issues
–
show
The method
toRGB() does not seem to exist on object<ILess\Node> .
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||
2177 | |||
2178 | $alpha = $color->getAlpha(true); |
||
2179 | $returner .= '<stop offset="' . $positionValue . '" stop-color="' . |
||
2180 | $colorValue . '"' . |
||
2181 | ($alpha < 1 ? ' stop-opacity="' . $alpha . '"' : '') . '/>'; |
||
2182 | } |
||
2183 | |||
2184 | $returner .= '</' . $gradientType . 'Gradient><rect ' . $rectangleDimension . ' fill="url(#gradient)" /></svg>'; |
||
2185 | |||
2186 | $returner = Util::encodeURIComponent($returner); |
||
2187 | $returner = 'data:image/svg+xml,' . $returner; |
||
2188 | |||
2189 | return new UrlNode(new QuotedNode("'" . $returner . "'", $returner, false)); |
||
2190 | } |
||
2191 | |||
2192 | /** |
||
2193 | * Default function. |
||
2194 | * |
||
2195 | * @return KeywordNode|null |
||
2196 | * |
||
2197 | * @throws Exception |
||
2198 | */ |
||
2199 | public function defaultFunc() |
||
2200 | { |
||
2201 | return DefaultFunc::compile(); |
||
2202 | } |
||
2203 | |||
2204 | /** |
||
2205 | * Returns the image size. |
||
2206 | * |
||
2207 | * @param Node $node The path node |
||
2208 | * |
||
2209 | * @return ExpressionNode |
||
2210 | * |
||
2211 | * @throws IOException |
||
2212 | */ |
||
2213 | public function imageSize(Node $node) |
||
2214 | { |
||
2215 | $size = $this->getImageSize($node); |
||
2216 | |||
2217 | return new ExpressionNode( |
||
2218 | [ |
||
2219 | new DimensionNode($size['width'], 'px'), |
||
2220 | new DimensionNode($size['height'], 'px'), |
||
2221 | ] |
||
2222 | ); |
||
2223 | } |
||
2224 | |||
2225 | /** |
||
2226 | * Returns the image width. |
||
2227 | * |
||
2228 | * @param Node $node The path node |
||
2229 | * |
||
2230 | * @return DimensionNode |
||
2231 | * |
||
2232 | * @throws IOException |
||
2233 | */ |
||
2234 | public function imageWidth(Node $node) |
||
2235 | { |
||
2236 | $size = $this->getImageSize($node); |
||
2237 | |||
2238 | return new DimensionNode($size['width'], 'px'); |
||
2239 | } |
||
2240 | |||
2241 | /** |
||
2242 | * Returns the image height. |
||
2243 | * |
||
2244 | * @param Node $node The path node |
||
2245 | * |
||
2246 | * @return DimensionNode |
||
2247 | * |
||
2248 | * @throws IOException |
||
2249 | */ |
||
2250 | public function imageHeight(Node $node) |
||
2251 | { |
||
2252 | $size = $this->getImageSize($node); |
||
2253 | |||
2254 | return new DimensionNode($size['height'], 'px'); |
||
2255 | } |
||
2256 | |||
2257 | /** |
||
2258 | * Returns the width and height of the image. |
||
2259 | * |
||
2260 | * @param Node $path |
||
2261 | * |
||
2262 | * @throws IOException |
||
2263 | * |
||
2264 | * @return array |
||
2265 | */ |
||
2266 | protected function getImageSize(Node $path) |
||
2267 | { |
||
2268 | $filePath = $path->value; |
||
2269 | |||
2270 | $fragmentStart = strpos($filePath, '#'); |
||
2271 | // $fragment = ''; |
||
2272 | if ($fragmentStart !== false) { |
||
2273 | // $fragment = substr($filePath, $fragmentStart); |
||
2274 | $filePath = substr($filePath, 0, $fragmentStart); |
||
2275 | } |
||
2276 | |||
2277 | $filePath = $this->getFilePath($filePath); |
||
0 ignored issues
–
show
It seems like
$filePath can also be of type object<ILess\Node> ; however, ILess\FunctionRegistry::getFilePath() does only seem to accept string , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
2278 | |||
2279 | if (!is_readable($filePath)) { |
||
2280 | throw new IOException(sprintf('The file "%s" is does not exist or is not readable', $filePath)); |
||
2281 | } |
||
2282 | |||
2283 | $size = @getimagesize($filePath); |
||
2284 | |||
2285 | if ($size === false) { |
||
2286 | throw new IOException( |
||
2287 | sprintf('The file "%s" dimension could not be read. It is an image?', $filePath) |
||
2288 | ); |
||
2289 | } |
||
2290 | |||
2291 | return [ |
||
2292 | 'width' => $size[0], |
||
2293 | 'height' => $size[1], |
||
2294 | ]; |
||
2295 | } |
||
2296 | |||
2297 | /** |
||
2298 | * Returns the file path, takes care about relative urls. |
||
2299 | * |
||
2300 | * @param string $path |
||
2301 | * |
||
2302 | * @return mixed|string |
||
2303 | */ |
||
2304 | protected function getFilePath($path) |
||
2305 | { |
||
2306 | $path = Util::sanitizePath($path); |
||
2307 | |||
2308 | if (Util::isPathRelative($path) && $this->currentFileInfo) { |
||
2309 | if ($this->context->relativeUrls) { |
||
2310 | $path = $this->currentFileInfo->currentDirectory . $path; |
||
2311 | } else { |
||
2312 | $path = $this->currentFileInfo->entryPath . $path; |
||
2313 | } |
||
2314 | $path = Util::normalizePath($path); |
||
2315 | } |
||
2316 | |||
2317 | return $path; |
||
2318 | } |
||
2319 | |||
2320 | protected function doMinmax($isMin, $args) |
||
2321 | { |
||
2322 | switch (count($args)) { |
||
2323 | case 0: |
||
2324 | throw new CompilerException('One or more arguments required.'); |
||
2325 | } |
||
2326 | |||
2327 | $order = []; // elems only contains original argument values. |
||
2328 | $values = []; // key is the unit.toString() for unified tree.Dimension values, |
||
2329 | $unitClone = $unitStatic = $j = null; |
||
2330 | |||
2331 | // value is the index into the order array. |
||
2332 | for ($i = 0; $i < count($args); ++$i) { |
||
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
![]() |
|||
2333 | $current = $args[$i]; |
||
2334 | if (!($current instanceof DimensionNode)) { |
||
2335 | if (is_array($args[$i])) { |
||
2336 | $args[] = $args[$i]->value; |
||
2337 | } |
||
2338 | continue; |
||
2339 | } |
||
2340 | |||
2341 | if ($current->unit->toString() === '' && $unitClone !== null) { |
||
2342 | $dim = new DimensionNode($current->value, $unitClone); |
||
0 ignored issues
–
show
It seems like
$current->value can also be of type object<ILess\Node> ; however, ILess\Node\DimensionNode::__construct() does only seem to accept string , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
2343 | $currentUnified = $dim->unify(); |
||
2344 | } else { |
||
2345 | $currentUnified = $current->unify(); |
||
2346 | } |
||
2347 | |||
2348 | $unit = $currentUnified->unit->toString() === '' && $unitStatic !== null ? $unitStatic : $currentUnified->unit->toString(); |
||
2349 | // $unitStatic = $unit !== '' && $unitStatic === null || $unit !== '' && $order[0]->unify()->unit->toString() === '' ? $unit : $unitStatic; |
||
2350 | |||
2351 | if ($unit !== '' && !$unitStatic || $unit !== '' && $order[0]->unify()->unit->toString() === '') { |
||
2352 | $unitStatic = $unit; |
||
2353 | } |
||
2354 | |||
2355 | $unitClone = $unit !== '' && $unitClone === null ? $current->unit->toString() : $unitClone; |
||
2356 | |||
2357 | if (isset($values['']) && $unit !== '' && $unit === $unitStatic) { |
||
2358 | $j = $values['']; |
||
2359 | } elseif (isset($values[$unit])) { |
||
2360 | $j = $values[$unit]; |
||
2361 | } else { |
||
2362 | if ($unitStatic !== null && $unit !== $unitStatic) { |
||
2363 | throw new RuntimeException(sprintf('Incompatible types "%s" and "%s" given', $unitStatic, $unit)); |
||
2364 | } |
||
2365 | |||
2366 | $values[$unit] = count($order); |
||
2367 | $order[] = $current; |
||
2368 | continue; |
||
2369 | } |
||
2370 | |||
2371 | if ($order[$j]->unit->toString() === '' && $unitClone !== null) { |
||
2372 | $dim = new DimensionNode($order[$j]->value, $unitClone); |
||
2373 | $referenceUnified = $dim->unify(); |
||
2374 | } else { |
||
2375 | $referenceUnified = $order[$j]->unify(); |
||
2376 | } |
||
2377 | |||
2378 | if (($isMin && $currentUnified->value < $referenceUnified->value) || |
||
2379 | (!$isMin && $currentUnified->value > $referenceUnified->value) |
||
2380 | ) { |
||
2381 | $order[$j] = $current; |
||
2382 | } |
||
2383 | } |
||
2384 | |||
2385 | if (count($order) === 1) { |
||
2386 | return $order[0]; |
||
2387 | } |
||
2388 | |||
2389 | foreach ($order as $k => $a) { |
||
2390 | $order[$k] = $a->toCSS($this->context); |
||
2391 | } |
||
2392 | |||
2393 | $args = implode(($this->context->compress ? ',' : ', '), $order); |
||
2394 | |||
2395 | return new AnonymousNode(($isMin ? 'min' : 'max') . '(' . $args . ')'); |
||
2396 | } |
||
2397 | |||
2398 | /** |
||
2399 | * Checks if the given object is of this class or has this class as one of its parents. |
||
2400 | * |
||
2401 | * @param Node $node |
||
2402 | * @param string $className The className to check |
||
2403 | * |
||
2404 | * @return KeywordNode |
||
2405 | */ |
||
2406 | protected function isA(Node $node, $className) |
||
2407 | { |
||
2408 | if (is_a($node, $className)) { |
||
2409 | return new KeywordNode('true'); |
||
2410 | } |
||
2411 | |||
2412 | return new KeywordNode('false'); |
||
2413 | } |
||
2414 | |||
2415 | /** |
||
2416 | * Clamps the value. |
||
2417 | * |
||
2418 | * @param int $value |
||
2419 | * |
||
2420 | * @return int |
||
2421 | */ |
||
2422 | protected function clamp($value) |
||
2423 | { |
||
2424 | return min(1, max(0, $value)); |
||
2425 | } |
||
2426 | |||
2427 | /** |
||
2428 | * Convert the given node to color node. |
||
2429 | * |
||
2430 | * @param Node $node The node |
||
2431 | * @param null $exceptionMessage ILess\Exception\Exception message if the node could not be converted to color node |
||
2432 | * |
||
2433 | * @return ColorNode |
||
2434 | * |
||
2435 | * @throws InvalidArgumentException If the node could not be converted to color |
||
2436 | */ |
||
2437 | protected function getColorNode(Node $node, $exceptionMessage = null) |
||
2438 | { |
||
2439 | if ($node instanceof ColorNode) { |
||
2440 | return $node; |
||
2441 | } |
||
2442 | |||
2443 | // this is a keyword |
||
2444 | if ($node instanceof KeywordNode && Color::isNamedColor($node->value)) { |
||
0 ignored issues
–
show
It seems like
$node->value can also be of type object<ILess\Node> ; however, ILess\Color::isNamedColor() does only seem to accept string , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
2445 | $node = new ColorNode(Color::color($node->value)); |
||
0 ignored issues
–
show
It seems like
$node->value can also be of type object<ILess\Node> ; however, ILess\Color::color() does only seem to accept string , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
2446 | } elseif ($node instanceof ToColorConvertibleInterface) { |
||
2447 | $node = $node->toColor(); |
||
2448 | } |
||
2449 | |||
2450 | if (!$node instanceof ColorNode) { |
||
2451 | throw new InvalidArgumentException($exceptionMessage ? $exceptionMessage : 'Cannot convert node to color'); |
||
2452 | } |
||
2453 | |||
2454 | return $node; |
||
2455 | } |
||
2456 | |||
2457 | /** |
||
2458 | * Color blending. |
||
2459 | * |
||
2460 | * @param callable $mode |
||
2461 | * @param Color $color1 |
||
2462 | * @param Color $color2 |
||
2463 | * |
||
2464 | * @return ColorNode |
||
2465 | */ |
||
2466 | protected function colorBlend(callable $mode, Color $color1, Color $color2) |
||
2467 | { |
||
2468 | $ab = $color1->getAlpha(); // backdrop |
||
2469 | $as = $color2->getAlpha(); // source |
||
2470 | $r = []; // result |
||
2471 | |||
2472 | $ar = $as + $ab * (1 - $as); |
||
2473 | $rgb1 = $color1->rgb; |
||
2474 | $rgb2 = $color2->rgb; |
||
2475 | for ($i = 0; $i < 3; ++$i) { |
||
2476 | $cb = $rgb1[$i] / 255; |
||
2477 | $cs = $rgb2[$i] / 255; |
||
2478 | $cr = call_user_func($mode, $cb, $cs); |
||
2479 | if ($ar) { |
||
2480 | $cr = ($as * $cs + $ab * ($cb - $as * ($cb + $cs - $cr))) / $ar; |
||
2481 | } |
||
2482 | $r[$i] = $cr * 255; |
||
2483 | } |
||
2484 | |||
2485 | return new ColorNode($r, $ar); |
||
2486 | } |
||
2487 | |||
2488 | private function colorBlendMultiply($cb, $cs) |
||
2489 | { |
||
2490 | return $cb * $cs; |
||
2491 | } |
||
2492 | |||
2493 | private function colorBlendScreen($cb, $cs) |
||
2494 | { |
||
2495 | return $cb + $cs - $cb * $cs; |
||
2496 | } |
||
2497 | |||
2498 | private function colorBlendOverlay($cb, $cs) |
||
2499 | { |
||
2500 | $cb *= 2; |
||
2501 | |||
2502 | return ($cb <= 1) |
||
2503 | ? $this->colorBlendMultiply($cb, $cs) |
||
2504 | : $this->colorBlendScreen($cb - 1, $cs); |
||
2505 | } |
||
2506 | |||
2507 | private function colorBlendSoftlight($cb, $cs) |
||
2508 | { |
||
2509 | $d = 1; |
||
2510 | $e = $cb; |
||
2511 | if ($cs > 0.5) { |
||
2512 | $e = 1; |
||
2513 | $d = ($cb > 0.25) ? sqrt($cb) |
||
2514 | : ((16 * $cb - 12) * $cb + 4) * $cb; |
||
2515 | } |
||
2516 | |||
2517 | return $cb - (1 - 2 * $cs) * $e * ($d - $cb); |
||
2518 | } |
||
2519 | |||
2520 | private function colorBlendHardlight($cb, $cs) |
||
2521 | { |
||
2522 | return $this->colorBlendOverlay($cs, $cb); |
||
2523 | } |
||
2524 | |||
2525 | private function colorBlendDifference($cb, $cs) |
||
2526 | { |
||
2527 | return abs($cb - $cs); |
||
2528 | } |
||
2529 | |||
2530 | private function colorBlendExclusion($cb, $cs) |
||
2531 | { |
||
2532 | return $cb + $cs - 2 * $cb * $cs; |
||
2533 | } |
||
2534 | |||
2535 | private function colorBlendAverage($cb, $cs) |
||
2536 | { |
||
2537 | return ($cb + $cs) / 2; |
||
2538 | } |
||
2539 | |||
2540 | private function colorBlendNegation($cb, $cs) |
||
2541 | { |
||
2542 | return 1 - abs($cb + $cs - 1); |
||
2543 | } |
||
2544 | } |
||
2545 |
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.