From 6880042c6a32dde23c3d9c560f1b36c204184ded Mon Sep 17 00:00:00 2001 From: moppeeer Date: Mon, 12 Oct 2026 14:57:09 +0200 Subject: [PATCH] fix(compose): Hyphenation Zone applies to the Single-line Composer only InDesign's Hyphenation Zone ("the white space allowed at the end of a line of unjustified text before hyphenation begins") applies only with the Single-line Composer. The Paragraph Composer, the default, weighs every break of the paragraph instead. DesignCraft applied the default 3p0 zone to both, so ragged paragraphs under the Paragraph Composer refused hyphens InDesign makes. In LYH Studio's poster tutorial the placeholder text breaks "aper-natem" and "mosticsia-tur"; ours ran a line longer. The breaker now gets the zone only for unjustified Single-line Composer paragraphs. Co-Authored-By: Claude Opus 5.5 --- ROADMAP.md | 1 + crates/compose/src/lib.rs | 4 +++- crates/compose/src/tests.rs | 15 ++++++++++----- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 4b7163c..fa779dd 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -132,6 +132,7 @@ Newest first. - **2026-10-12** · Window close and application/menu Quit ask about unsaved documents; later Cancel keeps every tab open, including earlier Don't Save choices. Approvals are rechecked after edits. Cancelable macOS Dock Quit remains open (#544). No readiness percentage change. - **2026-10-12** · Each running app keeps recovery data in its own locked folder; current folder and lock ownership are checked before writes and cleanup. Failed isolation disables recovery with a warning instead of sharing document IDs. No readiness percentage change. - **2026-10-12** · Native engine saves and exports replace files atomically; failed writes retain the original, private staging preserves Unix permissions, and valid long filenames work. Desktop Services and CLI raster exports remain separate follow-ups. No readiness percentage change. +- **2026-10-12** · Hyphenation Zone applies to the Single-line Composer only, as in InDesign. With the default Paragraph Composer, ragged text hyphenates where InDesign does (aper-natem), giving the same line breaks. No readiness percentage change. - **2026-10-12** · Words in capitals hyphenate like capitalized words (FERRUM COM-MODI), as in InDesign; Hyphenate Capitalized Words off keeps them whole. No readiness percentage change. - **2026-10-11** · `transform.move {copy}`, Edit › Duplicate and Step and Repeat return the copies' ids, so a script can go on with them. No readiness percentage change. - **2026-10-11** · `object.fill` and `object.stroke` refuse a swatch name the document doesn't have (it painted nothing) and suggest the name meant (`Paper` → `[Paper]`). No readiness percentage change. diff --git a/crates/compose/src/lib.rs b/crates/compose/src/lib.rs index 3dd7c25..24004d2 100644 --- a/crates/compose/src/lib.rs +++ b/crates/compose/src/lib.rs @@ -1477,7 +1477,9 @@ fn spacing_for(pp: &ParaProps, base_size: f64) -> Spacing { hyphen_penalty: 50.0 + 450.0 * pp.hyph_weight, hyphen_limit: pp.hyph_limit, ragged_stretch: base_size * 2.0, - hyph_zone: if pp.align.is_justified() { 0.0 } else { pp.hyph_zone }, + // The zone is the Single-line Composer's (unjustified text only), as in InDesign: the + // Paragraph Composer weighs every break of the paragraph instead. + hyph_zone: if pp.align.is_justified() || pp.composer != Composer::SingleLine { 0.0 } else { pp.hyph_zone }, optical: pp.optical_margin, korean_char_breaks: pp.korean_char_breaks, } diff --git a/crates/compose/src/tests.rs b/crates/compose/src/tests.rs index f5d0113..a7a9814 100644 --- a/crates/compose/src/tests.rs +++ b/crates/compose/src/tests.rs @@ -288,11 +288,16 @@ fn hyphenation_zone_limits_ragged_hyphens() { let cs = compose_story(&d, sid, &ComposeOptions::default()); all_lines(&cs).iter().filter(|l| l.hyphenated).count() }; - for c in [designcraft_doc::Composer::Paragraph, designcraft_doc::Composer::SingleLine] { - let (free, zoned, huge) = (count(0.0, c), count(36.0, c), count(1000.0, c)); - // A huge zone leaves only words that start a line (no space to break at) hyphenable. - assert!(free > 0 && zoned <= free && huge * 4 <= free, "{c:?}: {free} {zoned} {huge}"); - } + // Single-line Composer: a huge zone leaves only words that start a line (no space to break + // at) hyphenable. + let c = designcraft_doc::Composer::SingleLine; + let (free, zoned, huge) = (count(0.0, c), count(36.0, c), count(1000.0, c)); + assert!(free > 0 && zoned <= free && huge * 4 <= free, "{c:?}: {free} {zoned} {huge}"); + // The zone is the Single-line Composer's only (InDesign): the Paragraph Composer hyphenates + // the same whatever it is. + let c = designcraft_doc::Composer::Paragraph; + let (free, zoned, huge) = (count(0.0, c), count(36.0, c), count(1000.0, c)); + assert!(free > 0 && zoned == free && huge == free, "{c:?}: {free} {zoned} {huge}"); } #[test]