Commit Graph
2702 Commits
Author SHA1 Message Date
Sean HammondandClaude Opus 5.5 0635dea065 Text wrap: small single-character frames (tombstones) are set beside text wrap
An article's closing tombstone - a one-character text frame, here a 7.6 pt
Noto Emoji symbol in a 10.5 pt box - was overset (red +, nothing drawn)
whenever its spread had a text-wrap object anywhere, while InDesign sets it.

Two causes in the wrap code:
- Every text frame took every wrap object on its spread as an exclusion,
  whether or not the object reached the frame. Now only objects that
  overlap the frame wrap its text.
- free_slot skips gaps narrower than 1.5 em of the paragraph's size
  (slivers beside a wrapped object), but applied that to the whole column
  too when nothing cut it: with a 14 pt paragraph style, no line could go
  in a frame narrower than 21 pt. The minimum now only applies to gaps a
  wrap object cut; a band no object reaches gets the whole column, however
  narrow.

On the document that showed it (an InDesign 2026 IDML with 12 tombstones and
two unrelated wrap objects on the spread), the 12 tombstone stories are set
and no other story's layout changes (54 -> 42 overset stories, all of the
difference the tombstones).

Tests: small_single_character_frame_sets_beside_unrelated_text_wrap and
narrow_frame_sets_lines_no_wrap_object_reaches fail before (overset) and
pass after.

