Commit Graph
1004 Commits
Author SHA1 Message Date
aiongg cffff885bb Integration: GREP lookbehind overlay test passes the drop-cap end (#425)
next's overlays() takes the drop cap's end as a fifth argument; the test from #316 calls it with 0, like the other overlay tests.
2026-10-11 02:20:00 +00:00
aiongg 037771057e Merge #316 update: GREP styles with a pattern that can't compile are rejected, and imports warn
Conflicts:
- engine cmd/file.rs, cmd/interchange.rs: kept next's file.open and
  file.openIdml docs (content detection, INDD conversion, package parts)
  and added "GREP styles whose pattern can't compile" to their warnings.
  open_idml keeps next's conversion and import-report warnings and appends
  grep_style_warnings after the font warnings.
- engine cmd/style.rs: style.paragraph.create/edit docs combine next's
  startAt and kinsoku notes with the grepStyles rule. create_para and
  edit_para keep next's set_json_over, continue_numbering and
  explicit_default_kinsoku, then call check_grep_styles. The branch's
  grep_style_error, check_grep_styles and grep_style_warnings follow
  explicit_default_kinsoku. Kept next's delete_tests and
  swatch_options_tests; grep_style_tests goes at the end of the file.
- ui-egui dialogs.rs: kept next's style_section_edit tests and added the
  branch's bad-GREP-pattern test.

confirm_paragraph_style_options, grep_error and the dialog status line
merged without conflicts; next had not changed the OK arm they replace.
2026-10-11 02:19:10 +00:00
aiongg cf0ff4a034 Merge group-nested-panic: Objects: group siblings inside a group; refuse mixed levels and spreads
Conflicts in crates/engine/src/cmd/object.rs:
- Helpers: kept next's opt_u64, siblings_mut(d, spread, parent), reorder,
  set_layer_deep and set_layer, then added the branch's GroupPlan,
  group_plan, GROUP_SAME_LEVEL and can_group. The branch's
  siblings_mut(d, &GroupPlan) is dropped; group() calls next's helper as
  siblings_mut(d, plan.spread, &plan.parent).
- Tests: kept next's reorder_tests and the other test modules next added,
  followed by the branch's group_tests module.

group() and ungroup() were unchanged on next, so group() is the branch's
version. cmd/mod.rs (CANT_GROUP_SELECTION, selection_reason) and lib.rs
(execute_unguarded) merged without conflicts.
2026-10-11 02:15:58 +00:00
aiongg aa6446336b Paragraph Style Options: after a later step fails, OK edits the style it created
Once style.paragraph.create (or edit with a rename) succeeds, the dialog
switches to editing that style, so when export tagging then fails the
dialog stays open with the error and a second OK edits the style instead
of creating another.
2026-10-11 01:58:37 +00:00
aiongg ae50689e27 GREP: styles with a pattern that can't compile are rejected, and imports warn
style.paragraph.create, style.paragraph.edit and type.para return the
compile error (bad GREP: ...) for a GREP style pattern that can't compile
and change nothing. Paragraph Style Options shows the error under the
pattern as it is typed, and on OK keeps the dialog open on the GREP Style
section with the command's error.

Opening an IDML or native document keeps such a style and reports a
warning naming the style (or paragraph) and the pattern; composition
keeps skipping it. Adds a lookbehind GREP style test.
2026-10-11 01:51:51 +00:00
aiongg 21a230e426 Merge pdf-effects-wrap: PDF: items with soft effects keep their text wrap 2026-10-11 01:47:49 +00:00
aiongg c014832572 Objects: group siblings inside a group; refuse mixed levels and spreads
Grouping objects that were not top-level items of the first object's
spread panicked (index out of bounds), through object.group, Group on a
content selection, and states.create. Objects nested at different levels
or on different spreads were silently left out of the new group.

Objects that share a spread and a parent group now group into a nested
group in that parent, keeping their stacking order and position. Objects
on different spreads or at different levels return an error and the
document is unchanged, as do objects inside a multi-state object. Group
is disabled in the menu for a selection it can't group; a call that
names its ids still runs whatever is selected.

Fixes #412
2026-10-11 01:46:19 +00:00
aiongg 814102ed35 Layout: items with soft effects keep their text wrap
PDF export replaces objects with soft effects by images of their
appearance. The image item carried no text wrap, so text recomposed
for the export ran under the object. Each rasterized object with a
wrap now stays in the export copy as a nonprinting stand-in that keeps
the wrap of the frame, its placed graphic and its grouped items, with
its text, form field, button and media removed.
2026-10-11 01:39:19 +00:00
aiongg 2d67dc8737 Merge #83 update: Em Box Height follows the font's typo box or cap height
# Conflicts:
#	crates/fonts/src/vertical.rs
2026-10-11 01:15:03 +00:00
aiongg 0b72584465 Layout: Em Box Height follows the font's typo box or cap height
A font's em box is its BASE em box; else it tops at the OS/2 typo
ascender when the typo ascender and descender span exactly one em; else
it is centred on half the cap height (OS/2 sCapHeight, else the H
glyph's top), 0.5 em + cap / 2 above the baseline; else 0.88 em. The Em
Box Height first baseline, vertical text and declared_em_box all use
this one em box; declared_em_box is None only for the 0.88 em fallback.
2026-10-11 01:12:08 +00:00
aiongg 16a17604df Merge #360 update: span columns in a one-column frame add no span space
# Conflicts:
#	crates/compose/src/lib.rs
2026-10-11 01:11:47 +00:00
aiongg 91a01a6774 Compose: span columns in a one-column frame add no span space 2026-10-11 01:09:28 +00:00
aiongg e3bf0e745c Merge #413: Fonts: a pan-CJK font's family name decides its font menu group 2026-10-11 01:02:11 +00:00
aiongg f9985611bc Merge #411: Undo: a command that runs another is one undo step 2026-10-11 01:02:10 +00:00
aiongg ef65f39b93 Integration: FontDb::system_fonts_cataloged builds on wasm (#394) 2026-10-11 00:53:49 +00:00
con3codeandClaude Opus 5.5 52ffb3c68a Fonts: a pan-CJK font's family name decides its font menu group
A font of a pan-CJK family lists the code pages of every language it
covers. With no `meta` languages and no CJK family name, the first group
in menu order won, so a Simplified Chinese face such as "… Noto Sans CJK
SC" was listed under Japanese.

When a font lists several CJK code pages, the region tag in its family
name (JP; SC, CN, GB; TC, HK, TW, MO, HC; KR — a whole word in capitals)
now decides, if the font lists that language. Fonts with one CJK code
page, or none, are grouped as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013phQ3ekq6uGBEWD6FjFYG2
2026-10-11 09:50:51 +09:00
aiongg 54b9a4d314 Merge mojikumi-base: CJK: custom mojikumi tables without a base set apply their rules
# Conflicts:
#	crates/engine/src/tests.rs
2026-10-11 00:47:10 +00:00
aiongg 11631cde12 CJK: custom mojikumi tables without a base set apply their rules 2026-10-11 00:42:47 +00:00
aiongg 12ea53f10e Merge #404: SVG: a font family named in any case finds the installed font 2026-10-11 00:40:54 +00:00
aiongg f1b4b0cf49 Merge #394 update: UI: CJK interface text from installed fonts, on the Latin baseline
# Conflicts:
#	crates/ui-egui/src/theme.rs
2026-10-11 00:35:02 +00:00
noah1400andClaude Opus 5.5 ad173006f7 Undo: a command that runs another is one undo step (#406)
Cut, Duplicate, Paste in Place, the Arrange commands and pasting text
run a second command inside themselves, and both recorded an undo
step: the second Undo did nothing. Only the outer command records now.
A command that fails after changing the document records its step
too; a script that stopped at a bad step left changes that could not
be undone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 02:34:43 +02:00
aiongg d666f0e312 Merge #393 update: UI: no crash on textures past the GPU limit
# Conflicts:
#	crates/ui-egui/src/canvas.rs
2026-10-11 00:32:52 +00:00
aiongg ee0b462446 Merge #309 update: Snap: smart guides beat the baseline grid; a box centres between two others 2026-10-11 00:32:23 +00:00
aiongg 0946f5931d Merge #305 update: Preserve explicit nullable text defaults when reopening documents
# Conflicts:
#	ROADMAP.md
2026-10-11 00:32:22 +00:00
aiongg ce144a614a Merge remote-tracking branch 'upstream/main' into next
# Conflicts:
#	ROADMAP.md
2026-10-11 00:30:35 +00:00
aiongg ecdb9b2dc2 Integration: rustfmt after merging #389-#392, indd 8 and 9 2026-10-10 23:52:24 +00:00
aiongg 9d717ea417 Merge cjk-run-baseline: CJK: smaller runs align to the line's em box centre
Conflicts:
- crates/fonts/src/fontdb.rs, vertical.rs: next's em cache
  ((top, bottom), declared) with FontFace::declared_em_box and the ICF
  cache/icf_box kept; the branch's base_em_box accessor dropped (same
  value). em_box's fallback chain takes the branch's let em form.
- crates/compose/src/lib.rs: next's cjk_icf_box and the branch's
  alignment_em_box, which reads declared_em_box.
- crates/compose/src/tests.rs: both tests. next applies character
  alignment only under the Japanese composers (5dc8383a), so the branch's
  smaller_cjk_run_aligns_to_the_line_em_box_centre runs under japanese();
  next's cjk_em_center_alignment_moves_small_characters measures centres
  on the alignment em box (declared, else 0.88/-0.12 em).
2026-10-10 23:49:04 +00:00
aiongg 778a270f48 Merge smallcap-tounicode: PDF: small caps and substituted figures keep their text
Conflicts:
- crates/pdf/src/text.rs run_text: the branch's two generated_text
  branches first, then #392's kashida branch (no text), then the cmap
  fallback for other inserted glyphs.
- crates/compose/src/lib.rs: next's kashida PlacedGlyph (with dx) gets
  generated_text: None.
- crates/compose/src/shape.rs hyphen_after: next's rendered_char/moji
  resets and generated_text = None.
- crates/compose/src/ruby.rs: next's ruby module (#363); the branch's
  edit to the old ruby set() has nothing to apply to.
- crates/pdf/src/tests.rs: tests from both.

Also, so the merge compiles: next's ruby (ruby.rs annotate) and kenten
(kenten.rs shape_mark) PlacedGlyph literals take generated_text: None;
they map back through the font like other inserted glyphs. Kanji page
numbers, composite-font note numbers and fallback-face label segments
go through shape_segment's replacement and list labels through
prepend_label, so they carry their generated text.
2026-10-10 23:47:37 +00:00
aiongg 8806a223fa Integration: shatai glyphs in right-to-left lines draw inside the line span (#392)
next's shatai path draws a slanted glyph on its own through tagged_run,
which opens a Span; inside #392's right-to-left line span that nested
marked content and krilla panicked ("can't start marked content twice")
in tagged exports. While a line span is open, the glyph is drawn with
run like the line's other runs. Test:
shatai_glyphs_in_right_to_left_lines_stay_in_the_line_span (panicked
before).
2026-10-10 23:46:28 +00:00
aiongg 93924a00b3 Merge pdf-rtl-text: PDF: right-to-left text extracts in reading order
No conflicts.
2026-10-10 23:45:02 +00:00
aiongg a386c73d82 Integration: PDF crop box is part of an asset's identity; clippings keep anchored graphics (#391)
Asset::same_file compares pdf_crop (#362) with type, page and bytes: one
PDF page shown with two crop boxes keeps two assets, so add_asset,
adopt_asset, insert_asset (IDML/INDD import) and the load/save merge
never point a placement at another crop. Test in
identical_files_share_one_asset.

The copy clipping (edit.rs clip_doc) keeps the assets used_assets finds
in it, so graphics anchored in copied text, graphic table cells (#379),
notes and media posters keep their files; it collected only graphics on
the copied items before. Test:
copied_text_frames_keep_the_graphics_anchored_in_their_text.
2026-10-10 23:44:15 +00:00
aiongg cfd57cb3ca Merge asset-dedupe: Assets: one asset per image, and saves leave out unused ones
Conflicts:
- crates/engine/src/cmd/{datamerge/fill.rs, file.rs, mathexpr.rs,
  media.rs, table.rs}: the branch's add_asset calls, with next's Asset
  fields (pdf_crop, pdf_box) through ..Default::default(); file.place
  keeps next's PdfCrop-aware asset (crop_pdf) and adds it with add_asset;
  the data merge graphic keeps next's wrap field.
- crates/format/src/lib.rs: load runs next's upgrade(doc, version), then
  merge_duplicate_assets (zip and legacy JSON); tests from both, with the
  round-trip test placing its asset (saves drop unused ones).
- crates/idml/src/import.rs graphic(): the branch's linked_assets reuse and
  insert_asset, with next's PDF page and PdfCrop on the asset and the
  graphic's text wrap (#389 integration) in the shared graphic closure.
  linked_assets is keyed by (path, page, crop), so placements of one PDF
  showing different pages or crop boxes keep separate assets.

Also, so the merge compiles: Asset/Graphic literals in the branch's tests
(crates/doc/src/assets.rs, format, engine links.rs) take next's pdf_crop,
pdf_box and wrap fields.
2026-10-10 23:41:30 +00:00
aiongg 27312c1cf9 Integration: feathers inherit from object styles; merge closes its functions (#390)
The merge of idml-feathers left overlay() in crates/idml/src/import.rs and
imports_and_round_trips_text_wrap_side_and_contour_type in tests.rs
without their closing braces (both sides added code at the same place);
this closes them.

Test: feathers_come_from_the_object_style_unless_its_category_turns_them_off
(gradient and directional feathers come from the style through
with_style; EnableGradientFeather="false" in
ObjectStyleObjectEffectsCategorySettings drops the style's gradient
feather; the item's own Applied="false" wins).
2026-10-10 23:38:21 +00:00
aiongg 15bcbae754 Merge idml-feathers: IDML: gradient and directional feathers import and export
Conflicts:
- crates/idml/src/import.rs, free functions: next's effect_flag/overlay
  (#389) and the branch's finite/gradient_feather_in both kept. The
  feather reads sit inside the TransparencySetting block, which next reads
  through with_style, so object style feathers are inherited and their
  EnableGradientFeather/EnableDirectionalFeather category flags apply.
- crates/idml/src/tests.rs: tests from both.
2026-10-10 23:37:23 +00:00
aiongg 75ce3f88e0 Integration: placed graphics take text wrap from their object style (#389)
A graphic element that names an AppliedObjectStyle reads its
TextWrapPreference through with_style, so mode, side, offsets and
ContourOption come from the style where the graphic sets none. Test:
text_wrap_side_and_contour_come_from_the_style_for_frames_and_placed_graphics.

Also: swatch_ref's doc comment sits on swatch_ref again.
2026-10-10 23:37:01 +00:00
aiongg 06baf887fb Merge idml-style-effects: IDML: frames take corners, effects and text wrap from their object style
Conflicts:
- crates/idml/src/import.rs, style chain helper: next's object_style_chain
  (trims BasedOn, ends with [None], cycle-safe) kept; the branch's
  style_chain dropped. with_style and attr_or_style use object_style_chain.
- import.rs corners: next's corner import over the object style chain kept
  (per-corner then all-corners at each level, InDesign default radius);
  the branch's second corner pass dropped, so corners are read once.
- import.rs text wrap: with_style(e, "TextWrapPreference") feeds next's
  shared text_wrap() reader (side, ContourOption, offsets) instead of the
  branch's inline TextWrap build.
- import.rs TextFramePreference: next's chain-aware text_frame_options
  with column rule colour kept; BaselineFrameGridOption read through
  with_style.
- crates/idml/src/tests.rs: test modules from both.
2026-10-10 23:37:01 +00:00
Brandon ThomasandClaude Opus 5.5 a9124a0517 Release prep: version 0.6.0; Linux riscv64 tar.gz in releases (#398)
- release.yml: new linux-riscv64 job (cross-compiled on ubuntu-24.04 against
  ports.ubuntu.com riscv64 libs, tar.gz only, CLI smoke-tested under QEMU),
  ported from GridCraft; the draft release job needs it, so SHA256SUMS covers it.
- packaging/linux/package.sh: CROSS_ARCH/CROSS_TARGET/CROSS_COMPILE/EMULATOR
  support, as in GridCraft.
- cargo xtask version set 0.6.0; README, hardware parity and ROADMAP log note
  the new platform.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
v0.6.0
2026-10-10 19:33:30 -04:00
con3codeandClaude Opus 5.5 70cfd2d4fa UI: installed CJK faces are read once, without waiting for the font scan
- install_fonts no longer waits for the system font catalog on the first
  frame: the built-in faces are installed at once, the scan runs in the
  background, and the installed CJK faces are added when it is done.
- The installed faces are read once and shared: changing the interface
  language reorders them without copying the font files into egui again.
- fonts: line_metrics no longer sits between feature's doc comment and
  feature.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013phQ3ekq6uGBEWD6FjFYG2
2026-10-11 08:30:39 +09:00
aiongg 6b3d7c4ba8 Integration: installed CJK UI faces are read once per process (#394)
install_fonts caches system_ui_fonts in a OnceLock; the face bytes are
leaked once and borrowed (Cow::Borrowed) by each FontData, so a language
change reorders the faces without re-reading font files or copying them.
SystemFont.bytes is a Cow<'static, [u8]>.

Also: line_metrics no longer sits between feature's doc comment and
feature (crates/fonts), and the canvas texture test's frame closure
drops an unneeded mut.
2026-10-10 23:30:09 +00:00
aiongg 2b96dffda1 PDF: right-to-left text extracts in reading order
Lines with right-to-left text are wrapped in a marked span whose
ActualText is the line's text in reading order, so viewers that order
text by position (Preview, PDFKit) no longer return it reversed.

A base letter and its marks (Hebrew points) map glyph by glyph when
each glyph stands for one of the cluster's characters, and are drawn in
text order, so ToUnicode-only extraction reads each letter once with
its points after it. Marks stay in their run, placed by glyph offsets
(compensated for skew), instead of starting runs of their own.
Kashidas inserted by justification carry no text.

Fixes #392.
2026-10-10 23:29:46 +00:00
aiongg fbfc4eecf9 Merge #394: CJK interface text from installed fonts, on the Latin baseline
Conflict: crates/ui-egui/src/theme.rs install_fonts: the PR's
system_ui_fonts/add_system_fallbacks replace next's #126 system-font loop
(fallback_for per CJK sample char into system-ui-{id} faces when
CRAFT_FONTS is empty), so installed faces are not loaded twice. No #126
helper in theme.rs is left unused; FontDb::fallback_for stays (compose,
images use it).
2026-10-10 23:29:09 +00:00
sanyamsingh001andCodex 21fa11780c docs: avoid unrelated roadmap changes
Co-Authored-By: Codex <codex@openai.com>
2026-10-11 09:28:45 +10:00
aiongg daf1a0ccb3 Assets: one asset per image, and saves leave out unused ones
Placing a file that the document already holds reuses its asset (same
bytes, type and PDF page), in file.place, place.load, media and poster
placement, graphic table cells, math, data merge image fields, IDML
import (a linked file is read once) and paste/duplicate between
documents (which also maps ids that collide in the target).

Saving merges identical assets into the first and leaves out assets
nothing references; the open document keeps them for undo. Opening a
file saved with one copy per placement shares the identical bytes as
they are read and merges the assets. Package and Copy Links write only
used files, and links.list lists only used assets.

Refs #391
2026-10-10 23:28:24 +00:00
aiongg ea69df5bff Integration: canvas edits patch only a full-resolution texture (#393)
patch_texture writes full-resolution dirty rects with set_partial; when
upload() has shrunk the canvas texture to max_texture_side (a viewport
wider than the GPU limit), the edit takes a full render instead of a
partial write past the texture's bounds (a wgpu validation error). Test:
edits_patch_the_canvas_only_at_full_resolution.

The content ghost proxy goes through widgets::fit_texture (capped at 4096)
instead of skipping graphics larger than the limit.
2026-10-10 23:28:09 +00:00
con3codeandClaude Opus 5.5 cc836fe4df UI: an edit repaints a sampled-down canvas texture whole
patch_texture computed the damaged region in view pixels and wrote it
with set_partial into the canvas texture upload() had sampled down to
the GPU limit: a viewport wider than max_texture_side put the region in
the wrong place or outside the texture (a wgpu validation error on the
first edit). Such a texture is now rendered whole.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013phQ3ekq6uGBEWD6FjFYG2
2026-10-11 08:25:43 +09:00
aiongg 9ba7e9e8c7 Merge #393: no crash on textures past the GPU limit
No conflicts.
2026-10-10 23:25:09 +00:00
aiongg 0c1d021dfd Integration: macOS menu bar rebuilds when Show CJK Features changes (#397, #336)
NativeMenu keys its rebuild on (language, cjk_features(app)), so the
CJK commands that menus::shown filters appear or disappear at once.
2026-10-10 23:24:57 +00:00
aiongg 3667fcc3a3 Merge #397: macOS menu bar follows the interface language at once
No conflicts.
2026-10-10 23:24:36 +00:00
aiongg 62fe6eb23b Merge #396: the welcome screen's Discord button clears the text beside it
No conflicts.
2026-10-10 23:24:27 +00:00
aiongg 153fa60054 Merge #388: Show the Pencil stroke while drawing
Conflict: crates/ui-egui/src/canvas.rs draw_tool_overlays: the PR's
Overlay::Path arm (draw_path_overlay) and next's Overlay::ContentGhost
arm both kept; draw_path_overlay sits before draw_content_ghost.
2026-10-10 23:23:48 +00:00