#! /usr/bin/env node /**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the utils of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ const _ = require('lodash'); const fs = require('fs'); const postcss = require('postcss'); const minifyGradients = require('postcss-minify-gradients'); const valueParser = require('postcss-value-parser'); const parseColor = require('parse-color'); const math = require('mathjs'); const argc = process.argv.length; if (argc < 3) { console.log("usage: gradientgen [mode] "); process.exit(1); } const filename = process.argv[argc - 1]; const mode = argc > 3 ? process.argv[argc - 2] : 'json'; fs.readFile(filename, (err, css) => { postcss([minifyGradients]).process(css) .then(result => { let enums = []; let gradients = []; result.root.walkRules(rule => { gradients.push(null); // Placeholder const name = _.startCase(rule.selector).replace(/\s/g, ''); if (enums.indexOf(name) >= 0) return; // Duplicate entry // We can only support single gradient declarations if (rule.nodes.length > 1) return; valueParser(rule.nodes[0].value).walk(node => { if (node.type !== 'function') return; if (node.value !== 'linear-gradient') return; const args = node.nodes.reduce((args, arg) => { if (arg.type === 'div') args.push([]); else if (arg.type !== 'space') args[args.length - 1].push(arg.value); return args; }, [[]]); let angle = valueParser.unit(args[0][0]); if (angle.unit !== 'deg') return; angle = parseInt(angle.number); if (angle < 0) angle += 360; // Angle is in degrees, but we need radians const radians = angle * math.pi / 180; const gradientLine = (math.abs(math.sin(radians)) + math.abs(math.cos(radians))); const cathetus = fn => math.round(fn(radians - math.pi / 2) * gradientLine / 2, 10); const x = cathetus(math.cos); const y = cathetus(math.sin); const start = { x: 0.5 - x, y: 0.5 - y }; const end = { x: 0.5 + x, y: 0.5 + y }; let stops = [] let lastPosition = 0; args.slice(1).forEach((arg, index) => { let [color, position = !index ? '0%' : '100%'] = arg; position = parseInt(position) / 100; if (position < lastPosition) position = lastPosition; lastPosition = position; color = parseColor(color).hex; color = parseInt(color.slice(1), 16) stops.push({ color, position }) }); gradients[gradients.length - 1] = { name, start, end, stops }; }); if (!gradients[gradients.length - 1]) return; // Not supported enums.push(name); if (mode == 'debug') console.log(name, args, gradients[gradients.length - 1]) else if (mode == 'enums') console.log(`${name} = ${gradients.length},`) }); // Done walking declarations if (mode == 'json') console.log(JSON.stringify(gradients, undefined, 4)); }); });