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.
+
+===
+
+
+
+@@@
+
+