From 0f0e707e60e42d6629d85680204c2ca8493e2975 Mon Sep 17 00:00:00 2001 From: M Balazs PC Date: Sat, 7 Nov 2026 16:57:21 +0100 Subject: [PATCH] Type: a line a soft return ends is justified as a wrapped line is In Justify Left, Center or Right, only the paragraph's last line keeps its alignment; a line that a soft return (U+2028) ends is spread to the frame's edges like any wrapped line. Illustrator's own layout in a user's .ai sets such lines justified, and VectorCraft left them ragged. --- crates/text/src/layout/flow.rs | 4 +++- crates/text/src/tests/typo.rs | 23 ++++++++++++++++------- docs/type-parity.md | 5 +++-- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/crates/text/src/layout/flow.rs b/crates/text/src/layout/flow.rs index 112dabb23..f46c1c23a 100644 --- a/crates/text/src/layout/flow.rs +++ b/crates/text/src/layout/flow.rs @@ -543,7 +543,9 @@ fn prepare_line_geometry(cx: &Ctx<'_>, t: &TextObject, paragraph: &ParagraphData // Justification adds nothing to the list marker's glyphs. let mut held = held; held.extend(index..paragraph.marker.min(body)); - let last_of_para = position.end >= n || position.end.checked_sub(1).and_then(|i| sg.get(i)).is_some_and(|g| g.ch == '\u{2028}'); + // A line a soft return ends is justified as a wrapped one is: only the paragraph's last line + // keeps the alignment of Justify Left, Center or Right. + let last_of_para = position.end >= n; LineGeometry { position, index, diff --git a/crates/text/src/tests/typo.rs b/crates/text/src/tests/typo.rs index 8f37e5905..ee629ba4a 100644 --- a/crates/text/src/tests/typo.rs +++ b/crates/text/src/tests/typo.rs @@ -1970,14 +1970,23 @@ fn soft_return_breaks_line_without_new_paragraph() { assert_eq!(&t.plain_text()[l1.start..l1.end], "Line 2"); } +/// A line ending in a soft return is justified as a wrapped line is: only the paragraph's last +/// line keeps its alignment. Illustrator's own layout in a user's `.ai` (used locally, not +/// committed) spreads such lines to the frame's edge. #[test] -fn soft_return_in_justified_text_does_not_spread() { - let text = "Short\u{2028}A much longer second line of text inside the frame."; - let t = area(text, style(12.0), Rect::new(0.0, 0.0, 300.0, 200.0), Justify::JustifyLeft); - let lay = layout(db(), &t); - assert!(lay.lines.len() >= 2); - let l0 = &lay.lines[0]; - assert!(l0.x1 - l0.x0 < 100.0, "short line ending with soft return is not justified: {}", l0.x1 - l0.x0); +fn soft_return_in_justified_text_spreads_like_a_wrapped_line() { + let frame = Rect::new(0.0, 0.0, 300.0, 200.0); + let text = "A line of a few words\u{2028}and the last line."; + for justify in [Justify::JustifyLeft, Justify::JustifyCenter, Justify::JustifyRight] { + let lay = layout(db(), &area(text, style(12.0), frame, justify)); + assert_eq!(lay.lines.len(), 2); + let (l0, l1) = (&lay.lines[0], &lay.lines[1]); + assert!((l0.x0 - frame.x0).abs() < 1e-6 && (l0.x1 - frame.x1).abs() < 1e-6, "{justify:?}: {l0:?}"); + assert!(l1.x1 - l1.x0 < 200.0, "{justify:?}: the last line isn't justified: {l1:?}"); + } + // Aligned type stays aligned. + let lay = layout(db(), &area(text, style(12.0), frame, Justify::Left)); + assert!(lay.lines[0].x1 < frame.x1 - 100.0); } #[test] diff --git a/docs/type-parity.md b/docs/type-parity.md index b36cb4892..6100f028a 100644 --- a/docs/type-parity.md +++ b/docs/type-parity.md @@ -1,6 +1,6 @@ # Type parity -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-07 · **Change:** minor (Indian-language hyphenation review and license allowlist, #4947; Bulgarian among the languages, with its quote marks and the fonts' Bulgarian forms, #5945; previously minor: Show Snap to Glyph Options scrolls to the options, with a Snap to Glyph checkbox, #5273; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-07 · **Change:** minor (a soft return in justified type no longer keeps its line from being justified; Indian-language hyphenation review and license allowlist, #4947; Bulgarian among the languages, with its quote marks and the fonts' Bulgarian forms, #5945; previously minor: Show Snap to Glyph Options scrolls to the options, with a Snap to Glyph checkbox, #5273; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x) Type is Illustrator's largest single area by use (weight 13 of 105 across "Type core" and "Type advanced" in [target-app-parity.md](target-app-parity.md)). This checklist lists the features one by one. Status is from the @@ -19,7 +19,7 @@ against Illustrator's public documentation; **estimated** unless noted. | Feature | Status | Notes | |---|---|---| | Mouse wheel over the closed font-family field | done | #5253: Character, Properties and Control step selected text through the family list using saved font filters (excluding search text), one undo step per notch; the style is matched and the list stops at either end. Escape and leaving the field keep the change. Order, bounds and Undo grouping are VectorCraft's choices; scores unchanged. | -| Soft return (forced line break, Shift+Enter) | done | Shift+Enter inserts a soft return (U+2028), breaking the line without starting a new paragraph; paragraph spacing (space before/after) and first-line indents apply only at paragraph ends; continuation lines in lists do not repeat the marker; soft return lines in justified text do not spread (#2754) | +| Soft return (forced line break, Shift+Enter) | done | Shift+Enter inserts a soft return (U+2028), breaking the line without starting a new paragraph; paragraph spacing (space before/after) and first-line indents apply only at paragraph ends; continuation lines in lists do not repeat the marker; in justified text a line a soft return ends is justified as a wrapped line is, only the paragraph's last line keeping its alignment, as Illustrator's own layout in a user's `.ai` sets it (evidence: `tests::typo::soft_return_in_justified_text_spreads_like_a_wrapped_line`; first done the other way in #2754) | | Native font-family labels | partial | With Show Font Names in English off, localized legacy names are used when typographic names contain no native label (#2208); loaded-font and catalog-only regressions. Choosing among multiple native languages is unchanged. | | Point, area and type-on-a-path type; vertical variants | done / partial | vertical point, area and path type have initial support; fullwidth `!` / `?` keep the nominal glyph upright when no vertical alternate exists (Unicode Tu); in a non-rectangular area a word too wide for the top lines moves down to the first line that holds it (#1615); Escape while typing ends the edit, keeps the type selected and switches to the Selection tool (#1802); `text.create` and `text.createInPath` take `justify` (#1752); MCP `add_text` forwards `vertical` to both commands; the Type and Vertical Type tools make area type when a closed path's outline is clicked and type on a path when an open one is, with pointers that say which, as the public help describes ([Create text](https://web.archive.org/web/20220127090642/https://helpx.adobe.com/illustrator/using/creating-text.html), [Create type on a path](https://web.archive.org/web/20220127090635/https://helpx.adobe.com/illustrator/using/creating-type-path.html)) | | Area Type Options (rows, columns, inset, first baseline, Text Flow by rows or by columns, Auto Size, Shrink Text to Fit) | done | Text Flow fills the cells down each column first (By Columns, the default, as files from before it open) or across each row first (By Rows), in the dialog and `text.areaOptions {flow}` (#4978); the commands that make or restyle type say when it does not fit its frame; MCP `add_text` takes Auto Size and Shrink Text to Fit (#1471) | @@ -79,6 +79,7 @@ Character Styles menu New/Redefine and footer New capture the first selected cha | Date | Change | Summary | |---|---|---| +| 2026-11-07 | minor | Soft return: in Justify Left, Center or Right, the line a soft return ends is justified as a wrapped line is; only the paragraph's last line keeps its alignment. Illustrator's own layout in a user's `.ai` (used locally, not committed) justifies those lines. Scores and estimates unchanged. | | 2026-11-07 | minor | Indian-language hyphenation (#4947): eleven MIT-licensed pattern sets, with grapheme and shaping-cluster protection in both composers and existing paragraph limits. Assamese and Sanskrit are selectable; Sanskrit automatic patterns remain pending an allowlisted source. Scores and estimates unchanged. | | 2026-11-06 | minor | Alt + numeric-keypad codes (`Alt+0176` → °) type their character at the caret on Windows, and `type.insert` inserts a character by `code` or `unicode` (#5108); scores and estimates unchanged | | 2026-11-06 | minor | Snap to Glyph › Glyph Bounds: each glyph's box gives four corners a drawn point lands on, also on a curved side (`B`), and its box and edges turn with rotated type (#5112); scores and estimates unchanged |