* hyphenation: linear heuristic, cache misses outside the lock
The syllable heuristic built each word suffix as a String to test it, which is
quadratic in the word's length; it now uses prefix sums of vowels and UTF-8
lengths. Mapping a word's break points to glyphs scanned the word for each
point; both are indexed once per word. A word not in the hyphenation cache is
worked out without holding the cache's global mutex.
* hyphenation: compare the word ending with ends_with
A cached story copied every wrap neighbour's whole signature and item list into
its entry; stories on one spread share its wrapping items, so entries grew with
all of theirs together. A neighbour's signature now goes in as its hash and its
items are kept once each.
Anchored-frame placement asked for the host's composition once per frame, and
again at every level a host was reached from. Each host is now asked for once
per placement pass, and the cache and the uncached path remember the hosts they
resolved for the whole traversal.
- Footnote references on a line are deduplicated with a set instead of
searching the references collected so far.
- Nested styles stream the paragraph up to their delimiter with one character
of lookahead instead of copying the rest of the paragraph for each style,
and a delimiter's characters are indexed once per style.
- Shaping resolves which nested/GREP style is on top with one sweep over the
overlay boundaries instead of scanning every overlay for each stretch.
- Column rules group crossing lines by paragraph through an index.
- Table fragments index each row's top once instead of searching the rows
for every cell.
The drop cap is set at the indent and the list number beside it, so the
number's character is the later one on the line and sets the indent.
Pin that with a test, and say so where the character is looked up.
The character was looked up among the line's body glyphs, so one inside
the drop cap was missed, and one in a list number's ^i matched the first
body glyph (after the label's tab) instead of itself. Find it among the
placed glyphs, which include the drop cap's and the label's.
The lines after an Indent to Here start at the character, which already sits past the drop cap, but the lines beside the drop cap still added its width on top. They no longer do. Adds tests for the drop cap, for Indent to Here after a tab (the usual hanging number) and for a right-to-left paragraph, and documents how the indent behaves beside a text wrap.
The composer treated Indent to Here as an invisible zero-width character and nothing else, so inserting it changed nothing. A line holding one now sets the start-side indent of the paragraph's following lines to the character's position, and those lines are broken again with the narrower measure. The indent holds into the next columns and frames; a later Indent to Here in the paragraph replaces it.
crates/ui-egui/src/panels/properties.rs, properties/object.rs: main's split module kept; preview_row and paint_corner_shape exported for the shading corner menus
crates/ui-egui/src/panels/properties/tests.rs: both sides' tests kept
crates/ui-egui/src/dialogs/tests.rs: main's tests kept; the border test uses the new corner labels; the shading layout test added
crates/ui-egui/src/i18n/*.rs: union of keys without duplicates
crates/ui-egui/src/dialogs.rs: the corner shape face uses corner_shape_button (no hard-coded colour in the dialog)
crates/ui-egui/src/dialogs.rs: both dialog tests kept
crates/ui-egui/src/i18n/*.rs: union of keys
docs/target-app-parity.md: main's change line plus the Text Frame Options entry
Applied as the diff of #1497 to #1498's head; the older copy of #1496 is not taken.
crates/engine/src/cmd/find.rs: PR's found-text Change path; format_only keeps main's cleared-attributes case
crates/ui-egui/src/dialogs/tests.rs: main's tests kept, the PR's Change test added
crates/ui-egui/src/i18n/*.rs: union of keys
docs/target-app-parity.md: main's text plus the Change wording
On a parent page a running-header variable shows <Name>, as InDesign shows it (it was blank). Text
with no page that isn't on a parent (a frame composition can't place on a page) keeps the
variable's text before and after: frames now record whether they are on a parent spread, and
the composed values are cached by page and parent.
Split from #1232 (parent-page-display), as asked in review.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CgGsJkVe5GYG9qK6VFdECa
A single wrapping object moved by keep options or vertical justification had four passes to
settle before; one-per-object would have given it two.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Enable hypher's "dutch" feature: Piet Tutelaers's hyph-nl.tex 1.1 from
hyph-utf8, MIT licensed (added to NOTICE). Dutch text, including InDesign's
nl_NL_2005, now hyphenates instead of never breaking a word.
Recognize U+00AD independently of automatic hyphenation in the greedy breaker, reusing the existing visible hyphen output. Cover both composers, zero-width unbroken soft hyphens, pattern suppression, and tagged and untagged PDF text extraction.
Fixes#1955
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fit() counted every break character in the overset text and every
Start Paragraph option. A break followed by a paragraph whose option it
already meets moved the text once but asked for two frames, and breaks
that tracked changes delete or a hidden condition hides asked for
frames that composing never uses. Autoflow added those pages and
removed them again: 200 chapters that end in page breaks and start on
the next page took 61095 ids and 430 ms, now 798 ids and 16 ms.
Each paragraph composing places now counts once, when a visible break
ends the paragraph before it or its start option sends it on; after a
break it is at the top of a frame, where the option only fixes odd or
even page parity. A visible break inside a paragraph counts once more.
previous_visible_break and the new visible_break in designcraft-compose
are public, so the estimate and the composer use one rule.
Reserve column and spanning footnotes when fitting inline table row groups. Continue rows in the next column or frame when the remaining space is too small, and include cell-local footnotes in measured row height.
Fixes#1901
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The start option lookup now reads the next paragraph composing places,
past tracked-deleted ones. Frames that start options and breaks force
are counted and asked for in one round, so a story with a paragraph per
page no longer gets one frame per round.