/** * Creates a SVG gradient * * @param Node $direction * @param Node ...$stop1 * @return UrlNode * @throws CompilerException If the arguments are invalid */ public function svggradient(Node $direction) { $numArgs = func_num_args(); $arguments = func_get_args(); if ($numArgs === 2) { // a list of colors if (is_array($arguments[1]->value) && count($arguments[1]->value) < 2) { throw new CompilerException('svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position]'); } $stops = $arguments[1]->value; } elseif ($numArgs < 3) { throw new CompilerException('svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position]'); } else { $stops = array_slice($arguments, 1); } $gradientType = 'linear'; $rectangleDimension = 'x="0" y="0" width="1" height="1"'; $renderEnv = new Context(['compress' => false]); $directionValue = $direction->toCSS($renderEnv); switch ($directionValue) { case 'to bottom': $gradientDirectionSvg = 'x1="0%" y1="0%" x2="0%" y2="100%"'; break; case 'to right': $gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="0%"'; break; case 'to bottom right': $gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="100%"'; break; case 'to top right': $gradientDirectionSvg = 'x1="0%" y1="100%" x2="100%" y2="0%"'; break; case 'ellipse': case 'ellipse at center': $gradientType = 'radial'; $gradientDirectionSvg = 'cx="50%" cy="50%" r="75%"'; $rectangleDimension = 'x="-50" y="-50" width="101" height="101"'; break; default: throw new CompilerException("svg-gradient direction must be 'to bottom', 'to right', 'to bottom right', 'to top right' or 'ellipse at center'"); } $returner = '<?xml version="1.0" ?>' . '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none">' . '<' . $gradientType . 'Gradient id="gradient" gradientUnits="userSpaceOnUse" ' . $gradientDirectionSvg . '>'; for ($i = 0; $i < count($stops); $i++) { if ($stops[$i] instanceof ExpressionNode) { $color = $stops[$i]->value[0]; $position = $stops[$i]->value[1]; } else { $color = $stops[$i]; $position = null; } if (!$color instanceof ColorNode || !(($i === 0 || $i + 1 === count($stops)) && $position === null) && !$position instanceof DimensionNode) { throw new CompilerException('svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position] or direction, color list'); } if ($position) { $positionValue = $position->toCSS($renderEnv); } elseif ($i === 0) { $positionValue = '0%'; } else { $positionValue = '100%'; } $colorValue = $color->getColor()->toRGB(); $alpha = $color->getAlpha(true); $returner .= '<stop offset="' . $positionValue . '" stop-color="' . $colorValue . '"' . ($alpha < 1 ? ' stop-opacity="' . $alpha . '"' : '') . '/>'; } $returner .= '</' . $gradientType . 'Gradient><rect ' . $rectangleDimension . ' fill="url(#gradient)" /></svg>'; $returner = Util::encodeURIComponent($returner); $returner = 'data:image/svg+xml,' . $returner; return new UrlNode(new QuotedNode("'" . $returner . "'", $returner, false)); }
/** * Generates the CSS. * * @param Context $context * * @return string */ public function generateCSS(Context $context) { $output = new MappedOutput($this->contentsMap, $this); // catch the output $this->root->generateCSS($context, $output); // prepare sources foreach ($this->contentsMap as $filename => $contents) { // match md5 hash in square brackets _[#HASH#]_ // see ILess\Parser\Core::parseString() if (preg_match('/(\\[__[0-9a-f]{32}__\\])+$/', $filename)) { $filename = substr($filename, 0, -38); } $this->sources[$this->normalizeFilename($filename)] = $contents; } $sourceMapUrl = null; if ($url = $this->getOption('url')) { $sourceMapUrl = $url; } elseif ($path = $this->getOption('filename')) { $sourceMapUrl = $this->normalizeFilename($path); // naming conventions, make it foobar.css.map if (!preg_match('/\\.map$/', $sourceMapUrl)) { $sourceMapUrl = sprintf('%s.map', $sourceMapUrl); } } $sourceMapContent = $this->generateJson(); // write map to a file if ($file = $this->getOption('write_to')) { $this->saveMap($file, $sourceMapContent); } else { $sourceMap = 'data:application/json;'; if ($this->getOption('inline_encode_base64')) { $sourceMap .= 'base64,'; $sourceMapContent = base64_encode($sourceMapContent); } else { $sourceMapContent = Util::encodeURIComponent($sourceMapContent); } $sourceMapUrl = $sourceMap . $sourceMapContent; } if ($sourceMapUrl) { $output->add(sprintf('/*# sourceMappingURL=%s */', $sourceMapUrl)); } return $output->toString(); }