Commit Graph
4115 Commits
Author SHA1 Message Date
aiongg 8ce8ed5fbe Text: list labels don't raise the Ascent first baseline
The bullet or number a paragraph's list adds no longer counts toward the
first line's tallest typographic ascender: with First Baseline Offset
set to Ascent, only the line's own text places the first baseline. The
label still counts toward the line's ascent, descent and leading, and
toward the Cap Height and x Height offsets. An empty list paragraph
places its first baseline as an empty paragraph does.

Characters that don't draw, such as spaces, keep counting toward the
Ascent offset; a test pins that.
2026-10-07 22:56:10 -04:00
aiongg bb608dc03f Text: a frame's visible stroke insets its text
A text frame's text area starts at the inner edge of its stroke: the
frame edge, then the part of the stroke inside the frame, then the
inset, on all four edges. A centred stroke takes half its weight, an
inside stroke all of it and an outside stroke none. A stroke without a
colour (or with no weight) doesn't count.

Composition, hit testing and vertical frames all take the text area
from the frame, so they agree. Graphics frames, wraps and the frame's
bounds are unchanged, and type on a path, which has no inset, ignores
the stroke as well.
2026-10-07 22:55:43 -04:00
aiongg 93287b0b10 Text: vertical scale doesn't move the Ascent first baseline
With First Baseline Offset set to Ascent, the first baseline sits the
font's typographic ascender times the nominal point size below the top
of the text area: vertically scaled characters no longer push it down.
The line's ascent and descent, its leading, the Cap Height and x Height
offsets and drop caps still follow the vertical scale.
2026-10-07 22:55:24 -04:00
Brandon ThomasandClaude Opus 5.5 6f42f598bc Merge origin/main into fix/29-kerning-across-runs
Pieces carry their style's shaping settings (a missing font's glyph
fallback) and group only with pieces that share them; jidori pieces stay
apart, since jidori fits its own run. shape_run / shape_run_raw take the
per-byte style runs; the digit substitution takes main's multi-byte
ranges and fallback lookup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 22:54:25 -04:00
Brandon Thomas f4a4c9709b Merge pull request #76 from CameronGilroy/pr/data-merge
Data merge: linked source, placeholders, preview, and tiled merge
2026-10-07 22:53:41 -04:00
Brandon ThomasandClaude Opus 5.5 0590f63406 Merge #83 (layout parity) into feat/text-editing-and-frames
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>
2026-10-07 22:47:17 -04:00
Brandon ThomasandClaude Opus 5.5 962234fbdf Merge origin/main into feat/text-editing-and-frames
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>
2026-10-07 22:41:43 -04:00
aiongg acf0059d84 UI: toolbars that don't fit the window switch to two columns or scroll (#57)
In a short window the Tools panel lays its tools out in two columns,
without changing the single/double-column preference, which comes back
when the window grows again. While the window forces two columns the
column toggle is disabled. Whatever two columns can't fit scrolls
vertically.

The Control panel and the application bar scroll sideways when their
controls are wider than the window. The Control panel keeps its height.
In the application bar the workspace controls follow the menus instead of
overlapping them. A plain mouse wheel scrolls these one-direction bars,
and a thin floating scroll bar shows only when something overflows, so
nothing changes while everything fits.

