Remove empty closed paths

As discussed in the github issue,
https://github.com/whatwg/html/issues/1079, it's generally agreed to
skip drawing line caps for closed paths. This is a follow up cl of:
https://chromium-review.googlesource.com/c/chromium/src/+/4864061.

In this cl, it verifies if each closed path is empty, then it removes
the empty closed subpaths from path. As the subpaths are removed, the
corresponding line caps are skipped.

fix

Change-Id: Ic4a2f23470a7c1abcc5b9793cd100451db3a4ac1
diff --git a/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.arc-expected.html b/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.arc-expected.html
new file mode 100644
index 0000000..7c0faba
--- /dev/null
+++ b/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.arc-expected.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.path.stroke.prune.closePath.arc</title>
+<h1>2d.path.stroke.prune.closePath.arc</h1>
+<p class="desc">Test if zero-lengthed closePath before and after arc are ignored corrected.</p>
+<canvas id="canvas" width="100" height="50">
+  <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script>
+  const canvas = document.getElementById("canvas");
+  const ctx = canvas.getContext('2d');
+
+  ctx.fillStyle = '#0f0';
+  ctx.fillRect(0, 0, 100, 50);
+
+  ctx.strokeStyle = '#f00';
+  ctx.lineWidth = 10;
+  ctx.lineCap = 'round';
+  ctx.lineJoin = 'round';
+
+  ctx.moveTo(10, 10);
+  ctx.arc(20, 20, 15, 0, Math.PI);
+  ctx.closePath();
+  ctx.stroke();
+</script>
diff --git a/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.arc.html b/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.arc.html
new file mode 100644
index 0000000..4b1d069
--- /dev/null
+++ b/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.arc.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.path.stroke.prune.closePath.arc-expected.html">
+<title>Canvas test: 2d.path.stroke.prune.closePath.arc</title>
+<h1>2d.path.stroke.prune.closePath.arc</h1>
+<p class="desc">Test if zero-lengthed closePath before and after arc are ignored corrected.</p>
+<canvas id="canvas" width="100" height="50">
+  <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script>
+  const canvas = document.getElementById("canvas");
+  const ctx = canvas.getContext('2d');
+
+  ctx.fillStyle = '#0f0';
+  ctx.fillRect(0, 0, 100, 50);
+
+  ctx.strokeStyle = '#f00';
+  ctx.lineWidth = 10;
+  ctx.lineCap = 'round';
+  ctx.lineJoin = 'round';
+
+  ctx.beginPath();
+  ctx.moveTo(50, 25);
+  ctx.lineTo(50, 25);
+  ctx.closePath();
+
+  ctx.moveTo(10, 10);
+  ctx.arc(20, 20, 15, 0, Math.PI);
+  ctx.closePath();
+
+  ctx.moveTo(40, 40);
+  ctx.lineTo(40, 40);
+  ctx.closePath();
+  ctx.stroke();
+</script>
diff --git a/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.bezierCurve-expected.html b/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.bezierCurve-expected.html
new file mode 100644
index 0000000..4b867f8
--- /dev/null
+++ b/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.bezierCurve-expected.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.path.stroke.prune.closePath.bezierCurve</title>
+<h1>2d.path.stroke.prune.closePath.bezierCurve</h1>
+<p class="desc">Test if zero-lengthed closePath before and after bezier curve are ignored corrected.</p>
+<canvas id="canvas" width="100" height="50">
+  <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script>
+  const canvas = document.getElementById("canvas");
+  const ctx = canvas.getContext('2d');
+
+  ctx.fillStyle = '#0f0';
+  ctx.fillRect(0, 0, 100, 50);
+
+  ctx.strokeStyle = '#f00';
+  ctx.lineWidth = 10;
+  ctx.lineCap = 'round';
+  ctx.lineJoin = 'round';
+
+  ctx.moveTo(10, 10);
+  ctx.bezierCurveTo(10, 30, 40, 50, 100, 50);
+  ctx.closePath();
+  ctx.stroke();
+</script>
diff --git a/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.bezierCurve.html b/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.bezierCurve.html
new file mode 100644
index 0000000..2c974bd
--- /dev/null
+++ b/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.bezierCurve.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.path.stroke.prune.closePath.bezierCurve-expected.html">
+<title>Canvas test: 2d.path.stroke.prune.closePath.bezierCurve</title>
+<h1>2d.path.stroke.prune.closePath.bezierCurve</h1>
+<p class="desc">Test if zero-lengthed closePath before and after bezier curve are ignored corrected.</p>
+<canvas id="canvas" width="100" height="50">
+  <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script>
+  const canvas = document.getElementById("canvas");
+  const ctx = canvas.getContext('2d');
+
+  ctx.fillStyle = '#0f0';
+  ctx.fillRect(0, 0, 100, 50);
+
+  ctx.strokeStyle = '#f00';
+  ctx.lineWidth = 10;
+  ctx.lineCap = 'round';
+  ctx.lineJoin = 'round';
+
+  ctx.beginPath();
+  ctx.moveTo(5, 5);
+  ctx.lineTo(5, 5);
+  ctx.closePath();
+
+  ctx.moveTo(10, 10);
+  ctx.bezierCurveTo(10, 30, 40, 50, 100, 50);
+  ctx.closePath();
+
+  ctx.moveTo(20, 40);
+  ctx.lineTo(20, 40);
+  ctx.closePath();
+  ctx.stroke();
+</script>
diff --git a/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.line-expected.html b/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.line-expected.html
new file mode 100644
index 0000000..87a99c7
--- /dev/null
+++ b/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.line-expected.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.path.stroke.prune.closePath.line</title>
+<h1>2d.path.stroke.prune.closePath.line</h1>
+<p class="desc">Test if zero-lengthed closePath before and after line are ignored corrected.</p>
+<canvas id="canvas" width="100" height="50">
+  <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script>
+  const canvas = document.getElementById("canvas");
+  const ctx = canvas.getContext('2d');
+
+  ctx.fillStyle = '#0f0';
+  ctx.fillRect(0, 0, 100, 50);
+
+  ctx.strokeStyle = '#f00';
+  ctx.lineWidth = 10;
+  ctx.lineCap = 'round';
+  ctx.lineJoin = 'round';
+
+  ctx.moveTo(10, 10);
+  ctx.lineTo(40, 40);
+  ctx.closePath();
+  ctx.stroke();
+</script>
diff --git a/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.line.html b/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.line.html
new file mode 100644
index 0000000..655b2e1
--- /dev/null
+++ b/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.line.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.path.stroke.prune.closePath.line-expected.html">
+<title>Canvas test: 2d.path.stroke.prune.closePath.line</title>
+<h1>2d.path.stroke.prune.closePath.line</h1>
+<p class="desc">Test if zero-lengthed closePath before and after line are ignored corrected.</p>
+<canvas id="canvas" width="100" height="50">
+  <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script>
+  const canvas = document.getElementById("canvas");
+  const ctx = canvas.getContext('2d');
+
+  ctx.fillStyle = '#0f0';
+  ctx.fillRect(0, 0, 100, 50);
+
+  ctx.strokeStyle = '#f00';
+  ctx.lineWidth = 10;
+  ctx.lineCap = 'round';
+  ctx.lineJoin = 'round';
+
+  ctx.beginPath();
+  ctx.moveTo(50, 25);
+  ctx.lineTo(50, 25);
+  ctx.closePath();
+
+  ctx.moveTo(10, 10);
+  ctx.lineTo(40, 40);
+  ctx.closePath();
+
+  ctx.moveTo(45, 45);
+  ctx.lineTo(45, 45);
+  ctx.closePath();
+  ctx.stroke();
+</script>
diff --git a/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.quadraticCurve-expected.html b/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.quadraticCurve-expected.html
new file mode 100644
index 0000000..03635b0
--- /dev/null
+++ b/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.quadraticCurve-expected.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.path.stroke.prune.closePath.quadraticCurve</title>
+<h1>2d.path.stroke.prune.closePath.quadraticCurve</h1>
+<p class="desc">Test if zero-lengthed closePath before and after quadratic curve are ignored corrected.</p>
+<canvas id="canvas" width="100" height="50">
+  <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script>
+  const canvas = document.getElementById("canvas");
+  const ctx = canvas.getContext('2d');
+
+  ctx.fillStyle = '#0f0';
+  ctx.fillRect(0, 0, 100, 50);
+
+  ctx.strokeStyle = '#f00';
+  ctx.lineWidth = 10;
+  ctx.lineCap = 'round';
+  ctx.lineJoin = 'round';
+
+  ctx.moveTo(10, 10);
+  ctx.quadraticCurveTo(80, 10, 100, 50);
+  ctx.closePath();
+  ctx.stroke();
+</script>
diff --git a/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.quadraticCurve.html b/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.quadraticCurve.html
new file mode 100644
index 0000000..9066770
--- /dev/null
+++ b/html/canvas/element/path-objects/2d.path.stroke.prune.closePath.quadraticCurve.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.path.stroke.prune.closePath.quadraticCurve-expected.html">
+<title>Canvas test: 2d.path.stroke.prune.closePath.quadraticCurve</title>
+<h1>2d.path.stroke.prune.closePath.quadraticCurve</h1>
+<p class="desc">Test if zero-lengthed closePath before and after quadratic curve are ignored corrected.</p>
+<canvas id="canvas" width="100" height="50">
+  <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script>
+  const canvas = document.getElementById("canvas");
+  const ctx = canvas.getContext('2d');
+
+  ctx.fillStyle = '#0f0';
+  ctx.fillRect(0, 0, 100, 50);
+
+  ctx.strokeStyle = '#f00';
+  ctx.lineWidth = 10;
+  ctx.lineCap = 'round';
+  ctx.lineJoin = 'round';
+
+  ctx.beginPath();
+  ctx.moveTo(5, 5);
+  ctx.lineTo(5, 5);
+  ctx.closePath();
+
+  ctx.moveTo(10, 10);
+  ctx.quadraticCurveTo(80, 10, 100, 50);
+  ctx.closePath();
+
+  ctx.moveTo(40, 40);
+  ctx.lineTo(40, 40);
+  ctx.closePath();
+  ctx.stroke();
+</script>
diff --git a/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.arc-expected.html b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.arc-expected.html
new file mode 100644
index 0000000..7c0faba
--- /dev/null
+++ b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.arc-expected.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.path.stroke.prune.closePath.arc</title>
+<h1>2d.path.stroke.prune.closePath.arc</h1>
+<p class="desc">Test if zero-lengthed closePath before and after arc are ignored corrected.</p>
+<canvas id="canvas" width="100" height="50">
+  <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script>
+  const canvas = document.getElementById("canvas");
+  const ctx = canvas.getContext('2d');
+
+  ctx.fillStyle = '#0f0';
+  ctx.fillRect(0, 0, 100, 50);
+
+  ctx.strokeStyle = '#f00';
+  ctx.lineWidth = 10;
+  ctx.lineCap = 'round';
+  ctx.lineJoin = 'round';
+
+  ctx.moveTo(10, 10);
+  ctx.arc(20, 20, 15, 0, Math.PI);
+  ctx.closePath();
+  ctx.stroke();
+</script>
diff --git a/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.arc.html b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.arc.html
new file mode 100644
index 0000000..aeff5bf
--- /dev/null
+++ b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.arc.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.path.stroke.prune.closePath.arc-expected.html">
+<title>Canvas test: 2d.path.stroke.prune.closePath.arc</title>
+<h1>2d.path.stroke.prune.closePath.arc</h1>
+<p class="desc">Test if zero-lengthed closePath before and after arc are ignored corrected.</p>
+<canvas id="canvas" width="100" height="50">
+  <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script>
+  const canvas = new OffscreenCanvas(100, 50);
+  const ctx = canvas.getContext('2d');
+
+  ctx.fillStyle = '#0f0';
+  ctx.fillRect(0, 0, 100, 50);
+
+  ctx.strokeStyle = '#f00';
+  ctx.lineWidth = 10;
+  ctx.lineCap = 'round';
+  ctx.lineJoin = 'round';
+
+  ctx.beginPath();
+  ctx.moveTo(50, 25);
+  ctx.lineTo(50, 25);
+  ctx.closePath();
+
+  ctx.moveTo(10, 10);
+  ctx.arc(20, 20, 15, 0, Math.PI);
+  ctx.closePath();
+
+  ctx.moveTo(40, 40);
+  ctx.lineTo(40, 40);
+  ctx.closePath();
+  ctx.stroke();
+
+  const outputCanvas = document.getElementById("canvas");
+  outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
+</script>
diff --git a/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.arc.w.html b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.arc.w.html
new file mode 100644
index 0000000..f108362
--- /dev/null
+++ b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.arc.w.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.path.stroke.prune.closePath.arc-expected.html">
+<title>Canvas test: 2d.path.stroke.prune.closePath.arc</title>
+<h1>2d.path.stroke.prune.closePath.arc</h1>
+<p class="desc">Test if zero-lengthed closePath before and after arc are ignored corrected.</p>
+<canvas id="canvas" width="100" height="50">
+  <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script id='myWorker' type='text/worker'>
+  self.onmessage = function(e) {
+    const canvas = new OffscreenCanvas(100, 50);
+    const ctx = canvas.getContext('2d');
+
+    ctx.fillStyle = '#0f0';
+    ctx.fillRect(0, 0, 100, 50);
+
+    ctx.strokeStyle = '#f00';
+    ctx.lineWidth = 10;
+    ctx.lineCap = 'round';
+    ctx.lineJoin = 'round';
+
+    ctx.beginPath();
+    ctx.moveTo(50, 25);
+    ctx.lineTo(50, 25);
+    ctx.closePath();
+
+    ctx.moveTo(10, 10);
+    ctx.arc(20, 20, 15, 0, Math.PI);
+    ctx.closePath();
+
+    ctx.moveTo(40, 40);
+    ctx.lineTo(40, 40);
+    ctx.closePath();
+    ctx.stroke();
+
+    const bitmap = canvas.transferToImageBitmap();
+    self.postMessage(bitmap, bitmap);
+  };
+</script>
+<script>
+  const blob = new Blob([document.getElementById('myWorker').textContent]);
+  const worker = new Worker(URL.createObjectURL(blob));
+  worker.addEventListener('message', msg => {
+    const outputCtx = document.getElementById("canvas").getContext('2d');
+    outputCtx.drawImage(msg.data, 0, 0);
+    document.documentElement.classList.remove("reftest-wait");
+  });
+  worker.postMessage(null);
+</script>
+</html>
diff --git a/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.bezierCurve-expected.html b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.bezierCurve-expected.html
new file mode 100644
index 0000000..4b867f8
--- /dev/null
+++ b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.bezierCurve-expected.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.path.stroke.prune.closePath.bezierCurve</title>
+<h1>2d.path.stroke.prune.closePath.bezierCurve</h1>
+<p class="desc">Test if zero-lengthed closePath before and after bezier curve are ignored corrected.</p>
+<canvas id="canvas" width="100" height="50">
+  <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script>
+  const canvas = document.getElementById("canvas");
+  const ctx = canvas.getContext('2d');
+
+  ctx.fillStyle = '#0f0';
+  ctx.fillRect(0, 0, 100, 50);
+
+  ctx.strokeStyle = '#f00';
+  ctx.lineWidth = 10;
+  ctx.lineCap = 'round';
+  ctx.lineJoin = 'round';
+
+  ctx.moveTo(10, 10);
+  ctx.bezierCurveTo(10, 30, 40, 50, 100, 50);
+  ctx.closePath();
+  ctx.stroke();
+</script>
diff --git a/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.bezierCurve.html b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.bezierCurve.html
new file mode 100644
index 0000000..09d3152
--- /dev/null
+++ b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.bezierCurve.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.path.stroke.prune.closePath.bezierCurve-expected.html">
+<title>Canvas test: 2d.path.stroke.prune.closePath.bezierCurve</title>
+<h1>2d.path.stroke.prune.closePath.bezierCurve</h1>
+<p class="desc">Test if zero-lengthed closePath before and after bezier curve are ignored corrected.</p>
+<canvas id="canvas" width="100" height="50">
+  <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script>
+  const canvas = new OffscreenCanvas(100, 50);
+  const ctx = canvas.getContext('2d');
+
+  ctx.fillStyle = '#0f0';
+  ctx.fillRect(0, 0, 100, 50);
+
+  ctx.strokeStyle = '#f00';
+  ctx.lineWidth = 10;
+  ctx.lineCap = 'round';
+  ctx.lineJoin = 'round';
+
+  ctx.beginPath();
+  ctx.moveTo(5, 5);
+  ctx.lineTo(5, 5);
+  ctx.closePath();
+
+  ctx.moveTo(10, 10);
+  ctx.bezierCurveTo(10, 30, 40, 50, 100, 50);
+  ctx.closePath();
+
+  ctx.moveTo(20, 40);
+  ctx.lineTo(20, 40);
+  ctx.closePath();
+  ctx.stroke();
+
+  const outputCanvas = document.getElementById("canvas");
+  outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
+</script>
diff --git a/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.bezierCurve.w.html b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.bezierCurve.w.html
new file mode 100644
index 0000000..66f15eb
--- /dev/null
+++ b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.bezierCurve.w.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.path.stroke.prune.closePath.bezierCurve-expected.html">
+<title>Canvas test: 2d.path.stroke.prune.closePath.bezierCurve</title>
+<h1>2d.path.stroke.prune.closePath.bezierCurve</h1>
+<p class="desc">Test if zero-lengthed closePath before and after bezier curve are ignored corrected.</p>
+<canvas id="canvas" width="100" height="50">
+  <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script id='myWorker' type='text/worker'>
+  self.onmessage = function(e) {
+    const canvas = new OffscreenCanvas(100, 50);
+    const ctx = canvas.getContext('2d');
+
+    ctx.fillStyle = '#0f0';
+    ctx.fillRect(0, 0, 100, 50);
+
+    ctx.strokeStyle = '#f00';
+    ctx.lineWidth = 10;
+    ctx.lineCap = 'round';
+    ctx.lineJoin = 'round';
+
+    ctx.beginPath();
+    ctx.moveTo(5, 5);
+    ctx.lineTo(5, 5);
+    ctx.closePath();
+
+    ctx.moveTo(10, 10);
+    ctx.bezierCurveTo(10, 30, 40, 50, 100, 50);
+    ctx.closePath();
+
+    ctx.moveTo(20, 40);
+    ctx.lineTo(20, 40);
+    ctx.closePath();
+    ctx.stroke();
+
+    const bitmap = canvas.transferToImageBitmap();
+    self.postMessage(bitmap, bitmap);
+  };
+</script>
+<script>
+  const blob = new Blob([document.getElementById('myWorker').textContent]);
+  const worker = new Worker(URL.createObjectURL(blob));
+  worker.addEventListener('message', msg => {
+    const outputCtx = document.getElementById("canvas").getContext('2d');
+    outputCtx.drawImage(msg.data, 0, 0);
+    document.documentElement.classList.remove("reftest-wait");
+  });
+  worker.postMessage(null);
+</script>
+</html>
diff --git a/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.line-expected.html b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.line-expected.html
new file mode 100644
index 0000000..87a99c7
--- /dev/null
+++ b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.line-expected.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.path.stroke.prune.closePath.line</title>
+<h1>2d.path.stroke.prune.closePath.line</h1>
+<p class="desc">Test if zero-lengthed closePath before and after line are ignored corrected.</p>
+<canvas id="canvas" width="100" height="50">
+  <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script>
+  const canvas = document.getElementById("canvas");
+  const ctx = canvas.getContext('2d');
+
+  ctx.fillStyle = '#0f0';
+  ctx.fillRect(0, 0, 100, 50);
+
+  ctx.strokeStyle = '#f00';
+  ctx.lineWidth = 10;
+  ctx.lineCap = 'round';
+  ctx.lineJoin = 'round';
+
+  ctx.moveTo(10, 10);
+  ctx.lineTo(40, 40);
+  ctx.closePath();
+  ctx.stroke();
+</script>
diff --git a/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.line.html b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.line.html
new file mode 100644
index 0000000..f5a4944
--- /dev/null
+++ b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.line.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.path.stroke.prune.closePath.line-expected.html">
+<title>Canvas test: 2d.path.stroke.prune.closePath.line</title>
+<h1>2d.path.stroke.prune.closePath.line</h1>
+<p class="desc">Test if zero-lengthed closePath before and after line are ignored corrected.</p>
+<canvas id="canvas" width="100" height="50">
+  <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script>
+  const canvas = new OffscreenCanvas(100, 50);
+  const ctx = canvas.getContext('2d');
+
+  ctx.fillStyle = '#0f0';
+  ctx.fillRect(0, 0, 100, 50);
+
+  ctx.strokeStyle = '#f00';
+  ctx.lineWidth = 10;
+  ctx.lineCap = 'round';
+  ctx.lineJoin = 'round';
+
+  ctx.beginPath();
+  ctx.moveTo(50, 25);
+  ctx.lineTo(50, 25);
+  ctx.closePath();
+
+  ctx.moveTo(10, 10);
+  ctx.lineTo(40, 40);
+  ctx.closePath();
+
+  ctx.moveTo(40, 40);
+  ctx.lineTo(40, 40);
+  ctx.closePath();
+  ctx.stroke();
+
+  const outputCanvas = document.getElementById("canvas");
+  outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
+</script>
diff --git a/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.line.w.html b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.line.w.html
new file mode 100644
index 0000000..4583020
--- /dev/null
+++ b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.line.w.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.path.stroke.prune.closePath.line-expected.html">
+<title>Canvas test: 2d.path.stroke.prune.closePath.line</title>
+<h1>2d.path.stroke.prune.closePath.line</h1>
+<p class="desc">Test if zero-lengthed closePath before and after line are ignored corrected.</p>
+<canvas id="canvas" width="100" height="50">
+  <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script id='myWorker' type='text/worker'>
+  self.onmessage = function(e) {
+    const canvas = new OffscreenCanvas(100, 50);
+    const ctx = canvas.getContext('2d');
+
+    ctx.fillStyle = '#0f0';
+    ctx.fillRect(0, 0, 100, 50);
+
+    ctx.strokeStyle = '#f00';
+    ctx.lineWidth = 10;
+    ctx.lineCap = 'round';
+    ctx.lineJoin = 'round';
+
+    ctx.beginPath();
+    ctx.moveTo(50, 25);
+    ctx.lineTo(50, 25);
+    ctx.closePath();
+
+    ctx.moveTo(10, 10);
+    ctx.lineTo(40, 40);
+    ctx.closePath();
+
+    ctx.moveTo(40, 40);
+    ctx.lineTo(40, 40);
+    ctx.closePath();
+    ctx.stroke();
+
+    const bitmap = canvas.transferToImageBitmap();
+    self.postMessage(bitmap, bitmap);
+  };
+</script>
+<script>
+  const blob = new Blob([document.getElementById('myWorker').textContent]);
+  const worker = new Worker(URL.createObjectURL(blob));
+  worker.addEventListener('message', msg => {
+    const outputCtx = document.getElementById("canvas").getContext('2d');
+    outputCtx.drawImage(msg.data, 0, 0);
+    document.documentElement.classList.remove("reftest-wait");
+  });
+  worker.postMessage(null);
+</script>
+</html>
diff --git a/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.quadraticCurve-expected.html b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.quadraticCurve-expected.html
new file mode 100644
index 0000000..03635b0
--- /dev/null
+++ b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.quadraticCurve-expected.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<title>Canvas test: 2d.path.stroke.prune.closePath.quadraticCurve</title>
+<h1>2d.path.stroke.prune.closePath.quadraticCurve</h1>
+<p class="desc">Test if zero-lengthed closePath before and after quadratic curve are ignored corrected.</p>
+<canvas id="canvas" width="100" height="50">
+  <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script>
+  const canvas = document.getElementById("canvas");
+  const ctx = canvas.getContext('2d');
+
+  ctx.fillStyle = '#0f0';
+  ctx.fillRect(0, 0, 100, 50);
+
+  ctx.strokeStyle = '#f00';
+  ctx.lineWidth = 10;
+  ctx.lineCap = 'round';
+  ctx.lineJoin = 'round';
+
+  ctx.moveTo(10, 10);
+  ctx.quadraticCurveTo(80, 10, 100, 50);
+  ctx.closePath();
+  ctx.stroke();
+</script>
diff --git a/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.quadraticCurve.html b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.quadraticCurve.html
new file mode 100644
index 0000000..1d51671
--- /dev/null
+++ b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.quadraticCurve.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<link rel="match" href="2d.path.stroke.prune.closePath.quadraticCurve-expected.html">
+<title>Canvas test: 2d.path.stroke.prune.closePath.quadraticCurve</title>
+<h1>2d.path.stroke.prune.closePath.quadraticCurve</h1>
+<p class="desc">Test if zero-lengthed closePath before and after quadratic curve are ignored corrected.</p>
+<canvas id="canvas" width="100" height="50">
+  <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script>
+  const canvas = new OffscreenCanvas(100, 50);
+  const ctx = canvas.getContext('2d');
+
+  ctx.fillStyle = '#0f0';
+  ctx.fillRect(0, 0, 100, 50);
+
+  ctx.strokeStyle = '#f00';
+  ctx.lineWidth = 10;
+  ctx.lineCap = 'round';
+  ctx.lineJoin = 'round';
+
+  ctx.beginPath();
+  ctx.moveTo(5, 5);
+  ctx.lineTo(5, 5);
+  ctx.closePath();
+
+  ctx.moveTo(10, 10);
+  ctx.quadraticCurveTo(80, 10, 100, 50);
+  ctx.closePath();
+
+  ctx.moveTo(40, 40);
+  ctx.lineTo(40, 40);
+  ctx.closePath();
+  ctx.stroke();
+
+  const outputCanvas = document.getElementById("canvas");
+  outputCanvas.getContext('2d').drawImage(canvas, 0, 0);
+</script>
diff --git a/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.quadraticCurve.w.html b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.quadraticCurve.w.html
new file mode 100644
index 0000000..5bbd273
--- /dev/null
+++ b/html/canvas/offscreen/path-objects/2d.path.stroke.prune.closePath.quadraticCurve.w.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
+<html class="reftest-wait">
+<link rel="match" href="2d.path.stroke.prune.closePath.quadraticCurve-expected.html">
+<title>Canvas test: 2d.path.stroke.prune.closePath.quadraticCurve</title>
+<h1>2d.path.stroke.prune.closePath.quadraticCurve</h1>
+<p class="desc">Test if zero-lengthed closePath before and after quadratic curve are ignored corrected.</p>
+<canvas id="canvas" width="100" height="50">
+  <p class="fallback">FAIL (fallback content)</p>
+</canvas>
+<script id='myWorker' type='text/worker'>
+  self.onmessage = function(e) {
+    const canvas = new OffscreenCanvas(100, 50);
+    const ctx = canvas.getContext('2d');
+
+    ctx.fillStyle = '#0f0';
+    ctx.fillRect(0, 0, 100, 50);
+
+    ctx.strokeStyle = '#f00';
+    ctx.lineWidth = 10;
+    ctx.lineCap = 'round';
+    ctx.lineJoin = 'round';
+
+    ctx.beginPath();
+    ctx.moveTo(5, 5);
+    ctx.lineTo(5, 5);
+    ctx.closePath();
+
+    ctx.moveTo(10, 10);
+    ctx.quadraticCurveTo(80, 10, 100, 50);
+    ctx.closePath();
+
+    ctx.moveTo(40, 40);
+    ctx.lineTo(40, 40);
+    ctx.closePath();
+    ctx.stroke();
+
+    const bitmap = canvas.transferToImageBitmap();
+    self.postMessage(bitmap, bitmap);
+  };
+</script>
+<script>
+  const blob = new Blob([document.getElementById('myWorker').textContent]);
+  const worker = new Worker(URL.createObjectURL(blob));
+  worker.addEventListener('message', msg => {
+    const outputCtx = document.getElementById("canvas").getContext('2d');
+    outputCtx.drawImage(msg.data, 0, 0);
+    document.documentElement.classList.remove("reftest-wait");
+  });
+  worker.postMessage(null);
+</script>
+</html>
diff --git a/html/canvas/tools/yaml-new/path-objects.yaml b/html/canvas/tools/yaml-new/path-objects.yaml
index b1754b9..8e0b981 100644
--- a/html/canvas/tools/yaml-new/path-objects.yaml
+++ b/html/canvas/tools/yaml-new/path-objects.yaml
@@ -2879,6 +2879,158 @@
     @assert pixel 50,25 == 0,255,0,255;
   expected: green
 
