What happens
After a Magic Wand selection on detailed artwork, zooming out freezes the app. The main thread stays pegged at 100% and never recovers. I hit it on a 27,000 x 5,400 banner at 0.6% zoom, and it also reproduces on unmodified main with a 10,800 x 5,400 PSD.
Steps
- Open a document with detailed artwork (ornate lettering, logos).
- Click the Magic Wand on the artwork with default settings (tolerance 32, contiguous).
- Zoom out. At 10% it's already sluggish; at around 1% it stops responding.
Measurements
These were taken on main at 01e8e52 from a local test. It ran MagicWand.select on a real 10,800 x 5,400 PSD, then timed exactly what TransformOverlay.drawSelection() does: a solid 1 pt stroke, then a [4, 4] dashed stroke, into a view-sized context.
The wand's outline size depends on what's clicked:
| Clicked on |
Outline edges |
| Flat background |
4 |
| Schedule text layer |
26 to 52,006 |
| Poster artwork layers |
194,548 to 271,662 |
Drawing the largest outline (271,662 edges) once:
| Zoom |
Solid |
Solid + dashed |
| 100% |
0.027 s |
0.055 s |
| 10% |
2.68 s |
3.27 s |
| 0.6% |
63.9 s |
94.9 s |
The ants timer (EditorCanvas.swift:2008) marks the overlay dirty every 0.12 s. From about 10% zoom down, a single redraw takes longer than that interval, so the next one is already queued and the app never catches up. The cost rises as you zoom out because every edge is still processed while hundreds of thousands of them collapse into a few screen pixels. The time is spent inside Core Graphics, so a Release build doesn't change it.
A sample of the frozen app shows the main thread in a single CA::Layer::display → CGDisplayListDrawInContextDelegate → ripc_DrawPath → aa_render → aa_distribute_edges call, identical across every sample for minutes.
The wand allows outlines of up to 8,000,000 edges (WandPixels.c:7, wand_edge_limit), so an outline far larger than the one measured here can reach the overlay.
Where
Compositor/Rendering/TransformOverlay.swift:197, drawSelection(): strokes the full selection.path twice per redraw, at full detail, at any zoom.
Compositor/Rendering/EditorCanvas.swift:2008: the 0.12 s marching-ants timer.
Possible fixes
- Level of detail for the outline. When a document pixel is smaller than a screen point, draw the ants from an outline traced at screen resolution instead of per document pixel. Tracing the selection mask downsampled to the current zoom, or caching one outline per zoom step, keeps the edge count bounded by what's on screen. This is the real fix.
- Backpressure on the ants timer. Skip a tick while the previous redraw is still pending, so a slow outline stutters instead of freezing the app. It's small and independent of fix 1, and worth having in any case.
I can send a PR for fix 2 if you'd like it, or try fix 1 if you have a preferred approach.
Environment: macOS 27.0 (26A428), Apple M3 Max, Compositor main at 01e8e52.
🤖 Generated with Claude Code
What happens
After a Magic Wand selection on detailed artwork, zooming out freezes the app. The main thread stays pegged at 100% and never recovers. I hit it on a 27,000 x 5,400 banner at 0.6% zoom, and it also reproduces on unmodified
mainwith a 10,800 x 5,400 PSD.Steps
Measurements
These were taken on
mainat01e8e52from a local test. It ranMagicWand.selecton a real 10,800 x 5,400 PSD, then timed exactly whatTransformOverlay.drawSelection()does: a solid 1 pt stroke, then a[4, 4]dashed stroke, into a view-sized context.The wand's outline size depends on what's clicked:
Drawing the largest outline (271,662 edges) once:
The ants timer (
EditorCanvas.swift:2008) marks the overlay dirty every 0.12 s. From about 10% zoom down, a single redraw takes longer than that interval, so the next one is already queued and the app never catches up. The cost rises as you zoom out because every edge is still processed while hundreds of thousands of them collapse into a few screen pixels. The time is spent inside Core Graphics, so a Release build doesn't change it.A
sampleof the frozen app shows the main thread in a singleCA::Layer::display→CGDisplayListDrawInContextDelegate→ripc_DrawPath→aa_render→aa_distribute_edgescall, identical across every sample for minutes.The wand allows outlines of up to 8,000,000 edges (
WandPixels.c:7,wand_edge_limit), so an outline far larger than the one measured here can reach the overlay.Where
Compositor/Rendering/TransformOverlay.swift:197,drawSelection(): strokes the fullselection.pathtwice per redraw, at full detail, at any zoom.Compositor/Rendering/EditorCanvas.swift:2008: the 0.12 s marching-ants timer.Possible fixes
I can send a PR for fix 2 if you'd like it, or try fix 1 if you have a preferred approach.
Environment: macOS 27.0 (26A428), Apple M3 Max, Compositor
mainat01e8e52.🤖 Generated with Claude Code