Tool buttons, icon buttons and the Fill proxy carry accessibility
labels, which the new window-size tests use to find them.
2026-10-07 22:37:21 -04:00
Brandon ThomasandClaude Opus 5.5 6e8e252cc4 Merge origin/main into feat/layout-parity
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>
2026-10-07 22:34:18 -04:00
Brandon ThomasandClaude Opus 5.5 8d2d180062 Merge origin/main into multi-language-fix
Resolve i18n conflicts: keep this branch's revised zh/ar wording plus
main's new rows (font-name, missing-glyph, Korean line-break labels).
Brazilian Portuguese (#103) now uses the same cached HashMap lookup as
Arabic; the cached-lookup test covers pt-br too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 22:32:13 -04:00
Brandon ThomasandClaude Opus 5.5 48dfbcfd19 Merge origin/main into data-merge
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>
2026-10-07 22:28:15 -04:00
aiongg ed3e8ba8c3 UI: text fields take Select All, Copy, Cut, Paste, Undo and Redo from the Mac menu (#30)
The macOS menu bar takes Cmd+A, Cmd+C, Cmd+X, Cmd+V, Cmd+Z and Cmd+Shift+Z
before the window sees them, so in a panel, dialog or search field they ran
the document's commands: Select All selected every frame, Paste pasted into
the layout, Undo undid the last document change.

While a text field has keyboard focus, these Edit items now act on the field,
whether chosen by shortcut or from the menu: Select All, Undo and Redo reach
it as their keys, Copy and Cut as clipboard events, and Paste asks the
window for the system clipboard. The items stay enabled for the field even
when the document has nothing to copy or undo. With no field focused, and
for every other item, the menu works as before.
2026-10-07 22:23:01 -04:00
Brandon Thomas 2c8ea6d167 Merge remote-tracking branch 'origin/main' into r55
# Conflicts:
#	Cargo.toml
2026-10-07 22:13:23 -04:00
Brandon Thomas e97d98977f Merge pull request #103 from RicSchonfelder/i18n-pt-br
i18n: add Brazilian Portuguese (pt-br) UI translation
2026-10-07 22:13:15 -04:00
Brandon Thomas 9f2f61bfbf Merge pull request #82 from aiongg/fix/psd-channels
Images: PSD composites decode by colour mode
2026-10-07 22:13:10 -04:00
Brandon ThomasandClaude Opus 5.5 2d889af2e2 M2: keep the system clipboard away from the control channel
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>
2026-10-07 22:11:44 -04:00
Brandon Thomas a39c8893b9 Merge remote-tracking branch 'origin/main' into fix/cmyk-tiff-pdf-export
# Conflicts:
#	crates/pdf/Cargo.toml
#	crates/pdf/src/tests.rs
2026-10-07 22:05:52 -04:00
Brandon Thomas aee756d604 Merge remote-tracking branch 'origin/main' into feat/cjk-and-fonts
# Conflicts:
#	crates/ui-egui/Cargo.toml
2026-10-07 22:04:42 -04:00
Brandon Thomas 625e6b0e01 Merge pull request #58 from EthanSuquet/feat/pdfx4-flag-rgb-under-cmyk-intent
PDF/X-4: flag device RGB under the CMYK output intent
2026-10-07 22:04:21 -04:00
Brandon Thomas dd8d3037b1 Merge pull request #75 from ShaoWenbinSaleh/arabic-chinese-typesetting-rules-fix
Preserve and compose Chinese and Arabic typesetting rules
2026-10-07 22:04:16 -04:00
Brandon Thomas feb3808029 Merge pull request #56 from storybored379/fix/guide-layer-locks
Guides: honor layer protection in move and delete commands
2026-10-07 22:04:06 -04:00
Brandon Thomas 864d0b6008 Merge pull request #53 from epfabian/middle-mouse-pan
Canvas: middle-mouse drag pans the view
2026-10-07 22:04:01 -04:00
Brandon Thomas a42bd84e89 Merge pull request #79 from aiongg/fix/34-transform-dialogs
Transform: Rotate and Shear open their dialogs (#34)
2026-10-07 22:03:56 -04:00
Brandon Thomas 3b8a58fcc4 Merge pull request #97 from denizkoekden/feat/office-fonts-macos
Fonts: read Microsoft Office's bundled fonts on macOS
2026-10-07 22:03:51 -04:00
Brandon Thomas 45866e6037 Merge pull request #101 from skylartaylor/fix/idml-packaged-link-resolution
IDML: resolve nested packaged image links after relocation
2026-10-07 22:03:46 -04:00
Brandon Thomas 8d828f6efb Merge pull request #104 from skylartaylor/fix/render-outside-stroke
Render: keep outside-aligned strokes out of closed interiors
2026-10-07 22:03:41 -04:00
Brandon Thomas 08b6e335dd Merge pull request #102 from skylartaylor/fix/idml-cell-edge-priority
IDML: honor explicit cell edges at table borders
2026-10-07 22:03:36 -04:00
Brandon Thomas fd0e801968 Merge pull request #105 from skylartaylor/fix/idml-scalar-inset-spacing
IDML: import scalar InsetSpacing property values
2026-10-07 22:03:31 -04:00
Brandon ThomasandClaude Opus 5.5 fdffbb4b23 M9: distinct zh label for Revert; translations are our own
Revert no longer shares Undo's Simplified Chinese label. Drop the
comments and ROADMAP wording that tied terminology to a vendor's help.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 22:01:57 -04:00
Brandon ThomasandClaude Opus 5.5 330b8c18f2 Images: PSD checks the image data is present before allocating
Header dimensions are untrusted: a tiny file claiming a ~460 MiB composite
allocated it before finding the data missing. ImageData::holds verifies
raw planes fit in the data, or that RLE row counts each reach a full row
and sum to no more than the data, before the RGBA buffer is allocated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:59:39 -04:00
Brandon ThomasandClaude Opus 5.5 593848bf17 Compose: an empty paragraph's format comes from its own mark
Story::char_format_at returns the preceding run at a boundary (the format
typing takes), so a run ending at the empty paragraph's start gave it the
previous paragraph's mark format. Add Story::char_format_of (the run
containing the byte) and use it; regression test with differing marks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:56:43 -04:00
Brandon ThomasandClaude Opus 5.5 2531f039fe Data merge: review fixes (bounded reads, no truncation, safe links, docs)
- Remove the docs/superpowers planning spec.
- textimport: cap decompressed zip parts at 64 MiB (protects Place and
  xlsx data sources); oversized part is an error. Regression test.
- datamerge: refuse data files over 256 MiB and skip image candidates
  over 256 MiB by metadata before reading.
- datamerge: assign_page uses get_mut instead of indexing spreads.
- datamerge: one/limit over u32 are errors, not truncated.
- select_records dedupes with a HashSet (was O(n^2)), order kept.
- Hyperlink cells: only http, https, ftp and mailto schemes link.
- Document data.* commands and data.merge creating a new document.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:54:38 -04:00
Brandon ThomasandClaude Opus 5.5 a79351e249 Glyph outlines: minimal boolean form (clippy 1.96 nonminimal_bool)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:49:48 -04:00
Brandon ThomasandClaude Opus 5.5 730d598d48 Kinsoku::allows: minimal boolean form (clippy 1.96 nonminimal_bool)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:48:33 -04:00
Brandon ThomasandClaude Opus 5.5 927191d25f About: contributor and model credits compiled in (grab bag + table, self-submitted names) (#108)
* About: contributors compiled in from contributors.json (grab bag + table, sortable, name toggle)

Adds the craftrules standard (standards/contributors.md) to Help > About DesignCraft, which now
has tabs About · Contributors · Models (`help.about {tab}` selects one).
contributors/contributors.json is generated by craftrules/scripts/contributors.py and baked
into the binary by crates/ui-egui/build.rs as static tables (crates/ui-egui/src/credits.rs).
Each contributor line: @username, opt-in display/real name, PRs, commits, lines +/−/Δ,
binary assets +/−, first/last commit. Sortable by every column; alphabetical ignores
case and the leading @.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Contributors docs: craftrules is two levels up (../../craftrules)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Contributors: self-submitted names in contributors/people.toml; AGENTS.md credit-yourself section

build.rs reads contributors/people.toml next to the generated contributors.json and shows a name only
for entries the generator verified as written by that person (craftrules standards/contributors.md).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Contributors: regenerate (verified people.toml entries)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:16:42 -04:00
skylar taylor-barrick 8d56e875eb Compose: fit horizontal text frames by the last baseline 2026-10-07 16:10:43 -06:00
skylar taylor-barrick 0629137ef7 IDML: import scalar InsetSpacing property values 2026-10-07 16:10:32 -06:00
skylar taylor-barrick 4910e42bcc Render: keep outside-aligned strokes out of closed interiors 2026-10-07 16:10:24 -06:00
RicSchonfelder bd8291c55f i18n: add Brazilian Portuguese (pt-br) UI translation
Registers pt-br in the interface-language menu (Edit › Interface
Language) with a dedicated pt_br.rs catalog mirroring the ar.rs
pattern: 1005 (en, pt-br) pairs covering the same key set, with the
'pt-br' dispatch added to i18n::tr and the translation test extended.
2026-10-07 17:43:34 -03:00
skylar taylor-barrick 0f888ef794 IDML: honor explicit cell edges at table borders 2026-10-07 14:38:40 -06:00
skylar taylor-barrick 089b1ac28f IDML: resolve nested packaged image links after relocation 2026-10-07 14:27:50 -06:00
Deniz Kökden 2a3b3e6661 Fonts: read Microsoft Office's bundled fonts on macOS 2026-10-07 21:23:57 +02:00
Deniz Kökden 60712dedb2 Compose: an empty paragraph takes its mark's character format
The line height of a paragraph without glyphs came from the paragraph style; InDesign uses the
format of the paragraph mark (the CharacterStyleRange holding its <Br/>).
2026-10-07 21:23:57 +02:00
Brandon ThomasandClaude Opus 5.5 f17397c305 Rename PrintCraft to PdfCraft (storytold/pdfcraft) (#95)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 14:55:09 -04:00
aiongg 2866f617a7 UI: font menu previews draw upright
text_line flipped glyph outlines that the font database already gives
y-down, so each family's preview in the font menu was drawn upside down
below its baseline and cut off at the bottom of the image.
2026-10-07 10:44:46 -04:00
aiongg 99f1e653f2 Text: locale-coded language names (de_DE_2006) get their language
IDML names some languages by locale code
(AppliedLanguage="$ID/de_DE_2006", "$ID/nl_NL_2005") beside names such
as "English: USA" and "Spanish: Castilian". language_tag maps any locale
code (ll, ll_CC, ll-CC, with a reform year after them) to its BCP 47 tag
(de-DE, nl-NL; kept once per process, at most 512 distinct tags), ignores
IDML's $ID/ prefix, and knows Spanish: Castilian (es-ES) and Swiss French
and Italian. The stored name stays as written, so IDML round trips are
unchanged.

What depends on the language now goes by the tag: typographer's quotes
(by language subtag; Swiss regions take guillemets), English
hyphenation and spelling (is_english), Korean word breaking and the CJK
fallback chains (ja-JP, ko-KR are Japanese and Korean whatever the
region).
2026-10-07 10:44:46 -04:00
aiongg c64e538de5 UI: the font menu groups fonts by script, CJK fonts by language
Font menus list Western (and other-script) families first, then
Japanese, Simplified Chinese, Traditional Chinese and Korean families,
each group alphabetical by the name shown, with a separator between
groups. The group comes from the font's own data, strongest signal
first: the meta table's dlng (else slng) languages, family names in a
CJK language (Windows and Macintosh language IDs), OS/2 code pages (JIS,
Chinese Simplified, Korean Wansung, Chinese Traditional, Korean Johab);
a font declaring none of these goes by what it covers (kana, Hangul,
ideographs). Ties go Japanese, Simplified, Traditional, Korean. Loaded faces are classified
once; installed fonts by the font scan, which also reads their OS/2 and
meta tables (and cmap only for fonts declaring nothing), capped.

CJK families show their family name in their language, the English
name on hover; Preferences > Type > Show Font Names in English
(prefs.set {showFontNamesInEnglish}, off by default) shows English
names. Search matches either name; documents store the English name.
The Character panel, Control bar, Properties, style dialogs, Find Font
and Glyphs panel lists all follow this order. The main font menu stays
open while searching or starring (it closed on any click inside).

Font previews don't draw DesignCraft's missing-glyph box for fonts
whose .notdef is empty.
2026-10-07 10:44:46 -04:00
aiongg 1ef187ad02 Text: missing glyphs show as boxes
A character the applied font lacks is drawn as that font's missing-glyph
box (its .notdef, gid 0), on screen and in PDF, and Preflight lists the
characters by font ("Missing glyphs in <family> <style>: …", an error,
at most 20 named). A .notdef without an outline is drawn as a hollow box
across its advance, so a missing character never disappears. PDF draws
.notdef glyphs as paths, which PDF/A and PDF/UA accept. Kenten marks are
set in their text's font the same way.

The document setting Draw Missing Glyphs from Fallback Fonts
(DocSettings::glyph_fallback; Preferences > Composition,
document.preferences {glyphFallback}, undoable) draws them from fallback
fonts instead (the language-aware chains, then any font; kenten marks
from a fallback font, else a bullet). It is off in new documents and
IDML imports and on in files saved before it existed, which keep
drawing as they did. A missing font's substitute always uses fallback
fonts. The composition cache's signature includes the setting. Tests
whose Arabic comes from a fallback font turn the setting on.
2026-10-07 10:44:46 -04:00
aiongg a08198e139 CJK 1.11: Chinese language names in their common spellings
language_tag ignores case and punctuation and recognises Chinese in its
common spellings and locale codes (Simplified Chinese, Chinese
(Simplified), zh_CN, zh-Hans; Traditional Chinese, zh_TW, zh_HK,
zh-Hant), and Japanese and Korean locale codes (ja_JP, ko_KR).
Typographer's quotes for Chinese and Japanese follow the tag, so every
spelling takes the same quotes. IDML import keeps the name as written.
2026-10-07 10:44:46 -04:00
aiongg 76c0b79760 CJK 1.10: Package copies the fallback fonts that draw text
Composition draws the characters a named font lacks with fallback faces
(the language's CJK chain, then the generic fallbacks). Package now also
copies their font files: it collects the distinct faces of the visible
glyphs of every composed story (table cells and footnotes included) and
copies those that aren't a named font's face by the same rules (restricted
licence listed, bundled included with DesignCraft, no file noted, each file
once). The report lists them under Fallback fonts.
2026-10-07 10:44:46 -04:00