summaryrefslogtreecommitdiff
path: root/node_modules/svgo/plugins/applyTransforms.js
diff options
context:
space:
mode:
authorlittleblack111 <littleblack11111@gmail.com>2023-10-14 15:05:55 +0800
committerlittleblack111 <littleblack11111@gmail.com>2023-10-14 15:05:55 +0800
commitc06f7ee0a40255214c477e13d9b956a7e07c2900 (patch)
treef5982a568ef8fab865d0142e71c7494fea3e4c1b /node_modules/svgo/plugins/applyTransforms.js
parent3fd9400d4dccc25aa29b5702216732e0b7542073 (diff)
postcss,(plugins): nanocss, postcss-preset-env
Diffstat (limited to 'node_modules/svgo/plugins/applyTransforms.js')
-rw-r--r--node_modules/svgo/plugins/applyTransforms.js379
1 files changed, 379 insertions, 0 deletions
diff --git a/node_modules/svgo/plugins/applyTransforms.js b/node_modules/svgo/plugins/applyTransforms.js
new file mode 100644
index 00000000..bf60ac89
--- /dev/null
+++ b/node_modules/svgo/plugins/applyTransforms.js
@@ -0,0 +1,379 @@
+'use strict';
+
+/**
+ * @typedef {import('../lib/types').PathDataItem} PathDataItem
+ * @typedef {import('../lib/types').XastElement} XastElement
+ */
+
+const { collectStylesheet, computeStyle } = require('../lib/style.js');
+const {
+ transformsMultiply,
+ transform2js,
+ transformArc,
+} = require('./_transforms.js');
+const { path2js } = require('./_path.js');
+const { removeLeadingZero } = require('../lib/svgo/tools.js');
+const { referencesProps, attrsGroupsDefaults } = require('./_collections.js');
+
+/**
+ * @typedef {Array<PathDataItem>} PathData
+ * @typedef {Array<number>} Matrix
+ */
+
+const regNumericValues = /[-+]?(\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/g;
+
+/**
+ * Apply transformation(s) to the Path data.
+ *
+ * @type {import('../lib/types').Plugin<{
+ * transformPrecision: number,
+ * applyTransformsStroked: boolean,
+ * }>}
+ */
+const applyTransforms = (root, params) => {
+ const stylesheet = collectStylesheet(root);
+ return {
+ element: {
+ enter: (node) => {
+ const computedStyle = computeStyle(stylesheet, node);
+
+ // used only for paths for now
+ if (node.attributes.d == null) {
+ return;
+ }
+
+ // stroke and stroke-width can be redefined with <use>
+ if (node.attributes.id != null) {
+ return;
+ }
+
+ // if there are no 'stroke' attr and references to other objects such as
+ // gradiends or clip-path which are also subjects to transform.
+ if (
+ node.attributes.transform == null ||
+ node.attributes.transform === '' ||
+ // styles are not considered when applying transform
+ // can be fixed properly with new style engine
+ node.attributes.style != null ||
+ Object.entries(node.attributes).some(
+ ([name, value]) =>
+ referencesProps.includes(name) && value.includes('url(')
+ )
+ ) {
+ return;
+ }
+
+ const matrix = transformsMultiply(
+ transform2js(node.attributes.transform)
+ );
+ const stroke =
+ computedStyle.stroke != null && computedStyle.stroke.type === 'static'
+ ? computedStyle.stroke.value
+ : null;
+
+ const strokeWidth =
+ computedStyle['stroke-width'] != null &&
+ computedStyle['stroke-width'].type === 'static'
+ ? computedStyle['stroke-width'].value
+ : null;
+ const transformPrecision = params.transformPrecision;
+
+ if (
+ (computedStyle.stroke != null &&
+ computedStyle.stroke.type === 'dynamic') ||
+ (computedStyle.strokeWidth != null &&
+ computedStyle['stroke-width'].type === 'dynamic')
+ ) {
+ return;
+ }
+
+ const scale = Number(
+ Math.sqrt(
+ matrix.data[0] * matrix.data[0] + matrix.data[1] * matrix.data[1]
+ ).toFixed(transformPrecision)
+ );
+
+ if (stroke && stroke != 'none') {
+ if (params.applyTransformsStroked === false) {
+ return;
+ }
+
+ // stroke cannot be transformed with different vertical and horizontal scale or skew
+ if (
+ (matrix.data[0] !== matrix.data[3] ||
+ matrix.data[1] !== -matrix.data[2]) &&
+ (matrix.data[0] !== -matrix.data[3] ||
+ matrix.data[1] !== matrix.data[2])
+ ) {
+ return;
+ }
+
+ // apply transform to stroke-width, stroke-dashoffset and stroke-dasharray
+ if (scale !== 1) {
+ if (node.attributes['vector-effect'] !== 'non-scaling-stroke') {
+ node.attributes['stroke-width'] = (
+ strokeWidth || attrsGroupsDefaults.presentation['stroke-width']
+ )
+ .trim()
+ .replace(regNumericValues, (num) =>
+ removeLeadingZero(Number(num) * scale)
+ );
+
+ if (node.attributes['stroke-dashoffset'] != null) {
+ node.attributes['stroke-dashoffset'] = node.attributes[
+ 'stroke-dashoffset'
+ ]
+ .trim()
+ .replace(regNumericValues, (num) =>
+ removeLeadingZero(Number(num) * scale)
+ );
+ }
+
+ if (node.attributes['stroke-dasharray'] != null) {
+ node.attributes['stroke-dasharray'] = node.attributes[
+ 'stroke-dasharray'
+ ]
+ .trim()
+ .replace(regNumericValues, (num) =>
+ removeLeadingZero(Number(num) * scale)
+ );
+ }
+ }
+ }
+ }
+
+ const pathData = path2js(node);
+ applyMatrixToPathData(pathData, matrix.data);
+
+ // remove transform attr
+ delete node.attributes.transform;
+ },
+ },
+ };
+};
+exports.applyTransforms = applyTransforms;
+
+/**
+ * @type {(matrix: Matrix, x: number, y: number) => [number, number]}
+ */
+const transformAbsolutePoint = (matrix, x, y) => {
+ const newX = matrix[0] * x + matrix[2] * y + matrix[4];
+ const newY = matrix[1] * x + matrix[3] * y + matrix[5];
+ return [newX, newY];
+};
+
+/**
+ * @type {(matrix: Matrix, x: number, y: number) => [number, number]}
+ */
+const transformRelativePoint = (matrix, x, y) => {
+ const newX = matrix[0] * x + matrix[2] * y;
+ const newY = matrix[1] * x + matrix[3] * y;
+ return [newX, newY];
+};
+
+/**
+ * @type {(pathData: PathData, matrix: Matrix) => void}
+ */
+const applyMatrixToPathData = (pathData, matrix) => {
+ /**
+ * @type {[number, number]}
+ */
+ const start = [0, 0];
+ /**
+ * @type {[number, number]}
+ */
+ const cursor = [0, 0];
+
+ for (const pathItem of pathData) {
+ let { command, args } = pathItem;
+
+ // moveto (x y)
+ if (command === 'M') {
+ cursor[0] = args[0];
+ cursor[1] = args[1];
+ start[0] = cursor[0];
+ start[1] = cursor[1];
+ const [x, y] = transformAbsolutePoint(matrix, args[0], args[1]);
+ args[0] = x;
+ args[1] = y;
+ }
+ if (command === 'm') {
+ cursor[0] += args[0];
+ cursor[1] += args[1];
+ start[0] = cursor[0];
+ start[1] = cursor[1];
+ const [x, y] = transformRelativePoint(matrix, args[0], args[1]);
+ args[0] = x;
+ args[1] = y;
+ }
+
+ // horizontal lineto (x)
+ // convert to lineto to handle two-dimentional transforms
+ if (command === 'H') {
+ command = 'L';
+ args = [args[0], cursor[1]];
+ }
+ if (command === 'h') {
+ command = 'l';
+ args = [args[0], 0];
+ }
+
+ // vertical lineto (y)
+ // convert to lineto to handle two-dimentional transforms
+ if (command === 'V') {
+ command = 'L';
+ args = [cursor[0], args[0]];
+ }
+ if (command === 'v') {
+ command = 'l';
+ args = [0, args[0]];
+ }
+
+ // lineto (x y)
+ if (command === 'L') {
+ cursor[0] = args[0];
+ cursor[1] = args[1];
+ const [x, y] = transformAbsolutePoint(matrix, args[0], args[1]);
+ args[0] = x;
+ args[1] = y;
+ }
+ if (command === 'l') {
+ cursor[0] += args[0];
+ cursor[1] += args[1];
+ const [x, y] = transformRelativePoint(matrix, args[0], args[1]);
+ args[0] = x;
+ args[1] = y;
+ }
+
+ // curveto (x1 y1 x2 y2 x y)
+ if (command === 'C') {
+ cursor[0] = args[4];
+ cursor[1] = args[5];
+ const [x1, y1] = transformAbsolutePoint(matrix, args[0], args[1]);
+ const [x2, y2] = transformAbsolutePoint(matrix, args[2], args[3]);
+ const [x, y] = transformAbsolutePoint(matrix, args[4], args[5]);
+ args[0] = x1;
+ args[1] = y1;
+ args[2] = x2;
+ args[3] = y2;
+ args[4] = x;
+ args[5] = y;
+ }
+ if (command === 'c') {
+ cursor[0] += args[4];
+ cursor[1] += args[5];
+ const [x1, y1] = transformRelativePoint(matrix, args[0], args[1]);
+ const [x2, y2] = transformRelativePoint(matrix, args[2], args[3]);
+ const [x, y] = transformRelativePoint(matrix, args[4], args[5]);
+ args[0] = x1;
+ args[1] = y1;
+ args[2] = x2;
+ args[3] = y2;
+ args[4] = x;
+ args[5] = y;
+ }
+
+ // smooth curveto (x2 y2 x y)
+ if (command === 'S') {
+ cursor[0] = args[2];
+ cursor[1] = args[3];
+ const [x2, y2] = transformAbsolutePoint(matrix, args[0], args[1]);
+ const [x, y] = transformAbsolutePoint(matrix, args[2], args[3]);
+ args[0] = x2;
+ args[1] = y2;
+ args[2] = x;
+ args[3] = y;
+ }
+ if (command === 's') {
+ cursor[0] += args[2];
+ cursor[1] += args[3];
+ const [x2, y2] = transformRelativePoint(matrix, args[0], args[1]);
+ const [x, y] = transformRelativePoint(matrix, args[2], args[3]);
+ args[0] = x2;
+ args[1] = y2;
+ args[2] = x;
+ args[3] = y;
+ }
+
+ // quadratic Bézier curveto (x1 y1 x y)
+ if (command === 'Q') {
+ cursor[0] = args[2];
+ cursor[1] = args[3];
+ const [x1, y1] = transformAbsolutePoint(matrix, args[0], args[1]);
+ const [x, y] = transformAbsolutePoint(matrix, args[2], args[3]);
+ args[0] = x1;
+ args[1] = y1;
+ args[2] = x;
+ args[3] = y;
+ }
+ if (command === 'q') {
+ cursor[0] += args[2];
+ cursor[1] += args[3];
+ const [x1, y1] = transformRelativePoint(matrix, args[0], args[1]);
+ const [x, y] = transformRelativePoint(matrix, args[2], args[3]);
+ args[0] = x1;
+ args[1] = y1;
+ args[2] = x;
+ args[3] = y;
+ }
+
+ // smooth quadratic Bézier curveto (x y)
+ if (command === 'T') {
+ cursor[0] = args[0];
+ cursor[1] = args[1];
+ const [x, y] = transformAbsolutePoint(matrix, args[0], args[1]);
+ args[0] = x;
+ args[1] = y;
+ }
+ if (command === 't') {
+ cursor[0] += args[0];
+ cursor[1] += args[1];
+ const [x, y] = transformRelativePoint(matrix, args[0], args[1]);
+ args[0] = x;
+ args[1] = y;
+ }
+
+ // elliptical arc (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
+ if (command === 'A') {
+ transformArc(cursor, args, matrix);
+ cursor[0] = args[5];
+ cursor[1] = args[6];
+ // reduce number of digits in rotation angle
+ if (Math.abs(args[2]) > 80) {
+ const a = args[0];
+ const rotation = args[2];
+ args[0] = args[1];
+ args[1] = a;
+ args[2] = rotation + (rotation > 0 ? -90 : 90);
+ }
+ const [x, y] = transformAbsolutePoint(matrix, args[5], args[6]);
+ args[5] = x;
+ args[6] = y;
+ }
+ if (command === 'a') {
+ transformArc([0, 0], args, matrix);
+ cursor[0] += args[5];
+ cursor[1] += args[6];
+ // reduce number of digits in rotation angle
+ if (Math.abs(args[2]) > 80) {
+ const a = args[0];
+ const rotation = args[2];
+ args[0] = args[1];
+ args[1] = a;
+ args[2] = rotation + (rotation > 0 ? -90 : 90);
+ }
+ const [x, y] = transformRelativePoint(matrix, args[5], args[6]);
+ args[5] = x;
+ args[6] = y;
+ }
+
+ // closepath
+ if (command === 'z' || command === 'Z') {
+ cursor[0] = start[0];
+ cursor[1] = start[1];
+ }
+
+ pathItem.command = command;
+ pathItem.args = args;
+ }
+};