diff --git a/plugins/convertPathData.js b/plugins/convertPathData.js index 1f032b3e9..0d310cb6f 100644 --- a/plugins/convertPathData.js +++ b/plugins/convertPathData.js @@ -155,13 +155,25 @@ export const fn = (root, params) => { computedStyle['stroke-linecap'] && (computedStyle['stroke-linecap'].type === 'dynamic' || computedStyle['stroke-linecap'].value !== 'butt'); - const maybeHasStrokeAndLinecap = maybeHasStroke && maybeHasLinecap; const isSafeToUseZ = maybeHasStroke ? computedStyle['stroke-linecap']?.type === 'static' && computedStyle['stroke-linecap'].value === 'round' && computedStyle['stroke-linejoin']?.type === 'static' && computedStyle['stroke-linejoin'].value === 'round' : true; + const isSafeToRemove = ( + /** @type {boolean} */ isFirstDraw, + /** @type {boolean} */ safeIfNotFirstDraw, + ) => { + if (!maybeHasStroke) { + return true; + } + if (isFirstDraw) { + return !maybeHasLinecap; + } else { + return safeIfNotFirstDraw; + } + }; let data = path2js(node); @@ -174,7 +186,7 @@ export const fn = (root, params) => { data = filters(data, newParams, { isSafeToUseZ, - maybeHasStrokeAndLinecap, + isSafeToRemove, hasMarkerMid, }); @@ -387,14 +399,10 @@ const convertToRelative = (pathData) => { * * @param {import('../lib/types.js').PathDataItem[]} path * @param {InternalParams} params - * @param {{ isSafeToUseZ: boolean, maybeHasStrokeAndLinecap: boolean, hasMarkerMid: boolean }} param2 + * @param {{ isSafeToUseZ: boolean, isSafeToRemove: (isFirstDraw: boolean, safeIfNotFirstDraw: boolean) => boolean, hasMarkerMid: boolean }} param2 * @returns {import('../lib/types.js').PathDataItem[]} */ -function filters( - path, - params, - { isSafeToUseZ, maybeHasStrokeAndLinecap, hasMarkerMid }, -) { +function filters(path, params, { isSafeToUseZ, isSafeToRemove, hasMarkerMid }) { const stringify = data2Path.bind(null, params); const relSubpoint = [0, 0]; const pathBase = [0, 0]; @@ -844,7 +852,10 @@ function filters( } // remove useless non-first path segments - if (params.removeUseless && !maybeHasStrokeAndLinecap) { + if ( + params.removeUseless && + isSafeToRemove(prev.command == 'm' || prev.command == 'M', true) + ) { // l 0,0 / h 0 / v 0 / q 0,0 0,0 / t 0,0 / c 0,0 0,0 0,0 / s 0,0 0,0 if ( (command === 'l' || @@ -900,7 +911,10 @@ function filters( if ( (command === 'Z' || command === 'z') && params.removeUseless && - isSafeToUseZ && + isSafeToRemove( + prev.command == 'm' || prev.command == 'M', + isSafeToUseZ, + ) && // @ts-expect-error Math.abs(item.base[0] - item.coords[0]) < error / 10 && // @ts-expect-error diff --git a/test/plugins/convertPathData.38.svg.txt b/test/plugins/convertPathData.38.svg.txt new file mode 100644 index 000000000..5dc923a52 --- /dev/null +++ b/test/plugins/convertPathData.38.svg.txt @@ -0,0 +1,15 @@ +Should not break dots. + +See: https://github.com/svg/svgo/issues/2163 + +=== + + + + + +@@@ + + + + diff --git a/test/plugins/convertPathData.39.svg.txt b/test/plugins/convertPathData.39.svg.txt new file mode 100644 index 000000000..0cd9053c6 --- /dev/null +++ b/test/plugins/convertPathData.39.svg.txt @@ -0,0 +1,13 @@ +Should drop truely useless commands even when a linecap is present. + +=== + + + + + +@@@ + + + +