* 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
A group's transform can move a frame onto another page; the page lookup
used the frame's bounds without its parents' transforms, so the grid took
the wrong page's top margin.
The setting was imported and editable but never read: the composer, the
canvas grid and baseline snapping measured the grid from the page top.
BaselineGrid::origin gives the first line on a page (start, plus the
page's top margin for Top Margin), and all three use it. The composition
cache tracks the setting and the pages' top margins.
Also adds a left-to-right facing-pages guard test for mirrored margins
and the right parent page's guides and running head.
The first-line indent was added to the left indent whatever the paragraph's
direction, so a right-to-left paragraph's first line moved the wrong way. With
the hanging indent a numbered list uses — right indent 10 mm, first line
−10 mm — the first line went 10 mm outside the frame on the left while the
wrapped lines sat where it should have been.
It is the paragraph's start-side indent, which is the right one in a
right-to-left paragraph; the drop-cap case beside it already made that
distinction.
Measured on a 200 pt column with that hanging indent:
first line right edge 200 (the frame's edge, as InDesign sets it)
wrapped right edge 171.65 (10 mm in)
every line left edge >= 0 (nothing outside the frame)
and the same paragraph left to right is unchanged, first line at 0 and wrapped
lines 10 mm in.
The test checks both directions; the right-to-left half fails without the
change. 359 composition tests pass unchanged.
The points left out are recorded as story bytes, so the nested line styles
prepass (which indexes glyphs differently) leaves them out too, and a
style still covers exactly the lines it is set on. Their re-lays have a
bound of their own: each leaves out one more point of the paragraph, and
the keep options' budget no longer stops them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With Hyphenate Across Column off, a paragraph whose line ending at an
automatic hyphenation point would end a column or frame is re-laid
without that point, so the word moves on whole, as InDesign does. The
points left out are kept per paragraph across re-lays and cleared when an
earlier paragraph is re-laid. On by default, as in InDesign.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The emergency break inside a word wider than the measure could fall
between glyphs of one source character: an automatic page number wider
than its frame came out as "13" over "4". Glyphs sharing a cluster (the
generated digits of a page number, multi-glyph clusters) now stay together
and the number hangs out of its frame, as in InDesign.
Graphic literals (cli perf, doc assets/item, engine datamerge/export/file/links/mathexpr/media/table/sample, epub, format, pdf, pptx, render, tools, ui-egui properties, and tests): name the branch's clip and wrap (#561, #381) and the PR's fill.
crates/doc/src/item.rs: Graphic keeps wrap and gains fill.
crates/idml/src/import.rs: read the image swatch, then the branch's styled FrameFittingOption lookup; the graphic keeps its wrap.
crates/idml/src/tests/assets.rs: keep both new tests.
crates/render/src/lib.rs: keep #362's crop-box sizing of placed PDFs and colour the resulting pixmap.
crates/render/tests/colorize.rs, crates/epub/tests/grouped_reading_order.rs, crates/compose/src/tests.rs: literals name the branch's Asset and Graphic fields.
crates/pdf/src/export.rs: the soft mask interpolates by the standard's raster mode (the branch has no per-exporter interpolate switch).
docs/gaps.md, docs/target-app-parity.md: status lines list both sides' changes; gap text keeps the clipping-path items and adds the image swatch.
Past the estimated line slots the breaker assumes the whole column; the
rebreak check compares against that fallback too, so lines beside a wrap
object stay inside their segments.
(cherry picked from commit 94a06ed881)
Conflicts:
- crates/compose/src/shape.rs: typed figures and page-number markers both go through #1012's digit_mode; the batch's inline digits block and its second mapping of the marker text are gone.
- crates/compose/src/lib.rs: the list label keeps the batch's label_chars and prepend_label; it takes the Digits of the paragraph's first run unless the number's character style sets its own.
- crates/compose/src/tests.rs: kept page_numbers_take_the_digits_option and added #1012's test.
- crates/ui-egui/src/i18n.rs: kept the batch's French strings and added the Digits: row.
- crates/ui-egui/src/panels/properties.rs: the always-shown Digits row is followed by the batch's two-column Size, Kerning, Baseline, Leading and Tracking layout.
Conflicts:
- docs/target-app-parity.md: kept the batch's rows and added Greek to the hyphenation list.
- docs/typography-parity.md: kept the batch's Justification and Hyphenation rows and added Greek (hyph-el-monoton).
Greek text set unhyphenated however narrow the column: `Lang::for_language`
resolves a language through `hypher::Lang::from_iso`, which answers only for a
language whose patterns were compiled in, and `greek` was not among the features
the compose crate asks for. So `for_language("Greek")` was None and every Greek
word stayed whole.
The feature is asked for now. Nothing else was needed: the lookup is already by
ISO code, so "Greek", "Greek: Greece", "el" and "el-GR" all resolve, and
ανθρωπος breaks αν-θρω-πος as hyph-el gives it.
The patterns are `hyph-el-monoton.tex` 5.0 from hyph-utf8, Copyright (C)
2008-2011 Dimitrios Filippou, available under the LPPL or MIT and taken here
under MIT; NOTICE carries the licence, as it does for the other languages. The
published `hypher` crate ships compiled tries rather than the pattern files, so
that came from the file in hyph-utf8 rather than from the dependency.
They are the **monotonic** patterns, which is what `hypher` maps `el` to, so
polytonic text hyphenates by them too. Written into the module's documentation
rather than left to be discovered.
`gaps.md` 13, `target-app-parity.md` and `typography-parity.md` each listed the
four languages that hyphenate; they list five.
Only these two dialogs read bare numbers in the ruler unit; other dialogs keep their meaning.
Apply to: this page, both pages of the spread, or all pages. Parent edits default to the whole parent spread.
Replace unchecked indexing in inherited_guides and marginsAndColumns with get().
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWRYQ5eieuUrtxhdbh6goq
Conflicts:
- crates/compose/src/lib.rs: kept main's line placement (line_metrics with first
baseline tops, baseline grid snap) and this branch's leading model and Aki Below
advance. The Hyphenation Zone check uses Composer::single_line(), so the Japanese
single-line composer gets the zone too.
- crates/idml/src/tests.rs: kept both tests at the conflict (composer kinds, text
stroke alignment).
Also resolved:
- crates/idml/src/import.rs: removed the package scan for a Japanese composer and the
drop of [No paragraph style]'s leading model; the import keeps the file's leading
model and the composer kind, and compose applies the model per paragraph.
- crates/idml/src/tests.rs: the default-leading-model test lays out the document and
checks Roman spacing under the non-Japanese composers and the Aki Below spacing
under the Japanese ones; a new test round-trips a Japanese composer document.
A story that ends with a paragraph return has an empty last paragraph. When
it didn't fit, DesignCraft marked the story overset at the end of its text
(Preflight: "Overset text: 0 characters"; the out port turned red).
InDesign doesn't: Montilla Design's Flex Layout file has a caption ending
with a return, fitted to its three lines, and InDesign reports no errors.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A drop cap came out the same size whatever its point size: the fit
(drop + body cap height) / (the cap's own cap height) cancels the cap's
size, since its own cap height grows with it. InDesign fits the cap as if
it were set at the body text's size and scales that by the cap's size over
the body's, keeping its baseline: a larger cap rises above the first line,
a smaller one falls short of it. Measured against an InDesign capture
(Palatino, 14 pt body, 18 pt italic T, 2 lines): cap height 2.04x the line
gap there, 2.03x predicted.
The cap's box (selection highlight, caret) now reaches the top of a cap
that rises above its line; selected glyphs are drawn inverted, so the part
outside the box would vanish. A one-line cap still keeps its own size
when that is smaller.
Test: drop_cap_scales_with_its_point_size (a 15 pt cap over 10 pt text is
1.5x the fitted height on the same baseline, 7.5 pt is 0.75x, the body
lines don't move, the box covers the cap). Before the fix the 15 pt cap
was 30.7 pt, the same as at 10 pt; with it, 46.05 pt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CgGsJkVe5GYG9qK6VFdECa
Add multi-click text selection, pending caret formatting and clipboard support, text-aware colour controls, guide/grid snapping, and frame threading with loaded-port interactions.
Include the layout, drop-cap and IDML updates carried from #83, with safeguards for generated and linked stories, external text references, local IDs, locked frames and atomic colour edits.
Fixes#23.
Co-authored-by: Sean Hammond <sean.hammond@und.edu>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Start options were skipped for a paragraph at the top of a frame. That is
right for Next Page, Next Frame and Next Column (there is nothing to break
away from), but a Next Odd Page paragraph that lands at the top of an even
page stayed there, as did Next Even Page at the top of an odd page, and the
same went for odd and even page break characters. A part or chapter opener
whose previous section ended exactly at the bottom of an odd page therefore
opened on a left-hand page.
Cursor::start_at_top now moves such a paragraph to the next page of the
asked parity, for paragraphs, tables and break characters alike. Other
start options at the top of a frame are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>