Commit Graph
2966 Commits
Author SHA1 Message Date
Brandon Thomas a67cf73d83 Merge storytold/main into effects-dialog-global-light-angle 2026-10-24 10:22:52 -04:00
Brandon Thomas 520a810640 Merge pull request #1742 from dotCooCoo/fix/package-redirect-test-junction
Package: the Windows redirect test falls back to a directory junction
2026-10-24 10:22:47 -04:00
Brandon Thomas 8d6989c508 Merge pull request #1740 from Silvertree2010/fix/h1918-footnote-numbering-overflows-u32
Saturate footnote and endnote numbering at u32::MAX
2026-10-24 10:22:43 -04:00
Brandon Thomas 178efcccd9 Merge pull request #1732 from dotCooCoo/fix/rooted-link-tests-on-windows
Preflight: the missing-link test uses a path that is absolute on Windows too
2026-10-24 10:22:38 -04:00
Brandon Thomas 5dddce5eb6 Merge pull request #1707 from Silvertree2010/fix/h1903-table-style-altrows-counts-are-t
Saturate table style altRows counts instead of truncating to 32 bits
2026-10-24 10:22:35 -04:00
Brandon Thomas 280436dbdc Merge pull request #1700 from Silvertree2010/fix/h1882-html-epub-style-css-drops-the-un
Join underline and strikethrough into one text-decoration in EPUB CSS
2026-10-24 10:22:31 -04:00
Brandon Thomas 6cf71e33e3 Merge pull request #1699 from Silvertree2010/fix/h1863-from-bezpath-loses-smooth-anchor
Detect smooth anchors on all open subpaths in from_bezpath
2026-10-24 10:22:28 -04:00
aiongg 5def4a8c01 Story Optical Margin Alignment with a size, and Ignore Optical Margin (Story panel, engine and IDML) (#1705)
* Type: story Optical Margin Alignment with a size, and Ignore Optical Margin (engine, IDML)

A story's Optical Margin Alignment applies to every paragraph except those
with Ignore Optical Margin; hang amounts scale with the story's size.
story.options sets it, type.para and paragraph styles take
ignoreOpticalMargin. IDML imports and exports StoryPreference
OpticalMarginAlignment/OpticalMarginSize and IgnoreEdgeAlignment. The
per-paragraph opticalMargin switch keeps hanging at the text's own size.

Part of #947.

* Type: the Story panel, and Ignore Optical Margin in the Paragraph panel menu and Paragraph Style Options

Window > Type & Tables > Story sets Optical Margin Alignment and its size
for the stories of the text selection or the selected text frames through
story.options, and is disabled without either. type.selectionAttrs
reports the stories' values as storyOptions, null where they differ.
The Paragraph panel menu toggles ignoreOpticalMargin, and Paragraph Style
Options > Indents and Spacing has an Ignore Optical Margin checkbox.

Part of #947.

* ROADMAP: the story Optical Margin Alignment entry names its default and scope
2026-10-24 10:08:40 -04:00
Brandon ThomasandClaude Opus 5.5 5fca302ff6 Endnotes: saturate the remaining numbering sites at u32::MAX
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 10:01:04 -04:00
aiongg d767fcf41e Text frames: a custom baseline grid's Relative To (page, margin, frame or inset) (#1758) 2026-10-24 09:55:47 -04:00
aiongg 7848c21220 Paragraph Style Options: Align to Grid (None, All Lines, First Line Only) in Indents and Spacing (#1759) 2026-10-24 09:38:37 -04:00
aiongg 4be45a713a Anchored text frames compose against the grid and page where they are placed (#1710)
* Anchored text frames compose against the grid and page where they are placed

An anchored text frame is not a spread item, so frame_specs composed it at
its stored transform: no page, no page side, no page rect, and a baseline
grid phase taken from that transform. A note set to Only Align First Line
to Grid snapped to the wrong line, and page-number markers and
spine-relative alignment inside it saw no page.

The composer now looks up the host story's composition first, finds where
it placed the frame (in its frames' anchored objects, footnotes or table
cells) and composes the frame's story against that placement
(ComposeOptions::placed). The cache does the same and adds the placement
to the entry's signature, so a note recomposes when its host moves it.
Host lookups stop after eight levels, which bounds stories anchored in
each other.

* Anchored text frames: the cache keys on the placed spread's pages
2026-10-24 08:30:03 -04:00
aiongg d4c1322d97 Merge pull request #1709 from aiongg/w65-batch
Integration batch: book-chapter IDML baseline grids, hyphenation, and the Paragraph panel stack
2026-10-24 08:14:29 -04:00
NetterSilverandClaude Haiku 5.5 f0ce96138c Saturate footnote and endnote numbering at u32::MAX
Found while testing crates/compose/src/notes.rs:133 (also crates/doc/src/notes.rs:265 footnote_start and crates/doc/src/endnotes.rs:150 endnote_start)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 09:07:37 +00:00
PiMinusMaxandClaude Opus 5.5 c11006c832 Effects dialog: the Angle with Use Global Light sets the global light
The Angle field was greyed out with Use Global Light on. It now shows
the document's global light angle and changes it for every effect that
uses it, applied with the effects in one undo step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 10:55:13 +02:00
dotCooCoo 333cdf116f Package: the Windows redirect test falls back to a directory junction
package_refuses_windows_directory_redirects made its redirect with
symlink_dir. Without Developer Mode or elevation that call fails with
os error 1314 (ERROR_PRIVILEGE_NOT_HELD), which std does not report as
PermissionDenied, so the skip arm did not match and the test panicked.

When symlink_dir fails, the test now makes a directory junction with
mklink /J, which needs no privilege. is_redirect treats a junction as
a redirect, so the test still checks that File > Package refuses the
redirected folder. It skips only when neither can be made. The package
code is unchanged.
2026-10-24 01:53:04 -07:00
Dylan M. TaylorandClaude Sonnet 5.5 c313c53497 refactor: split complex functions in ruby, warichu, pdf text, render text, epub, pdfx (Sonar S3776) (#1728)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 04:51:58 -04:00
Dylan M. TaylorandClaude Sonnet 5.5 4c5ea73d98 refactor(tools): fewer parameters and simpler pointer handling (Sonar S107, S3776) (#1725)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 04:51:35 -04:00
Dylan M. TaylorandClaude Sonnet 5.5 75d5b015d3 refactor(idml): extract helpers to cut cognitive complexity (Sonar S3776) (#1723)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 04:51:31 -04:00
Dylan M. TaylorandClaude Sonnet 5.5 cb763c2583 refactor: split complex functions in psd, table, parabox, index, trace, pdf export, render (Sonar S3776) (#1724)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 04:51:26 -04:00
Dylan M. TaylorandClaude Sonnet 5.5 8271f1a26b refactor(engine): split execute_unguarded, load_styles and resize_border (Sonar S3776) (#1726)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 04:50:14 -04:00
Dylan M. TaylorandClaude Sonnet 5.5 c142678bd5 refactor(ui-egui): extract character style General section (Sonar S3776) (#1720)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 04:49:00 -04:00
Dylan M. TaylorandClaude Sonnet 5.5 e0c244d2ed refactor(ui-egui): extract style option field helpers (Sonar S3776) (#1719)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 04:48:56 -04:00
Dylan M. TaylorandClaude Sonnet 5.5 e651c637f4 refactor(ui): extract helpers from conditions, book, credits and page control panels (Sonar S3776) (#1721)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 04:45:48 -04:00
Dylan M. TaylorandClaude Sonnet 5.5 8299d26400 chore: replace trivial closures with method paths (Sonar S1612) (#1714)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 04:30:43 -04:00
Dylan M. TaylorandClaude Sonnet 5.5 bfd95b258b chore: drop redundant 'static lifetimes in statics and consts (Sonar S8863) (#1713)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 04:30:39 -04:00
dotCooCoo f5e1bda7cc Preflight: the missing-link test uses a path that is absolute on Windows too
a_missing_link_shown_by_its_preview_is_still_reported stored the link
/definitely/missing dir/photo.jpg in a document without a path. On
Windows that path names no drive, so document_path refuses it as not
absolute and the preflight message ends with "(the path is not
valid)", and the test failed. The test now stores a link under
std::env::temp_dir(), an absolute path with the default
temporary-folder settings on Windows, macOS and Linux, and expects the
message for that path. The preflight code is unchanged.
2026-10-24 01:21:55 -07:00
Dylan M. TaylorandDylan Taylor f90d286721 chore: resolve SonarCloud maintainability issues (#1698)
* chore: resolve SonarCloud maintainability issues

- Replace lambda closures with method references (S1612)
- Replace wildcard imports with explicit imports (S2208)
- Refactor complex functions with extracted helpers (S3776)
- Replace OR pattern with range pattern in math parser (S9047)

* style: apply rustfmt to warichu helper

* fix(compose): revert slice conversion in tests and remove unused var in warichu

* Group warichu row layout scalars to satisfy S107 parameter limit

* style: satisfy rustfmt in warichu.rs

---------

Co-authored-by: Dylan Taylor <dylan@craftmaker.dev>
2026-10-24 03:54:24 -04:00
aiongg 0143633930 Batch: the compose cache keeps both halves of each number's bits on 32-bit targets 2026-10-24 07:26:09 +00:00
aiongg 5905cd3d9a Batch: the compose cache keys on the page geometry under a frame; one copy of each progress-log line 2026-10-24 07:09:46 +00:00
skylar taylor-barrick 5449bc4757 M6: preserve PDF catalogs and safely apply layer choices (#1670)
Preserve existing PDF catalog entries and full object generations. Accept literal null trailer entries while failing closed on encrypted/hybrid/ambiguous or unreadable history. Validate visibility variants atomically before document edits, suppress stale unsupported canvas overrides, and preserve conservative content cropping without overcropping empty optional-content stubs.

Local full CI: all 9 gates passed, 3063 tests passed and 6 skipped, all 16 WASM-safe crates checked. Independent qpdf/preservation/Poppler checks passed for17 supported inputs;6 refusal cases stayed refused. All11 additional Prev controls passed. GitHub CI and CodeRabbit passed on00d5fa5c; CodeRabbit confirmed the Prev finding addressed. Author history preserved; no native format changes.
2026-10-24 00:51:57 -06:00
skylar taylor-barrick 00d5fa5cdd M6: reject unreadable PDF trailer history links (#1670)
Reject a non-null Prev entry that cannot be read as an offset instead of silently treating it as the end of the guarded trailer chain. Keep absent/null end markers and readable numeric offsets unchanged.

Reproduced CodeRabbit discussion_r4366245854 with an independent probe and a failing native regression before the fix. The synthetic regression covers seven unreadable value types plus absent/null and integer/real history controls.

Validation: all 9 cargo xtask ci gates passed (3063 tests passed, 6 skipped; 16 WASM-safe crates). One unrelated GPU test was labelled leaky by nextest in that run and passed cleanly in an isolated rerun. Independent checks: 17 original supported PDF variants still pass qpdf, logical preservation and Poppler pixels; 6 original refusal cases remain refused. All 11 additional Prev controls pass (7 refused, 4 accepted).
2026-10-24 00:40:33 -06:00
aiongg fa36996b80 Hyphenation Settings: doc comments on their functions, a mixed slider shows dimmed and a click sets it, a refused Preview says why 2026-10-24 06:38:40 +00:00
skylar taylor-barrick 7427a15863 M6: harden placed PDF layer variants (#1670)
Integrate current main (d8d78851) without rewriting the contributor's commits, retaining craft-libs 9f75d3dc.

Accept literal null trailer entries while rejecting actual or ambiguous encryption/hybrid markers. Structurally inspect bounded xref/trailer history instead of adopting trailer-looking comments. Preflight all selected source variants before editing/undo; preserve reset-to-defaults. Suppress stale unrewritable canvas overrides rather than revealing source content. Keep conservative all-content crop fallback without overcropping layerless/null stubs.

Validation: cargo xtask ci, all 9 gates passed; 3062 tests passed, 6 skipped; all 16 WASM-safe crates checked. 17 supported variants passed independent qpdf, logical preservation and Poppler pixel checks; 6 unsupported/repair-only cases refused. Direct-harness Claude Opus 5 reviewed the exact main-relative delta with no blocking findings.

No native-format changes or unrelated layer features. Synthetic regression fixtures are generated in test code.
2026-10-24 00:18:22 -06:00
NetterSilverandClaude Haiku 5.5 4867a3f41b Saturate table style altRows counts instead of truncating to 32 bits
Found while testing crates/engine/src/cmd/table.rs:1742

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 08:08:22 +02:00
aiongg f48ea43a63 Paragraph panel: Define Lists… opens its dialog; tests for First Line Only in the three panels 2026-10-24 06:04:36 +00:00
aiongg 92c565e854 Merge #1570: Paragraph panel: InDesign's layout and panel menu
# Conflicts:
#	crates/ui-egui/src/i18n/ar.rs
#	crates/ui-egui/src/i18n/cs.rs
#	crates/ui-egui/src/i18n/de.rs
#	crates/ui-egui/src/i18n/it.rs
#	crates/ui-egui/src/i18n/ja.rs
#	crates/ui-egui/src/i18n/ka.rs
#	crates/ui-egui/src/i18n/pl.rs
#	crates/ui-egui/src/i18n/pt_br.rs
#	crates/ui-egui/src/i18n/ru.rs
#	crates/ui-egui/src/i18n/uk.rs
2026-10-24 06:02:06 +00:00
aiongg 6d4b1f797f Merge #1486: Control panel (¶): Bulleted and Numbered List, Shading and Border, as InDesign's
# Conflicts:
#	crates/ui-egui/src/chrome.rs
#	crates/ui-egui/src/i18n/ar.rs
#	crates/ui-egui/src/i18n/cs.rs
#	crates/ui-egui/src/i18n/it.rs
#	crates/ui-egui/src/i18n/ka.rs
#	crates/ui-egui/src/i18n/pl.rs
#	crates/ui-egui/src/i18n/pt_br.rs
#	crates/ui-egui/src/i18n/ru.rs
#	crates/ui-egui/src/i18n/uk.rs
#	crates/ui-egui/src/panels/properties.rs
2026-10-24 06:01:20 +00:00
aiongg c428083d74 Merge #1483: Bulleted and Numbered List buttons give InDesign's default hanging indent
# Conflicts:
#	crates/ui-egui/src/i18n/ar.rs
#	crates/ui-egui/src/i18n/cs.rs
#	crates/ui-egui/src/i18n/de.rs
#	crates/ui-egui/src/i18n/it.rs
#	crates/ui-egui/src/i18n/ja.rs
#	crates/ui-egui/src/i18n/ka.rs
#	crates/ui-egui/src/i18n/pl.rs
#	crates/ui-egui/src/i18n/pt_br.rs
#	crates/ui-egui/src/i18n/ru.rs
#	crates/ui-egui/src/i18n/uk.rs
#	docs/target-app-parity.md
2026-10-24 06:00:59 +00:00
aiongg 55ec96920a Control panel ¶ Align to Baseline Grid keeps First Line Only paragraphs aligned 2026-10-24 06:00:47 +00:00
aiongg 3903519c80 Merge #1459: Control panel: the text controls have InDesign's Character (A) and Paragraph (¶) modes
# Conflicts:
#	crates/ui-egui/src/i18n/ar.rs
#	crates/ui-egui/src/i18n/cs.rs
#	crates/ui-egui/src/i18n/it.rs
#	crates/ui-egui/src/i18n/ka.rs
#	crates/ui-egui/src/i18n/pl.rs
#	crates/ui-egui/src/i18n/pt_br.rs
#	crates/ui-egui/src/i18n/ru.rs
#	crates/ui-egui/src/i18n/uk.rs
2026-10-24 05:59:51 +00:00
aiongg 0ba2828c77 Properties ••• Align to Baseline Grid keeps First Line Only paragraphs aligned 2026-10-24 05:59:40 +00:00
aiongg 48ff7aa03e Merge #1457: Properties: ••• expands Character and Paragraph in place, as in InDesign
# Conflicts:
#	crates/ui-egui/src/i18n/ar.rs
#	crates/ui-egui/src/i18n/cs.rs
#	crates/ui-egui/src/i18n/it.rs
#	crates/ui-egui/src/i18n/ka.rs
#	crates/ui-egui/src/i18n/pl.rs
#	crates/ui-egui/src/i18n/pt_br.rs
#	crates/ui-egui/src/i18n/ru.rs
#	crates/ui-egui/src/i18n/uk.rs
2026-10-24 05:56:55 +00:00
aiongg 87be33e969 Hyphenation: new documents start with Capitalized Words, Last Word and Across Column off 2026-10-24 05:56:36 +00:00
aiongg 0cfbc756d6 Hyphenate Across Column: overflow-safe re-lay budget; drop the stale ROADMAP clause 2026-10-24 05:53:02 +00:00
aiongg 4cbeea2232 Merge #1572: Hyphenate Across Column: no column or frame ends in a hyphen when it's off 2026-10-24 05:52:41 +00:00
aiongg e94e776fd8 Merge #1565: Hyphenation Settings: InDesign's dialog from the Paragraph panel menu, and in Paragraph Style Options 2026-10-24 05:52:41 +00:00
aiongg e79da41ce9 Merge #1704: Text frames: a custom baseline grid keeps its start and increment through IDML
# Conflicts:
#	crates/compose/src/lib.rs
#	crates/idml/src/tests.rs
2026-10-24 05:52:12 +00:00
aiongg e11f9f6202 Merge #1703: Baseline grid: Relative To Top Margin starts the grid at each page's top margin
# Conflicts:
#	crates/compose/src/lib.rs
2026-10-24 05:51:57 +00:00
aiongg d8d7885172 Anchored objects: Relative to Spine mirrors custom positions on right-hand pages (#1702)
* Anchored objects: Relative to Spine mirrors custom positions on right-hand pages

* Anchored objects: page side from the frame's spread position; footnote cache keyed by page side
2026-10-24 01:34:05 -04:00