#129's first commit (4f8d230) holds #124 and #126, which are already merged. Each conflicted file is a three-way merge of #129's own commits (4f8d230..pr/129) onto this branch, which takes #129's side against #126 and keeps the chain's (#81/#84) code.
Conflict: ROADMAP.md: kept both entries
Conflict: crates/compose/src/shape.rs: #129's Mojikumi metrics added; #81's pieces, the #126 composite-note piece and the #124 inline-object metrics unchanged
Conflict: crates/compose/src/tests.rs: tests only; #129's tests added, no duplicates of #124/#126's
Conflict: crates/engine/src/cmd/fonts.rs: #129's pub(super) for_each_story; #126's tests kept once
Conflict: crates/engine/src/cmd/preflight.rs: #129's nested-story paragraph rules; the used_fonts loop kept once
Conflict: crates/engine/src/tests.rs: tests only; #129's test added
Conflict: crates/fonts/src/fontdb.rs: #126 content (same in #129); no change
Conflict: crates/idml/src/import.rs: #129's Mojikumi import added
Conflict: crates/idml/src/tests.rs: tests only; #129's tests added
Conflict: crates/ui-egui/src/dialogs.rs: #126 content (same in #129); no change
Conflict: crates/ui-egui/src/lib.rs: #126 content (same in #129); no change
Conflict: crates/compose/src/shape.rs: #81 collects paint-only pieces and shapes them later, #126 shapes composite-font note labels inline. A footnote reference in a composite font becomes a Piece with `composite_note`, shaped alone in the piece pass with #126's per-entry label code (from the run's env, as in #126); other references stay ordinary pieces. #126's label fallback in shape_segment passes #81's StyleRuns.
Conflict: crates/fonts/src/fontdb.rs: #126's canonical_family lookup sits at the top of exact_style_traits, so #81's styles/traits_of/linked_style and #247's format-suffix fallback all use it; face() resolves canonical, then canonical without the format suffix, then #126's substitute_family, through #247's find_or_load; has_family is canonical_family as named or without the suffix
Conflict: crates/ui-egui/src/lib.rs: kept #84's system-clipboard copy match and added #126's Find Font on open and _fonts reset after it
Conflict: crates/ui-egui/src/dialogs.rs: OK label match has #146's Save and #126's Replace All; #80's alert-only OK kept, #126's Done label for findFont; find_font keeps #143's font_combo with #126's FALLBACK_FAMILY default
Conflict: crates/compose/src/tests.rs, crates/idml/src/tests.rs: tests only; kept both
Conflict: ROADMAP.md: kept both entries
Conflict: crates/compose/src/shape.rs: inline object on the baseline: #124's rule (its box alone sets the extents, not max with the font's) applied to every metric #83 tracks (ascent, typo_ascent, cap, xh); the above-line arm keeps #83's four fields
Conflict: crates/compose/src/tests.rs: tests only; kept both
Conflict: crates/engine/src/tests.rs: tests only; kept both
Conflict: crates/idml/src/tests.rs: tests only; kept both
Conflict: crates/fonts/src/fontdb.rs: kept #81's typo_ascent/plausible and #247's without_format_suffix; the format-suffix fallback goes inside #81's style_traits() through exact_style_traits() (same as wip 57ebfb2)
Conflict: crates/idml/src/tests.rs: tests only; kept #83's drop-cap and object-style tests and #247's layer-order test
Conflict: crates/ui-egui/src/lib.rs: kept #119's drain_inbox, import_file and ImportRequest (and its Services.inbox doc); import_file's and confirm_pdf_import's file.place/file.openBytes go through #80's open_file, so a failure shows the alert; import_file uses #80's opens_as_document for layout files
Conflict: crates/ui-egui/src/dialogs.rs: kept #119's pdfImport arm (async confirm, target activation); its native file.place goes through #80's open_file
Conflict: crates/ui-egui/src/dialogs.rs: took #144's structure (shared basic_character_formats and character_color sections); paragraph_style_options reads a clone of the document as #143 does, so the font menu can borrow the app; basic_character_formats takes &mut DesignApp and uses #143's font_combo (font_menu_rows is gone) with a × button that clears a style's family
Conflict: crates/pdf/src/export.rs: took #223's side (RasterMode with #147's decode check) and dropped #128's Exporter interpolate field; #128's RTL story/table work and its PDF/A test are kept
Reuse packaged-link candidates for embedded IDML images and native files.
Resolve missing original paths beside the opened document, retaining the
embedded image bytes and any original link that still exists. Bound path
lookup allocations and cover actual package relocation through commands.
Make existing data-merge test path assertions portable to Windows.
Co-authored-by: Codex <noreply@openai.com>
The rows share one fixed height that preserves their composed total. Merged rows and rows that are not laid out are refused, and the table stays unchanged.
Three commands took a count from their parameters and used it unchecked.
Parameters come from MCP, the control channel and scripts, so the count
is hostile input (never-crash: cap input-sized allocations, checked
arithmetic).
- layout.createGuides made one or two guides per row and column with no
upper limit: 30 million rows took 1.2 GB, and 2^32 - 1 would exhaust
memory, which aborts the process past the command guard. A count over
2^32 wrapped to a small one. Both counts are now capped at 100.
- edit.stepAndRepeat multiplied rows by columns as usize. In debug builds
the overflow panicked; in release builds 2^32 x 2^32 wraps to 0, passes
the 1000-copy limit and starts a grid of 2^64 copies. The product is
now checked, and a grid that large falls back to `count` copies like
any other grid over 1000.
- file.new stored any column count in the page (4 billion, or a wrapped
value past 2^32). Page::column_rects builds one rect per column each
time the columns are laid out. The count is now clamped to 1..=216,
the range layout.marginsAndColumns already uses.
Each case has a regression test that failed before the fix.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Resolve imported composite fonts by resource identity and preserve literal
display names. Export AppliedFont as an object reference instead of registering
a composite definition as an ordinary font family.
Share composite lookup and typed font usage between composition, font inventory,
and preflight. Include nested cells and notes, and report only component fonts
selected by the document's characters.
Add synthetic coverage for reference round trips, footnote character mapping
and metrics, nested font inventory, component replacement, and undo.
Resolve forward story references before importing embedded frames and groups.
Compose embedded stories, retain anonymous-story objects for screen and PDF
rendering, and invalidate layout caches when embedded frame geometry changes.
Measure inline objects by geometry, fill open contours, reject cyclic frame
references, and distinguish unplaced stories from located overset text.
Add synthetic round-trip, composition, preflight, pixel-rendering, and PDF
regressions. Update the roadmap with the supported import and rendering paths.
#83's Keep Lines Together tests change expectation: with the last baseline
allowed on the bottom inset, the first frame holds one more line, so the
10-line paragraph splits 7/3 instead of 6/4 (the keep rule is unchanged).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bold and Italic find the linked style through the document's font scope,
so a family from the document's fonts folder links its own styles; the
Character panel's B and I state reads the same scope.
Trailing spaces and drop caps both join the placed line; hit testing checks
the drop cap first, then the closest line (hit_line). hit_char also picks
the drop cap's character under the point, so a double click on the cap
selects from it (the follow-up both PRs named).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolve conflicts with the CJK/Arabic work: trailing spaces follow the line
only in left-to-right paragraphs without right-to-left glyphs (layout_line
now takes the bidi info); style linking moves to ScopedFonts so the
document's own fonts count (FontDb delegates to scope 0); threading keeps
the receiving story's direction and Vertical Type, and frames split off by
threading or removed from a thread keep theirs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolve conflicts with the CJK/Arabic composition work: line metrics keep
the first-baseline tops and add the CJK alignment shift; the CJK line
reference adjustment applies before baseline-grid snapping; layout_line
takes the bidi info and the drop cap is spliced in after it; vertical text
is now the story's direction (FrameSpec::vertical); IDML insets use main's
validated inset_spacing over the object style chain; format's JSON upgrade
(vertical frames) and model upgrade (format v2 defaults) both run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolve conflicts keeping both sides: doc gains both `cjk` and
`datamerge` modules; file.open resolves data-merge sources and loads the
document's fonts; DocState keeps preview_stash/preview_record and fonts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Commands run while handling a control request (engine.execute,
ui.menu.invoke, ...) no longer read the system clipboard into Paste or
write Copy/Cut text to it; only user-initiated runs do. Regression test
included. append_story allocates note, endnote, editorial and table ids
with saturating_add (no overflow panic on hostile ids), with a test.
Also fixes a clippy nonminimal_bool in cmd/text.rs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>