The shaper lets one call grow to 256 glyphs per input character, as an
embedded font's substitutions decide, and every glyph was then copied out.
Items longer than 1 KiB are now shaped in pieces (cut at a space where one
is near, never before a combining mark or after a joiner), each with the
rest of the paragraph as context and the item's script, and a piece that
expands past 32 glyphs per character falls back to one glyph per character
from the cmap.
* Animations: index morph matching and timeline lookups by shape
Morph pairing searched every shape of the next slide for each shape of the
current one, four times over, rebuilding shape text inside each comparison.
Timeline state looked up a shape's effects, paragraph owner and base colour
by scanning every effect, group and colour on the slide, once per shape and
paragraph drawn. Both are now indexed once, keeping the same match order.
* Animations: drop wall-clock bounds from the large morph and paragraph tests
On a loaded runner a ten-second bound can fail after every functional
assertion passed. The inputs stay large enough that a quadratic regression
hangs the test instead.
Found while testing crates/engine/src/cmd/file.rs:489 (save, with save_bytes at :341-349 and format_for_path at :440)
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/design/master_view.rs:8 (master_view; `master` read via usize_param, `layout` at :14)
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/file.rs:362 (pdf_options) with crates/pdf/src/lib.rs:364-371 (handout_boxes)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Main fixed the PDF font fixture independently (9005839), so that half
of this branch is dropped in favour of main's version; the language
dialog label fix remains.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Text: a word doesn't break after ?, !, } or + (URLs wrap as in PowerPoint)
Unicode line breaking allows a break after ?, !, } and + inside a word,
so a long URL broke after its '?' and after each '+' of a query and left
the rest of the line empty. Measured in PowerPoint 2016 for Windows with
latinLnBrk off (its default), none of them is a break: the word fills the
line and breaks where it no longer fits, as PowerPoint already does after
/ and \ (break_opportunities). The same synthetic slide now wraps line for
line as PowerPoint's PDF does, a Yandex search URL included.
* Text tests: the first line doesn't end at the separator
* Text tests: check the line is full, not that it avoids ending at a separator
* Keep the Unicode break after ?, !, / outside Latin words
The PowerPoint no-break rule only holds inside a word: before an ideograph
(日本!語) or punctuation the Unicode break stays, as CodeRabbit pointed out.
* Only letters and digits continue a word for the no-break rule
AL and AI also hold symbols such as & and ×, so a!&b kept no break after !.
is_word_char now also requires c.is_alphanumeric() (CodeRabbit).
* Test that Latin before CJK and a separator before a space still break
---------
Co-authored-by: Магда М.Г. <mail@mgmagda.ru>
Address review finding: keep signed insets unchanged when their sum fits,
scaling opposing insets proportionally only when both in the pair are
non-negative and their sum exceeds the box dimension.
When text insets exceed the shape dimensions (e.g. lIns + rIns > width),
proportionally scale them down so the inner text rectangle remains
bounded within the shape. Prevents off-slide helper shapes with large
insets from having their text center shifted onto the slide canvas.
- Parse each tags part once per import and cache in `Imp::tags_by_part`
- Cap total copied tags into the model at `MAX_TAG_BYTES` (64 MiB), charging each pair a fixed size_of::<(String, String)>() in addition to text
- Bound the cache: once `tags_capped` is set, return early before parsing or caching any subsequent part
- Tests covering deduplicated part copies, empty-tag pair budgets, and verifying unread tag parts are not parsed or cached after the budget is reached
Add Cascadia Code PL and Cascadia Mono PL to the monospace family
matching list, and add regression tests.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Avoid false-positive monospace match on 'code' in split_whitespace for
proportional families like Code Pro.
- Check office_twin before is_monospace_family in document_face so alias
families like Courier New CE resolve to Courier New when installed.
- Add negative tests for Code Pro and test Courier New CE mapping.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Found while testing crates/engine/src/spell.rs:693 (paragraph_words, the `inside` closure)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Found while testing crates/model/src/edit.rs:470-497 (change_case_parts, title/sentence branch)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
effects_below merged all subpaths into one silhouette and filled it
with the NonZero rule, discarding each subpath's even_odd flag, so the
holes of donut, frame and similar preset shapes filled in under outer
shadows, glows and reflections. Fill each participating subpath under
its own fill rule at the three effect fill sites, mirroring
fill_geometry; the glow stroke keeps the merged silhouette.
Fixes#1596. The picture-content shadow clip path is unchanged
(that is #1597's territory).