+- name: 2d.path.stroke.prune.closePath.line
+  desc: Test if zero-lengthed closePath before and after line are ignored corrected.
+  code: |
+    ctx.fillStyle = '#0f0';
+    ctx.fillRect(0, 0, 100, 50);
+
+    ctx.strokeStyle = '#f00';
+    ctx.lineWidth = 10;
+    ctx.lineCap = 'round';
+    ctx.lineJoin = 'round';
+
+    ctx.beginPath();
+    ctx.moveTo(50, 25);
+    ctx.lineTo(50, 25);
+    ctx.closePath();
+
+    ctx.moveTo(10, 10);
+    ctx.lineTo(40, 40);
+    ctx.closePath();
+
+    ctx.moveTo(40, 40);
+    ctx.lineTo(40, 40);
+    ctx.closePath();
+    ctx.stroke();
+  reference: |
+    ctx.fillStyle = '#0f0';
+    ctx.fillRect(0, 0, 100, 50);
+
+    ctx.strokeStyle = '#f00';
+    ctx.lineWidth = 10;
+    ctx.lineCap = 'round';
+    ctx.lineJoin = 'round';
+
+    ctx.moveTo(10, 10);
+    ctx.lineTo(40, 40);
+    ctx.closePath();
+    ctx.stroke();
+
+- name: 2d.path.stroke.prune.closePath.bezierCurve
+  desc: Test if zero-lengthed closePath before and after bezier curve are ignored corrected.
+  code: |
+    ctx.fillStyle = '#0f0';
+    ctx.fillRect(0, 0, 100, 50);
+
+    ctx.strokeStyle = '#f00';
+    ctx.lineWidth = 10;
+    ctx.lineCap = 'round';
+    ctx.lineJoin = 'round';
+
+    ctx.beginPath();
+    ctx.moveTo(5, 5);
+    ctx.lineTo(5, 5);
+    ctx.closePath();
+
+    ctx.moveTo(10, 10);
+    ctx.bezierCurveTo(10, 30, 40, 50, 100, 50);
+    ctx.closePath();
+
+    ctx.moveTo(20, 40);
+    ctx.lineTo(20, 40);
+    ctx.closePath();
+    ctx.stroke();
+  reference: |
+    ctx.fillStyle = '#0f0';
+    ctx.fillRect(0, 0, 100, 50);
+
+    ctx.strokeStyle = '#f00';
+    ctx.lineWidth = 10;
+    ctx.lineCap = 'round';
+    ctx.lineJoin = 'round';
+
+    ctx.moveTo(10, 10);
+    ctx.bezierCurveTo(10, 30, 40, 50, 100, 50);
+    ctx.closePath();
+    ctx.stroke();
+
+- name: 2d.path.stroke.prune.closePath.quadraticCurve
+  desc: Test if zero-lengthed closePath before and after quadratic curve are ignored corrected.
+  code: |
+    ctx.fillStyle = '#0f0';
+    ctx.fillRect(0, 0, 100, 50);
+
+    ctx.strokeStyle = '#f00';
+    ctx.lineWidth = 10;
+    ctx.lineCap = 'round';
+    ctx.lineJoin = 'round';
+
+    ctx.beginPath();
+    ctx.moveTo(5, 5);
+    ctx.lineTo(5, 5);
+    ctx.closePath();
+
+    ctx.moveTo(10, 10);
+    ctx.quadraticCurveTo(80, 10, 100, 50);
+    ctx.closePath();
+
+    ctx.moveTo(40, 40);
+    ctx.lineTo(40, 40);
+    ctx.closePath();
+    ctx.stroke();
+  reference: |
+    ctx.fillStyle = '#0f0';
+    ctx.fillRect(0, 0, 100, 50);
+
+    ctx.strokeStyle = '#f00';
+    ctx.lineWidth = 10;
+    ctx.lineCap = 'round';
+    ctx.lineJoin = 'round';
+
+    ctx.moveTo(10, 10);
+    ctx.quadraticCurveTo(80, 10, 100, 50);
+    ctx.closePath();
+    ctx.stroke();
+
+- name: 2d.path.stroke.prune.closePath.arc
+  desc: Test if zero-lengthed closePath before and after arc are ignored corrected.
+  code: |
+    ctx.fillStyle = '#0f0';
+    ctx.fillRect(0, 0, 100, 50);
+
+    ctx.strokeStyle = '#f00';
+    ctx.lineWidth = 10;
+    ctx.lineCap = 'round';
+    ctx.lineJoin = 'round';
+
+    ctx.beginPath();
+    ctx.moveTo(50, 25);
+    ctx.lineTo(50, 25);
+    ctx.closePath();
+
+    ctx.moveTo(10, 10);
+    ctx.arc(20, 20, 15, 0, Math.PI);
+    ctx.closePath();
+
+    ctx.moveTo(40, 40);
+    ctx.lineTo(40, 40);
+    ctx.closePath();
+    ctx.stroke();
+  reference: |
+    ctx.fillStyle = '#0f0';
+    ctx.fillRect(0, 0, 100, 50);
+
+    ctx.strokeStyle = '#f00';
+    ctx.lineWidth = 10;
+    ctx.lineCap = 'round';
+    ctx.lineJoin = 'round';
+
+    ctx.moveTo(10, 10);
+    ctx.arc(20, 20, 15, 0, Math.PI);
+    ctx.closePath();
+    ctx.stroke();
+
 - name: 2d.path.transformation.basic
   code: |
     ctx.fillStyle = '#f00';
@@ -3074,8 +3226,6 @@
     @assert pixel 50,25 == 0,255,0,255;
   expected: green
 
-
-
 - name: 2d.path.isPointInPath.basic.1
   desc: isPointInPath() detects whether the point is inside the path
   code: |