A font with no readable OS/2 table doesn't say what its licence allows,
and reporting fsType 0 made it look installable. FontFace::fs_type() now
returns None for it, and font.list reports fsType and the five flags as
null. restricted_licence() and bitmap_only() still treat it as
unrestricted, so export behaviour doesn't change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ApvpyStzzHbKyDBNxpzn2Y
file.openBytes used the name it was given as the document's title as is. The
IDML path strips .idml/.indd/.indt, but a native document opened as
"Brochure.designcraft" kept the extension, and everything that adds it back
doubled it: Save in the browser downloaded Brochure.designcraft.designcraft,
Save As suggested that name, and the File Name variable showed it. The app's
own drop and open paths strip the extension before calling, so only hosts and
scripts that pass a file name hit it.
The title now drops one trailing .designcraft (any case). Other names are
unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ApvpyStzzHbKyDBNxpzn2Y
font.list now gives, for the face that sets the text, its raw OS/2 fsType
and what the bits mean: restrictedLicence, bitmapOnly, noSubsetting,
editable and previewPrint (null when the face is missing). A host that
makes print PDFs can then refuse a face whose licence doesn't allow the
export, including system fonts and the bundled fonts, without reading the
font files itself. PDF export subsets every font, so a caller needs
noSubsetting as well as the restricted and bitmap-only bits.
FontFace gains fs_type(); restricted_licence() and bitmap_only() read it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ApvpyStzzHbKyDBNxpzn2Y
Found while testing crates/engine/src/math.rs:909 (to_svg, the `esc` closure used for each <text> glyph)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Found while testing crates/engine/src/cmd/mathexpr.rs:~50 (the math.svg query) vs insert at ~64
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Found while testing crates/engine/src/script.rs:30-47 (parse: `t.lines().enumerate()` runs over the trimmed text)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Go to Row's OK moved the view only when the row's page was not the page
at the center of the view, and then centered that page. When zoomed in,
a row on the page in view stayed off screen, and a row on another page
could stay off screen too.
The view now scrolls so the row is in the middle of the view from top to
bottom, at the same zoom, on the page in view or another. It scrolls
sideways only when no part of the row is in view across.
table.goToRow also returns the spread that shows the row, a document
or parent spread, and the row's bounds on that spread. A composed table fragment lists its rows with their top and
bottom, so a row inside cells merged across several rows is bounded by
its own height. A row in an anchored text frame is found where the
host story places the frame.
table.select and table.goToRow put the caret at the range's first grid
position, which has no cell of its own when a merged cell from the row
above covers it, so the caret was not drawn. The caret now goes in the
cell that covers that position.
table.goToRow took the page from the frame's center, so a row in a
frame that spans two pages of a spread could name the other page, and
the view moved there. It now takes the page under the row's first cell.
table.get takes cells: false to leave out the cells, and the Go to Row
dialog uses it, so opening the dialog on a large table does not copy
every cell's text.
table.goToRow and table.select naming a table in another story kept
the previous caret's frame, so frame commands that follow acted on the
other story's frame. The caret's frame is now kept only within the same
story, and Go to Row puts it in the frame that shows the row.
The Table menu order test lists Go to Row after Distribute Columns
Evenly.
Found while testing crates/engine/src/cmd/xml.rs:~215-245 (parse: the Start/Text/End depth handling; text at depth >= 4 matches no arm)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
crates/ui-egui/src/dialogs.rs: kept the Enter-stays-local fix
crates/ui-egui/src/package_dialog.rs: kept the summary wording and the fix; took the PR's pdf option value
crates/ui-egui/src/i18n/*.rs: kept the reworded keys and the PR's PDF Preset rows
Also (the PR's own CI failure): package.rs calls check_pdf_options and pdf_report on wasm, so those two re-exports are no longer wasm-gated (only pdf_export is).
crates/idml/src/tests.rs: kept the PR's TOC tests, dropped the duplicate copy from #1249
crates/engine/src/tests/idml.rs: main's createBookmarks plus the PR's right-indent separator
crates/ui-egui/src/dialogs.rs: main's labelled_by fields plus the PR's special-character menu
crates/ui-egui/src/i18n/*.rs: kept both added rows
crates/engine/src/cmd/table.rs: kept both exports.
crates/engine/src/cmd/table/structure.rs: main's strict size validation with #1676's limit constants and table style.
crates/ui-egui/src/dialogs.rs: kept Insert Pages dialog and #1676's Insert Table dialog; dialog title and width from #1676.
crates/ui-egui/src/dialogs/tests.rs: kept both sides' tests.