Opening an EPS whose threaded area type frame has a control point at
x = 8e115 failed with an internal error ("capacity overflow").
`eps_text_frames_never_panic` in `import_fuzz` found it with
PROPTEST_CASES=20000. Text layout flattens a frame to within 0.1 pt,
and for such a curve kurbo 0.13.1's `flatten` calls `reserve` for
`usize::MAX` quadratic pieces. Laying out text around a wrap shape with
such a curve failed the same way. Laying out type on a path along such
a curve panicked in kurbo's `solve_itp` ("attempt to shift left with
overflow") in builds with overflow checks, and in a release build it
did not finish within 20 s. Laying out area type in a triangle frame
that comes to a point at its top, at y = 1e20, did not finish either:
adding a lead to a baseline that large leaves the baseline where it is.
Text layout now leaves out a frame, a text wrap shape or the path of
type on a path that has a coordinate beyond 1,000,000,000 pt either
way, control points included, or a NaN coordinate in an anchor point.
Such a frame or path holds no text, and such a wrap shape is ignored.
PDF export uses the same bound (`MAX_COORD` in
`crates/pdf/src/export.rs`).
Text layout also steps a line down a frame cell at most 100,000 times
to find room for it. In a cell taller than 100,000 leads, a step is the
cell's height divided by 100,000; in a shorter cell, a step is one
lead, as before. Before this change, in a dev build, with triangle
frames that come to a point at their top, laying out text in one
2,000,000,000 pt tall took 9.8 s, and laying out a paragraph whose
Space Before is -1e300 pt in one 1,000 pt tall did not finish within
20 s.
The layout drops lines that overflow an area frame vertically, so counting
the first paragraph's laid-out lines cannot see a wrapped second line
when the frame holds only one. The bisection then found every tracking
"one line" and ran to its 2000 ceiling, which spread the line far past the
frame (most glyphs clipped away) while the command reported success.
one_line now asks whether the first line reaches the end of the first
paragraph, which holds regardless of dropped overflow lines. Regression
test: area 240x50 at size 36 previously returned tracking 1999.9, now
fills the width (avail - w < 5) with the paragraph on one line.
crates/trace/tests/quality draws its inputs from known vector art (no image files), traces them with every
built-in preset and measures fidelity, distance from the true outlines, economy, artefacts, time and memory.
docs/image-trace-quality.md records the numbers on main before any change, beside the same measures of an
open tracer run as a black box. No change to the tracer.
Delete, Cut, Group, Make Compound Path, Make Clipping Mask, Send to
Current Layer, Ungroup and Release Compound Path removed, inserted or
moved one object at a time. duplicate_in inserted one copy at a time;
Duplicate, Copy in the Move, Rotate, Scale, Reflect and Shear dialogs,
Transform Again after a copy, Transform Each with Copy, the perspective
copies and each move of an Alt-drag call it. Each insertion or removal
moved the later objects of the same layer or group to other indices.
The next lookup by id then walked the tree, and after every fourth such
walk Document::index_path rebuilt the whole lookup cache. Each command
did work that grew with the number of objects times the size of the
document: with 25,000 rectangles selected, a release build of
vectorcraft-cli took 7.2 s to group them and 11.5 s to copy them with
object.transform.
Document::remove_many, Document::wrap and Document::insert_beside
remove nodes, wrap them in a new node, or put nodes directly above or
in place of their anchors, in one pass over the children of each
parent. Each finds the nodes with one index_paths call, checks every id
before it changes anything, and clears the lookup cache once. The
commands above use them. The objects keep their order, the copies take
their ids in the same order, and the selection, the undo step and the
journal are the same. duplicate_in still copies one root at a time when
a root is listed twice or lies inside another root. A release build
with this change groups the 25,000 rectangles in 27 ms and copies them
in 121 ms.
Docs: docs/target-app-parity.md.
The check added for #1396 dropped the inner contour only when the path itself fell in the hole, which takes a stroke more than twice as wide as the shape. Between one and two times the size (a 30 pt ellipse with a 50 pt stroke), and on rectangles with round or bevel joins, the hole stayed.
An offset contour is now left out when no point of it lies half the weight from its subpath: it is then nowhere the edge of the stroke. Subpaths are judged one by one, and only when the stroke is at least as wide as the subpath's bounds, so ordinary strokes take the same single call as before.
A closed path stroked wider than it is came back as a ring, because the inner offset crossed the middle. When that outline no longer covers the path, the outer contour is kept so the stroke paints solid.