diff --git a/examples/tiger.png b/examples/tiger.png
index 5521f5f..a241b71 100644
Binary files a/examples/tiger.png and b/examples/tiger.png differ
diff --git a/src/pixie/paths.nim b/src/pixie/paths.nim
index ab5df36..1f6db0d 100644
--- a/src/pixie/paths.nim
+++ b/src/pixie/paths.nim
@@ -1068,6 +1068,17 @@ proc computeBounds*(
   shapes.transform(transform)
   computeBounds(shapes.shapesToSegments())
 
+proc initPartitionEntry(segment: Segment, winding: int16): PartitionEntry =
+  result.atY = segment.at.y
+  result.toY = segment.to.y
+  result.winding = winding
+  let d = segment.at.x - segment.to.x
+  if d == 0:
+    result.b = segment.at.x # Leave m = 0, store the x we want in b
+  else:
+    result.m = (segment.at.y - segment.to.y) / d
+    result.b = segment.at.y - result.m * segment.at.x
+
 proc partitionSegments(
   segments: seq[(Segment, int16)], top, height: int
 ): Partitioning =
@@ -1081,17 +1092,7 @@ proc partitionSegments(
   result.partitionHeight = height.uint32 div numPartitions
 
   for (segment, winding) in segments:
-    var entry: PartitionEntry
-    entry.atY = segment.at.y
-    entry.toY = segment.to.y
-    entry.winding = winding
-    let d = segment.at.x - segment.to.x
-    if d == 0:
-      entry.b = segment.at.x # Leave m = 0, store the x we want in b
-    else:
-      entry.m = (segment.at.y - segment.to.y) / d
-      entry.b = segment.at.y - entry.m * segment.at.x
-
+    let entry = initPartitionEntry(segment, winding)
     if result.partitionHeight == 0:
       result.partitions[0].add(entry)
     else:
@@ -1106,7 +1107,7 @@ proc partitionSegments(
         result.partitions[i].add(entry)
 
 proc getIndexForY(partitioning: Partitioning, y: int): uint32 {.inline.} =
-  if partitioning.partitionHeight == 0 or partitioning.partitions.len == 1:
+  if partitioning.partitions.len == 1:
     0.uint32
   else:
     min(
@@ -1114,39 +1115,43 @@ proc getIndexForY(partitioning: Partitioning, y: int): uint32 {.inline.} =
       partitioning.partitions.high.uint32
     )
 
+proc maxEntryCount(partitioning: Partitioning): int =
+  for i in 0 ..< partitioning.partitions.len:
+    result = max(result, partitioning.partitions[i].len)
+
 proc insertionSort(
-  a: var seq[(float32, int16)], lo, hi: int
+  hits: var seq[(float32, int16)], lo, hi: int
 ) {.inline.} =
   for i in lo + 1 .. hi:
     var
       j = i - 1
       k = i
-    while j >= 0 and a[j][0] > a[k][0]:
-      swap(a[j + 1], a[j])
+    while j >= 0 and hits[j][0] > hits[k][0]:
+      swap(hits[j + 1], hits[j])
       dec j
       dec k
 
-proc sort(a: var seq[(float32, int16)], inl, inr: int) =
+proc sort(hits: var seq[(float32, int16)], inl, inr: int) =
   ## Quicksort + insertion sort, in-place and faster than standard lib sort.
   let n = inr - inl + 1
   if n < 32:
-    insertionSort(a, inl, inr)
+    insertionSort(hits, inl, inr)
     return
   var
     l = inl
     r = inr
-  let p = a[l + n div 2][0]
+  let p = hits[l + n div 2][0]
   while l <= r:
-    if a[l][0] < p:
+    if hits[l][0] < p:
       inc l
-    elif a[r][0] > p:
+    elif hits[r][0] > p:
       dec r
     else:
-      swap(a[l], a[r])
+      swap(hits[l], hits[r])
       inc l
       dec r
-  sort(a, inl, r)
-  sort(a, l, inr)
+  sort(hits, inl, r)
+  sort(hits, l, inr)
 
 proc shouldFill(
   windingRule: WindingRule, count: int
@@ -1166,28 +1171,37 @@ iterator walk(
   width: float32
 ): (float32, float32, int) =
   var
+    i, count: int
     prevAt: float32
-    count: int
-  for i in 0 ..< numHits:
+  while i < numHits:
     let (at, winding) = hits[i]
-    if windingRule == wrNonZero and
-      (count != 0) == (count + winding != 0) and
-      i < numHits - 1:
-      # Shortcut: if nonzero rule, we only care about when the count changes
-      # between zero and nonzero (or the last hit)
-      count += winding
-      continue
     if at > 0:
       if shouldFill(windingRule, count):
+        if i < numHits - 1:
+          # Look ahead to see if the next hit is in the same spot as this hit.
+          # If it is, see if this hit and the next hit's windings cancel out.
+          # If they do, skip the hits. It will be yielded later in a
+          # larger chunk.
+          let (nextAt, nextWinding) = hits[i + 1]
+          if nextAt == at and winding + nextWinding == 0:
+            i += 2
+            continue
+          # Shortcut: we only care about when we stop filling (or the last hit).
+          # If we continue filling, move to next hit.
+          if windingRule == wrNonZero and count + winding != 0:
+            count += winding
+            inc i
+            continue
         yield (prevAt, at, count)
       prevAt = at
     count += winding
+    inc i
 
   when defined(pixieLeakCheck):
     if prevAt != width and count != 0:
       echo "Leak detected: ", count, " @ (", prevAt, ", ", y, ")"
 
-proc computeCoverages(
+proc computeCoverage(
   coverages: var seq[uint8],
   hits: var seq[(float32, int16)],
   numHits: var int,
@@ -1215,7 +1229,7 @@ proc computeCoverages(
     yLine += offset
     numHits = 0
     for i in 0 ..< partitionEntryCount: # Perf
-      let entry = partitioning.partitions[partitionIndex][i]
+      let entry = partitioning.partitions[partitionIndex][i].unsafeAddr # Perf
       if entry.atY <= yLine and entry.toY >= yLine:
         let x =
           if entry.m == 0:
@@ -1223,8 +1237,6 @@ proc computeCoverages(
           else:
             (yLine - entry.b) / entry.m
 
-        if numHits == hits.len:
-          hits.setLen(hits.len * 2)
         hits[numHits] = (min(x, width), entry.winding)
         inc numHits
 
@@ -1259,9 +1271,9 @@ proc computeCoverages(
           when defined(amd64) and not defined(pixieNoSimd):
             let sampleCoverageVec = mm_set1_epi8(cast[int8](sampleCoverage))
             for _ in 0 ..< fillLen div 16:
-              var coverage = mm_loadu_si128(coverages[i - startX].addr)
-              coverage = mm_add_epi8(coverage, sampleCoverageVec)
-              mm_storeu_si128(coverages[i - startX].addr, coverage)
+              var coverageVec = mm_loadu_si128(coverages[i - startX].addr)
+              coverageVec = mm_add_epi8(coverageVec, sampleCoverageVec)
+              mm_storeu_si128(coverages[i - startX].addr, coverageVec)
               i += 16
           for j in i ..< fillStart + fillLen:
             coverages[j - startX] += sampleCoverage
@@ -1299,11 +1311,11 @@ proc fillCoverage(
       for _ in 0 ..< coverages.len div 16:
         let
           index = image.dataIndex(x, y)
-          coverage = mm_loadu_si128(coverages[x - startX].unsafeAddr)
+          coverageVec = mm_loadu_si128(coverages[x - startX].unsafeAddr)
 
-        if mm_movemask_epi8(mm_cmpeq_epi16(coverage, zeroVec)) != 0xffff:
+        if mm_movemask_epi8(mm_cmpeq_epi16(coverageVec, zeroVec)) != 0xffff:
           # If the coverages are not all zero
-          if mm_movemask_epi8(mm_cmpeq_epi32(coverage, vec255)) == 0xffff:
+          if mm_movemask_epi8(mm_cmpeq_epi32(coverageVec, vec255)) == 0xffff:
             # If the coverages are all 255
             if blendMode == bmNormal and rgbx.a == 255:
               for i in 0 ..< 4:
@@ -1317,9 +1329,9 @@ proc fillCoverage(
                 )
           else:
             # Coverages are not all 255
-            var coverage = coverage
+            var coverageVec = coverageVec
             for i in 0 ..< 4:
-              var unpacked = unpackAlphaValues(coverage)
+              var unpacked = unpackAlphaValues(coverageVec)
               # Shift the coverages from `a` to `g` and `a` for multiplying
               unpacked = mm_or_si128(unpacked, mm_srli_epi32(unpacked, 16))
 
@@ -1342,7 +1354,7 @@ proc fillCoverage(
                 blenderSimd(backdrop, source)
               )
 
-              coverage = mm_srli_si128(coverage, 4)
+              coverageVec = mm_srli_si128(coverageVec, 4)
 
         elif blendMode == bmMask:
           for i in 0 ..< 4:
@@ -1534,11 +1546,11 @@ proc fillShapes(
 
   var
     coverages = newSeq[uint8](bounds.w.int)
-    hits = newSeq[(float32, int16)](4)
+    hits = newSeq[(float32, int16)](partitioning.maxEntryCount)
     numHits: int
 
   for y in startY ..< pathHeight:
-    computeCoverages(
+    computeCoverage(
       coverages,
       hits,
       numHits,
@@ -1591,11 +1603,11 @@ proc fillShapes(
 
   var
     coverages = newSeq[uint8](bounds.w.int)
-    hits = newSeq[(float32, int16)](4)
+    hits = newSeq[(float32, int16)](partitioning.maxEntryCount)
     numHits: int
 
   for y in startY ..< pathHeight:
-    computeCoverages(
+    computeCoverage(
       coverages,
       hits,
       numHits,
@@ -1937,10 +1949,7 @@ proc overlaps(
   let
     scanline = line(vec2(0, test.y), vec2(1000, test.y))
     segments = shapes.shapesToSegments()
-  for i in 0 ..< segments.len: # For gc:arc
-    let
-      segment = segments[i][0]
-      winding = segments[i][1]
+  for (segment, winding) in segments:
     if segment.at.y <= scanline.a.y and segment.to.y >= scanline.a.y:
       var at: Vec2
       if scanline.intersects(segment, at):
@@ -1950,8 +1959,7 @@ proc overlaps(
   sort(hits, 0, hits.high)
 
   var count: int
-  for i in 0 ..< hits.len: # For gc:arc
-    let (at, winding) = hits[i]
+  for (at, winding) in hits:
     if at > test.x:
       return shouldFill(windingRule, count)
     count += winding
diff --git a/tests/benchmark_paths.nim b/tests/benchmark_paths.nim
index 080d76e..cab240a 100644
--- a/tests/benchmark_paths.nim
+++ b/tests/benchmark_paths.nim
@@ -5,8 +5,16 @@ let pathStr = "m57.611-8.591c-1.487,1.851-4.899,4.42-1.982,6.348,0.194,0.129,0.5
 timeIt "parsePath":
   keep parsePath(pathStr)
 
-let image = newImage(500, 300)
-image.fill(rgba(255, 255, 255, 255))
+block:
+  let path = parsePath("""
+    M 10,30
+    A 20,20 0,0,1 50,30
+    A 20,20 0,0,1 90,30
+    Q 90,60 50,90
+    Q 10,60 10,30 z
+  """)
+  timeIt "fillOverlaps":
+    doAssert path.fillOverlaps(vec2(1, 1)) == false
 
 timeIt "roundedRect":
   const radius = 20
@@ -15,4 +23,5 @@ timeIt "roundedRect":
   path.roundedRect(0.5, 0.5, 499, 299, radius, radius, radius, radius)
   # path.roundedRect(0, 0, 500, 300, radius, radius, radius, radius)
 
+  let image = newImage(500, 300)
   image.fillPath(path, rgba(0, 0, 0, 255))
diff --git a/tests/contexts/bezierCurveTo_1.png b/tests/contexts/bezierCurveTo_1.png
index a007d41..83bb3bf 100644
Binary files a/tests/contexts/bezierCurveTo_1.png and b/tests/contexts/bezierCurveTo_1.png differ
diff --git a/tests/contexts/bezierCurveTo_2.png b/tests/contexts/bezierCurveTo_2.png
index 3bfda4a..ef9ed76 100644
Binary files a/tests/contexts/bezierCurveTo_2.png and b/tests/contexts/bezierCurveTo_2.png differ
diff --git a/tests/contexts/closePath_1.png b/tests/contexts/closePath_1.png
index bd5fc25..8869e5f 100644
Binary files a/tests/contexts/closePath_1.png and b/tests/contexts/closePath_1.png differ
diff --git a/tests/contexts/ellipse_1.png b/tests/contexts/ellipse_1.png
index f28603e..786a7d5 100644
Binary files a/tests/contexts/ellipse_1.png and b/tests/contexts/ellipse_1.png differ
diff --git a/tests/contexts/quadracticCurveTo_1.png b/tests/contexts/quadracticCurveTo_1.png
index de9463d..6f6b63f 100644
Binary files a/tests/contexts/quadracticCurveTo_1.png and b/tests/contexts/quadracticCurveTo_1.png differ
diff --git a/tests/contexts/strokeText_1.png b/tests/contexts/strokeText_1.png
index 0f22eb8..3b028b6 100644
Binary files a/tests/contexts/strokeText_1.png and b/tests/contexts/strokeText_1.png differ
diff --git a/tests/fileformats/svg/diffs/Ghostscript_Tiger.png b/tests/fileformats/svg/diffs/Ghostscript_Tiger.png
index 3742296..b870b2f 100644
Binary files a/tests/fileformats/svg/diffs/Ghostscript_Tiger.png and b/tests/fileformats/svg/diffs/Ghostscript_Tiger.png differ
diff --git a/tests/fileformats/svg/diffs/circle01.png b/tests/fileformats/svg/diffs/circle01.png
index 31eb2ed..f8606a0 100644
Binary files a/tests/fileformats/svg/diffs/circle01.png and b/tests/fileformats/svg/diffs/circle01.png differ
diff --git a/tests/fileformats/svg/diffs/ellipse01.png b/tests/fileformats/svg/diffs/ellipse01.png
index 0de4684..b446986 100644
Binary files a/tests/fileformats/svg/diffs/ellipse01.png and b/tests/fileformats/svg/diffs/ellipse01.png differ
diff --git a/tests/fileformats/svg/diffs/miterlimit.png b/tests/fileformats/svg/diffs/miterlimit.png
index b8299c7..7803a67 100644
Binary files a/tests/fileformats/svg/diffs/miterlimit.png and b/tests/fileformats/svg/diffs/miterlimit.png differ
diff --git a/tests/fileformats/svg/diffs/polygon01.png b/tests/fileformats/svg/diffs/polygon01.png
index 09dec93..e66307f 100644
Binary files a/tests/fileformats/svg/diffs/polygon01.png and b/tests/fileformats/svg/diffs/polygon01.png differ
diff --git a/tests/fileformats/svg/diffs/quad01.png b/tests/fileformats/svg/diffs/quad01.png
index f0e4ac6..3edde6c 100644
Binary files a/tests/fileformats/svg/diffs/quad01.png and b/tests/fileformats/svg/diffs/quad01.png differ
diff --git a/tests/fileformats/svg/diffs/rect02.png b/tests/fileformats/svg/diffs/rect02.png
index c4afed4..d3cf8c8 100644
Binary files a/tests/fileformats/svg/diffs/rect02.png and b/tests/fileformats/svg/diffs/rect02.png differ
diff --git a/tests/fileformats/svg/emojitwo.png b/tests/fileformats/svg/emojitwo.png
index e9dc17c..35a3fab 100644
Binary files a/tests/fileformats/svg/emojitwo.png and b/tests/fileformats/svg/emojitwo.png differ
diff --git a/tests/fileformats/svg/flat-color-icons.png b/tests/fileformats/svg/flat-color-icons.png
index a993866..8de3840 100644
Binary files a/tests/fileformats/svg/flat-color-icons.png and b/tests/fileformats/svg/flat-color-icons.png differ
diff --git a/tests/fileformats/svg/ionicons.png b/tests/fileformats/svg/ionicons.png
index 6312731..1d2aab4 100644
Binary files a/tests/fileformats/svg/ionicons.png and b/tests/fileformats/svg/ionicons.png differ
diff --git a/tests/fileformats/svg/noto-emoji.png b/tests/fileformats/svg/noto-emoji.png
index 5567d57..dad7899 100644
Binary files a/tests/fileformats/svg/noto-emoji.png and b/tests/fileformats/svg/noto-emoji.png differ
diff --git a/tests/fileformats/svg/openmoji.png b/tests/fileformats/svg/openmoji.png
index f21ebcf..70e32e7 100644
Binary files a/tests/fileformats/svg/openmoji.png and b/tests/fileformats/svg/openmoji.png differ
diff --git a/tests/fileformats/svg/rendered/Ghostscript_Tiger.png b/tests/fileformats/svg/rendered/Ghostscript_Tiger.png
index 805beb3..710a1b9 100644
Binary files a/tests/fileformats/svg/rendered/Ghostscript_Tiger.png and b/tests/fileformats/svg/rendered/Ghostscript_Tiger.png differ
diff --git a/tests/fileformats/svg/rendered/circle01.png b/tests/fileformats/svg/rendered/circle01.png
index ec30745..56799c1 100644
Binary files a/tests/fileformats/svg/rendered/circle01.png and b/tests/fileformats/svg/rendered/circle01.png differ
diff --git a/tests/fileformats/svg/rendered/ellipse01.png b/tests/fileformats/svg/rendered/ellipse01.png
index f4df489..9bf42b7 100644
Binary files a/tests/fileformats/svg/rendered/ellipse01.png and b/tests/fileformats/svg/rendered/ellipse01.png differ
diff --git a/tests/fileformats/svg/rendered/miterlimit.png b/tests/fileformats/svg/rendered/miterlimit.png
index 7a38b52..c2babb8 100644
Binary files a/tests/fileformats/svg/rendered/miterlimit.png and b/tests/fileformats/svg/rendered/miterlimit.png differ
diff --git a/tests/fileformats/svg/rendered/polygon01.png b/tests/fileformats/svg/rendered/polygon01.png
index aee52b8..ec6a32f 100644
Binary files a/tests/fileformats/svg/rendered/polygon01.png and b/tests/fileformats/svg/rendered/polygon01.png differ
diff --git a/tests/fileformats/svg/rendered/quad01.png b/tests/fileformats/svg/rendered/quad01.png
index 48166f7..4b3e6c5 100644
Binary files a/tests/fileformats/svg/rendered/quad01.png and b/tests/fileformats/svg/rendered/quad01.png differ
diff --git a/tests/fileformats/svg/rendered/rect02.png b/tests/fileformats/svg/rendered/rect02.png
index bb77d88..2c00983 100644
Binary files a/tests/fileformats/svg/rendered/rect02.png and b/tests/fileformats/svg/rendered/rect02.png differ
diff --git a/tests/fileformats/svg/simple-icons.png b/tests/fileformats/svg/simple-icons.png
index 0769a88..9d6217c 100644
Binary files a/tests/fileformats/svg/simple-icons.png and b/tests/fileformats/svg/simple-icons.png differ
diff --git a/tests/fileformats/svg/tabler-icons.png b/tests/fileformats/svg/tabler-icons.png
index 91ecfca..b629c1c 100644
Binary files a/tests/fileformats/svg/tabler-icons.png and b/tests/fileformats/svg/tabler-icons.png differ
diff --git a/tests/fileformats/svg/twbs-icons.png b/tests/fileformats/svg/twbs-icons.png
index 53ef9d8..ac850f3 100644
Binary files a/tests/fileformats/svg/twbs-icons.png and b/tests/fileformats/svg/twbs-icons.png differ
diff --git a/tests/fileformats/svg/twemoji.png b/tests/fileformats/svg/twemoji.png
index f77ab2d..9e11f33 100644
Binary files a/tests/fileformats/svg/twemoji.png and b/tests/fileformats/svg/twemoji.png differ
diff --git a/tests/fonts/diffs/image_stroke.png b/tests/fonts/diffs/image_stroke.png
index 089c82d..69f41a8 100644
Binary files a/tests/fonts/diffs/image_stroke.png and b/tests/fonts/diffs/image_stroke.png differ
diff --git a/tests/fonts/diffs/mask_stroke.png b/tests/fonts/diffs/mask_stroke.png
index fa09664..22dbf26 100644
Binary files a/tests/fonts/diffs/mask_stroke.png and b/tests/fonts/diffs/mask_stroke.png differ
diff --git a/tests/fonts/diffs/strikethrough3.png b/tests/fonts/diffs/strikethrough3.png
index 59db90a..95fb128 100644
Binary files a/tests/fonts/diffs/strikethrough3.png and b/tests/fonts/diffs/strikethrough3.png differ
diff --git a/tests/fonts/diffs/underline3.png b/tests/fonts/diffs/underline3.png
index f8bfa52..43467ab 100644
Binary files a/tests/fonts/diffs/underline3.png and b/tests/fonts/diffs/underline3.png differ
diff --git a/tests/fonts/rendered/image_stroke.png b/tests/fonts/rendered/image_stroke.png
index 63f588d..da57d70 100644
Binary files a/tests/fonts/rendered/image_stroke.png and b/tests/fonts/rendered/image_stroke.png differ
diff --git a/tests/fonts/rendered/mask_stroke.png b/tests/fonts/rendered/mask_stroke.png
index cbefc50..7301630 100644
Binary files a/tests/fonts/rendered/mask_stroke.png and b/tests/fonts/rendered/mask_stroke.png differ
diff --git a/tests/fonts/rendered/strikethrough3.png b/tests/fonts/rendered/strikethrough3.png
index f8e8dd0..699ffc5 100644
Binary files a/tests/fonts/rendered/strikethrough3.png and b/tests/fonts/rendered/strikethrough3.png differ
diff --git a/tests/fonts/rendered/underline3.png b/tests/fonts/rendered/underline3.png
index 948a5d4..2c7f62a 100644
Binary files a/tests/fonts/rendered/underline3.png and b/tests/fonts/rendered/underline3.png differ
diff --git a/tests/images/strokeEllipse.png b/tests/images/strokeEllipse.png
index 5b8e68d..3ef7e07 100644
Binary files a/tests/images/strokeEllipse.png and b/tests/images/strokeEllipse.png differ
diff --git a/tests/images/strokePolygon.png b/tests/images/strokePolygon.png
index 899fe33..62b1816 100644
Binary files a/tests/images/strokePolygon.png and b/tests/images/strokePolygon.png differ
diff --git a/tests/images/strokeRoundedRect.png b/tests/images/strokeRoundedRect.png
index 75d2404..22dae20 100644
Binary files a/tests/images/strokeRoundedRect.png and b/tests/images/strokeRoundedRect.png differ
diff --git a/tests/masks/strokeEllipse.png b/tests/masks/strokeEllipse.png
index c02ca91..76c08c7 100644
Binary files a/tests/masks/strokeEllipse.png and b/tests/masks/strokeEllipse.png differ
diff --git a/tests/masks/strokePolygon.png b/tests/masks/strokePolygon.png
index 8f82ce8..3c8f6e1 100644
Binary files a/tests/masks/strokePolygon.png and b/tests/masks/strokePolygon.png differ
diff --git a/tests/masks/strokeRoundedRect.png b/tests/masks/strokeRoundedRect.png
index 8991178..ee37251 100644
Binary files a/tests/masks/strokeRoundedRect.png and b/tests/masks/strokeRoundedRect.png differ
diff --git a/tests/paths/arc.png b/tests/paths/arc.png
index acda868..8ac91b3 100644
Binary files a/tests/paths/arc.png and b/tests/paths/arc.png differ
diff --git a/tests/paths/arcTo3.png b/tests/paths/arcTo3.png
index 9db12d4..8bb1cd2 100644
Binary files a/tests/paths/arcTo3.png and b/tests/paths/arcTo3.png differ
diff --git a/tests/paths/opacityStroke.png b/tests/paths/opacityStroke.png
index 8046321..57f2b5d 100644
Binary files a/tests/paths/opacityStroke.png and b/tests/paths/opacityStroke.png differ
diff --git a/tests/paths/pathStroke3.png b/tests/paths/pathStroke3.png
index 01c0f55..428b9fa 100644
Binary files a/tests/paths/pathStroke3.png and b/tests/paths/pathStroke3.png differ
diff --git a/tests/paths/pixelScale.png b/tests/paths/pixelScale.png
index 266554c..eb4bf09 100644
Binary files a/tests/paths/pixelScale.png and b/tests/paths/pixelScale.png differ