Probably also #476 (Wingdings bullets overset in 20 x 21 pt frames).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CgGsJkVe5GYG9qK6VFdECa
2026-10-12 06:16:04 +00:00
Fabio LussiandClaude Opus 5.5 fb90a508b1 docs: drop the docs workflows until the checker is on artcraft-services main
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 08:09:21 +02:00
MarekSpodBiedry 2c2e3d73c7 Drop the arithmetic-only app bar test; the test window test covers it (#481) 2026-10-12 08:06:16 +02:00
MarekSpodBiedry f8f8eb619f Test the app bar scroll bar at 115% scale in the test window (#481) 2026-10-12 08:05:01 +02:00
MarekSpodBiedry 11b9a0f104 Export explicit SameParaStyleSpacing Ignore so it round-trips (#449) 2026-10-12 08:04:46 +02:00
aiongg e5c5f043ee Integration: format 2026-10-12 05:56:41 +00:00
aiongg 5f6ee139da Integration: anchored objects wrap through next's wrap_obstacles (#557 × next's wrap sides and contours)
#557 built an anchored object's exclusion as its offset bounding box; next's Exclusion also has a side and a contour, built by wrap_obstacles for page items. wrap::obstacles keeps the object and its parent → spread transform, and wrap::exclusions runs wrap_obstacles with it, so anchored objects get sides (spine sides by page), contours (Same As Clipping from the clip), custom boundaries, Jump Object and the wrap of a graphic inside, each tagged with the anchor byte (after). Without this the merge doesn't compile. Test: anchored_object_wraps_with_its_contour_and_side.
2026-10-12 05:56:35 +00:00
aiongg 9a95cee172 Merge anchored-wrap: Text wrap: anchored objects wrap text (#557)
Conflict: ROADMAP.md: both progress lines
Conflict: docs/target-app-parity.md: next's header, anchored objects wrapping text added to its change list
Conflict: docs/typography-parity.md: next's header (dated 2026-10-12) with #557's change added; Text wrap row: next's text and caveat, plus "on page items and anchored objects"
Conflict: crates/compose/src/lib.rs: next's Exclusion (side, contour) with #557's after field (Exclusion::wraps_line; next's constructors and the tests' helper set None); next's contour_path and wrap_obstacles in frame_specs; next's line loop (carry, grid, wrap_slot) with the line's start byte passed to wrap_slot; wrap_slot, free_slots and estimate_slots take line_start and skip exclusions that don't wrap the line (Jump Object test and in-band edges included); #557's re-break trigger stays in the line loop
Conflict: crates/compose/src/cache.rs: next's ComposeOptions (section_marker) with #557's neighbour compositions
Conflict: crates/compose/src/tests.rs: both test blocks
Conflict: crates/render/src/damage.rs: #557's test before next's patched_diff helper
2026-10-12 05:54:58 +00:00
aiongg 6e9517b053 Text wrap: anchored objects wrap text (#557)
An anchored object with text wrap pushes aside the text of other stories
whose frames it overlaps on its spread, and the lines of its own story
after the line holding its anchor (custom and above-line objects). Its own
story is composed again with the objects where the previous pass placed
them until they settle, at most four more times. The composition cache
keys a story wrapped by other stories' anchored objects on their
signatures, and canvas damage repaints the stories they wrap.
2026-10-12 05:51:56 +00:00
aiongg 62520485e8 Integration: format 2026-10-12 05:48:15 +00:00
aiongg b4e2e553e5 Merge #408: Align panel: add objdistribute-* icons, reuse upstream objalign-*
Conflict: crates/ui-egui/src/icons.rs: test module keeps both (next's arrow fill test, #408's distribute icon test)
2026-10-12 05:48:01 +00:00
aiongg 5284bca791 Integration: the Color Picker from the Fill/Stroke box follows Formatting Affects Text (#552 × next's color_target)
#552 opens the picker without the "text" field and reads the selected text's colour itself. On next the proxy's swatches already come from color_target, which follows colors_affect_text (selected text, or text frames with Formatting Affects Text on), so the special case goes and the dialog gets "text": colors_affect_text(app) as the Swatches and Color panels' pickers do. Without it, OK coloured the frame instead of its text. Test: the_color_picker_from_the_fill_box_follows_formatting_affects_text; #552's test shares its double-click helper.
2026-10-12 05:46:45 +00:00
aiongg 048baca521 Merge #552: Double-clicking the Fill or Stroke box opens the Color Picker
Conflict: ROADMAP.md: both progress lines
2026-10-12 05:41:55 +00:00
aiongg 64b834f2e0 Merge anchored-settings: IDML: anchored objects take unset anchor settings from their object style (#555)
Conflict: crates/idml/src/import.rs: next's with_style kept after attr_or_style (#555 has no counterpart there); the anchored arm merged as next's header (TextFrame, no has_text guard) with #555's body
2026-10-12 05:41:43 +00:00
aiongg 3e7cca3a0d Integration: text wrap Same As Clipping follows the graphic's clipping path (#450 × #384)
#384's contour wrap followed the frame's path for Same As Clipping, which was all a graphic could clip to; #450 gives graphics clipping paths. contour_path takes the clip region (Graphic::clip_region) when the graphic has one. Test: a triangle clip widening downwards, Same As Clipping, left side: lines beside the narrow top run further in than those at the base.
2026-10-12 05:40:04 +00:00
aiongg 6c1d5b75db Integration: Graphic and Asset literals in tests name the fields both sides added (#450 × next)
#450 adds Graphic.clip; next added Graphic.wrap and Asset.pdf_box/pdf_crop. #450's tests in doc and render lack next's fields and next's tools test lacks clip; the tests didn't compile.
2026-10-12 05:38:04 +00:00
aiongg af389f9a0b Merge clipping-paths: Images: clipping paths from IDML clip the image on screen and in PDF
Conflict: ROADMAP.md: both progress lines
Conflict: docs/gaps.md: next's header, clipping paths added to its change list
Conflict: docs/target-app-parity.md: next's header, clipping paths added to its change list
Conflict: crates/doc/src/item.rs: both Graphic methods (next's shown_bounds, the branch's clip_region)
Conflict: crates/idml/src/names.rs: both imports (ClippingKind, ContourType)
Conflict: crates/idml/src/export.rs: both pushes, TextWrapPreference first, then the clipping settings
Conflict: crates/idml/src/import.rs: both lets (next's wrap, the branch's clip)
Conflict: crates/engine/src/cmd/file.rs: next's size and transform, plus clip: None
Conflict: crates/engine/src/cmd/datamerge/fill.rs: next's Graphic with wrap, plus clip: None
Conflict: crates/engine/src/cmd/mathexpr.rs: next's Graphic with wrap, plus clip: None
Conflict: crates/pdf/src/tests.rs: both tests
2026-10-12 05:37:19 +00:00
aiongg b7b0001cce Integration: IDML AppliedFont keeps a family's spaces through font_family_in (#558 × next's $ID/ handling)
#558 keeps an AppliedFont family exactly as written apart from line breaks; next routes the value through names::font_family_in (for InDesign's $ID/ prefix), which trimmed it. font_family_in strips CR/LF and the $ID/ prefix and keeps spaces; a blank or $ID/-only value is still no font. #558's applied_font_keeps_spaces_and_font_style_nothing_inherits fails without this.
2026-10-12 05:36:23 +00:00
aiongg 8f60e6349b Integration: idml tests.rs: restore the closing brace of hostile_custom_wrap_boundary_is_dropped
The keep-both resolution of tests.rs in the #558 merge (0ff65578) put #558's test after next's last test without its closing brace, which git had shared between the two sides.
2026-10-12 05:36:23 +00:00
aiongg 0ff65578b0 Merge idml-font-names: IDML: font family names keep their spaces; FontStyle Nothing inherits (#558)
Conflict: ROADMAP.md: both progress lines
Conflict: crates/fonts/src/fontdb.rs: next's style_traits/traits_of/linked_style, canonical_family lookup, family_kind and postscript_face; #558's alternate_names (as written, then trimmed) now chains plain_family ($ID/ prefix and format suffix) and is the fallback in style_traits, face (canonical_family, then substitute_family) and has_family
Conflict: crates/idml/src/import.rs: #558's CR/LF-only stripping (next's f.trim() dropped), next's composite_names lookup (by the trimmed name) and names::font_family_in; #558's FontStyle Nothing → unset
Conflict: crates/idml/src/tests.rs: both tests
2026-10-12 05:35:36 +00:00
aiongg 43a4e70658 Merge section-marker: Sections: the section marker shows the section's marker text (#556)
Conflict: ROADMAP.md: both progress lines (next's, then #556's)
Conflict: crates/compose/src/shape.rs: #556's empty-marker zero-width glyph; next's digit mapping, styles.at(i)/styles and sub.upright() in both arms
2026-10-12 05:34:13 +00:00
aiongg ab231cde62 IDML: a left-aligned anchored object's X offset reads in the layout's direction (#555) 2026-10-12 05:32:59 +00:00
aiongg e111bb74f7 Images: declare a graphic's clipping path beside its transform 2026-10-12 05:32:11 +00:00
aiongg 8125f2490b Images: clipping paths from IDML clip the image on screen and in PDF
A placed graphic keeps its clipping path (Detect Edges, Alpha Channel,
Photoshop Path or User-Modified Path) in graphic space, with the
options IDML carries. IDML import reads ClippingPathSettings and its
saved ClippingPathGeometry (anchors capped, non-finite subpaths
dropped); export writes them back. The canvas and PDF export clip the
image to the path inside the frame clip; an inverted path shows the
image outside it. Without saved geometry nothing changes.

object.clippingPathOptions reports a graphic's clipping path, inverts
it or removes it (Object > Clipping Path > None).

Fixes #450.
2026-10-12 05:31:03 +00:00
aiongg 25c215faf9 IDML: anchored objects take unset anchor settings from their object style (#555) 2026-10-12 05:20:12 +00:00
aiongg 9061475831 IDML: font family names keep their spaces; FontStyle Nothing inherits (#558) 2026-10-12 05:14:04 +00:00
Fabio LussiandClaude Opus 5.5 0638d6f944 docs: pin the docs checker to a commit and its SHA-256
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 07:13:50 +02:00
aiongg 406f1b3d26 Sections: the section marker shows the section's marker text (#556) 2026-10-12 05:09:40 +00:00
aiongg dfdf2c3b76 Integration: ROADMAP: one progress line each for #520 and #521
Upstream main's squashed #520 and #521 add the same progress lines next already had from the PR merges; the main sync auto-merged them in a second time. The copies from main are dropped.
2026-10-12 04:27:37 +00:00
aiongg b1804440d1 Merge #366 (update): Text: input method (IME) composition in the Type tool
#366 with #84's review fixes merged in: keyboard_pane is app.pane == app.focus_pane (the second window too), and the IME line in the parity doc.

Conflict: crates/ui-egui/src/canvas.rs: next's guard (menu_open, text_edit_focused, keyboard_pane)
2026-10-12 04:27:24 +00:00
aiongg fa3a184fad Merge #81 (update): Text: kerning survives a colour change (#29)
#81 with #84's review fixes merged in; tree unchanged against next.

Conflict: crates/idml/src/tests.rs: next's side (#81 carries #83's tests.rs through #84, already merged in 9196a164)
2026-10-12 04:27:05 +00:00
aiongg 6c52cdbc10 Integration: cs/ru/uk Swatches hint for objects or text (#84 × cs/ru/uk catalogs)
#84 renames the Swatches hint key to "Select an object or text to color its fill or stroke." and replaced the old key in uk.rs, where next already had the new key: the Ukrainian catalog had it twice, so #84's line is dropped. The Czech and Russian catalogs carried the old key, now unknown; they get the new key (our own translation, extended from the existing entry).
2026-10-12 04:26:43 +00:00
vxkj1211 957676492a Align panel: add objdistribute-* icons, reuse upstream objalign-* 2026-10-12 12:25:16 +08:00
aiongg d30cefe166 Integration: renaming a swatch reaches endnote text (#84 × #416)
#84's Add to Swatches renamed the colour in footnotes and endnotes through its own helpers; next's Document::rename_swatch_refs (#416), which add_to_swatches calls after the merge, covered footnotes but not endnotes. rename_swatch_refs now walks each story's endnotes too, and #84's test checks an endnote.
2026-10-12 04:23:54 +00:00
aiongg 70fe825045 Integration: autoflow page-break test names its command (#266 × #84)
#84 gives autoflow the id of the command that autoflows, for its errors; #266's odd/even page-break test called autoflow with the old three arguments. The test passes "file.place".
2026-10-12 04:20:54 +00:00
aiongg 89abf6b6c9 Merge #84 (update): Text editing, snapping and text threading (#23)
Review fixes for text editing, paste and threading (fix84-text,
fix84-thread), the Italian/Japanese/Portuguese/Ukrainian Swatches hint
and #83's update merged into the PR branch.

Conflict: ROADMAP.md: header combines #84's threading change with next's 2026-10-11 changes; progress lines and change-log rows both (#84's 2026-10-12 first); stage line #84's (alpha ~5–7 h away)
Conflict: docs/gaps.md: #84's header text plus next's kerning/fonts/print changes
Conflict: docs/roadmap.md: next's M1 row (#186 done), #84's M2 row
Conflict: crates/engine/src/cmd/style.rs: next's side; add_to_swatches calls next's Document::rename_swatch_refs, #84's rename_in_story/rename_in dropped (next's covers text, tables, cells, notes and items); #84's test kept
Conflict: crates/idml/src/tests.rs: next's side (#84 carries #83's tests.rs, already merged in 9196a164)
Conflict: crates/tools/src/select.rs: overlays keeps next's content-move ghosts and live corners, plus #84's snapped loaded-cursor drag frame; a Place click without a drag shows nothing
Conflict: crates/ui-egui/src/i18n/it.rs: next's side (the Swatches hint entry is already further down)
2026-10-12 04:20:34 +00:00
aiongg 9196a1643f Merge #83 (update): Layout: first baselines, Jump Object wrap, drop caps, IDML defaults
Conflict: crates/format/src/lib.rs: next's side (upgrade, merge_duplicate_assets, then mark_differing_margins_local) in both loaders
Conflict: docs/target-app-parity.md: next's RTL and Interface Language lines, plus #83's "IDML Kashidas"
2026-10-12 04:17:58 +00:00
aiongg d2a6dd39a2 Integration: character fill swatch errors go through known_swatch (#403 × #520)
#403 added validate_char_fill with its own message; #520 added known_swatch for object fills and strokes, which also suggests the intended name. validate_char_fill now calls known_swatch with key "fill", so one error path covers both. #403's tests still pass (the message names the fill, swatch.create and the returned name).
2026-10-12 04:17:15 +00:00
aiongg 8f1c60e4fc Merge upstream main 835edae6
Brings #514 (MCP request replay), #523 final (already in next), #403
(character fill must name a swatch), #520 and #521 finals (already in
next as their PR heads).

Conflict: crates/engine/src/cmd/object.rs: next's side throughout (transform.move doc with content?, object.fill with tint alone from #525, move_content, reorder/content_move/group/tint_alone test modules); upstream's copy_ids_tests already in next
Conflict: crates/engine/src/cmd/text.rs: both; #403's validate_char_fill after next's ruby_cmd
Conflict: crates/pdf/src/export.rs: next's side (item/item_guarded cycle guard, frame_objects; upstream's anchored loop dropped as in d11ccad3)
Conflict: crates/render/src/lib.rs: next's side (drawing_items, draw_item/draw_item_inner)
2026-10-12 04:15:40 +00:00
aiongg 7eed1dffe1 Merge #84 into feat/ime 2026-10-12 04:12:45 +00:00
aiongg a993f2ea37 Merge #84 into fix/29-kerning-across-runs 2026-10-12 04:12:25 +00:00
aiongg dd044dd8b1 Merge review fixes: threading 2026-10-12 04:10:06 +00:00
aiongg 237bfb7a2c Merge review fixes: text editing and paste 2026-10-12 04:10:06 +00:00
aiongg 6f55df4370 Canvas: a press right after a drag is not a double click 2026-10-12 04:07:47 +00:00
aiongg 9964025ffb Swatches: Add to Swatches renames the colour in text, tables and notes 2026-10-12 04:04:07 +00:00
aiongg 9d3581929a Threading: progress docs for threading by hand
The alpha gate's threading row and gap 0 shrink to the Primary Text
Frame page fixes (#165). New gaps: autoflow onto the existing following
pages, and threading into a grouped frame with the loaded text cursor.
2026-10-12 04:02:35 +00:00
aiongg 7adc0be491 Threading: Alt-click moves the loaded cursor on only to the frame the click added
The click records the frame it expects to join (the clicked frame, or a
new one in place of the old neighbour). The load moves on only when the
document has that frame there, so a failed thread or an undo leaves the
cursor on the frame it was loaded from; an undo after moving on goes
back to it.
2026-10-12 04:01:20 +00:00
aiongg 52b58c0519 Text: Bold and Italic that change nothing add no undo step 2026-10-12 04:01:12 +00:00
aiongg d163837781 Text: text.selectAt needs a point 2026-10-12 04:00:19 +00:00
aiongg 6a0f0cf386 Text: a quadruple click selects the paragraph with its return 2026-10-12 03:59:53 +00:00