PowerPoint keeps fi, ffi and Calibri's ti apart and kerns a run only when
a:rPr/@kern is set and the size reaches it; DeckCraft shaped with the font's
defaults (ligatures and kerning always on), so Calibri text read differently
and kern="0" text came out narrower.
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Bullets in Wingdings, Wingdings 2/3, Symbol and other symbol fonts were
always swapped for a look-alike from one Wingdings table, so a Wingdings 2
star (0xEA) became a round dot. When the deck's symbol font is installed,
its glyph is drawn (symbol fonts map character codes at U+F000 + code), as
PowerPoint does; otherwise Wingdings 2 and 3 codes get their own
look-alikes.
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Circled-number lists (circleNumDbPlain) and character bullets whose glyph
isn't in the paragraph's font were drawn as missing-glyph boxes (numbers)
or always from Inter (characters). Both now go through the usual font
fallback, as PowerPoint draws them.
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Emoji: colour glyphs, and emoji take the colour emoji font
Emoji were drawn as black outlines from a symbol font, with ZWJ sequences
(families, flags) falling apart into their parts. Now:
- an emoji cluster (emoji presentation, U+FE0F, ZWJ between pictographs,
skin tones, regional indicators, keycaps) takes an installed colour font
(COLR, CBDT, sbix or SVG tables) before the document's fonts, so its
sequences ligate as in PowerPoint; U+FE0E keeps a plain face;
- COLR v0 and v1 glyphs are painted in their CPAL colours (solid fills,
linear, radial and sweep gradients, transforms, composite modes), with
palette index 0xFFFF in the text colour.
A tiny COLRv0 test font (two squares, CC0, regenerated by
make_colr_font.py) backs the render test.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Render: lock skrifa for colour glyphs
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Text: wrap lines where PowerPoint does
- Without latinLnBrk (PowerPoint's default) a word doesn't break after '/'
or '\': URLs and paths fill the line and break at its edge.
- Korean wraps between words, not between syllables.
- With hangingPunct, closing East Asian punctuation hangs past the end of
the line instead of dragging the previous character down.
ParaProps gains latin_line_break and hanging_punct, read and written as
latinLnBrk and hangingPunct.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Text: simpler break guard (clippy)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Text: single-spaced lines are 1.2 times the font size apart, as in PowerPoint
PowerPoint spaces single-spaced lines 1.2 x the font size apart in every
font (measured on twenty Latin, CJK, Thai and Indic fonts at 18 and 40 pt
with PowerPoint's slide export) and puts the baseline where the font's
Windows ascent/descent split it. DeckCraft used each font's own ascent plus
descent, so Calibri lines were 15% too tight and Segoe UI ones too loose.
FontFace gains line_split (usWinAscent / (usWinAscent + usWinDescent));
line_metrics uses it with LINE_PITCH = 1.2.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Text: tidy the line pitch test
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Fonts: line_split guard reads plainly (clippy)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Text: note that the 1.2 line pitch was measured on one Windows install
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
When marL + indent is negative, PowerPoint pins the bullet to the box's edge
and starts the first line's text at -indent; DeckCraft put the text right
after the number, so numbered lists written with indent=-457200 and no marL
lost their gap.
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
PowerPoint draws buChar char="••" (seen in a LibreOffice test deck) as a
single dot; DeckCraft drew both, pushing the text right.
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Superscript and subscript glyphs were drawn at two thirds of the run's size but
advanced by the full size, so the letters spread apart ("s u p e r") and the
line ran wider than in PowerPoint. The cluster advance now uses the same scale
as the glyphs.
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Sprint 1: bidi and Arabic typography engine
fonts: ISO 15924 script and a:latin/a:ea/a:cs slot classification;
shape_range shapes an item with the whole paragraph as HarfRust
pre/post context, explicit script/language/direction, glyphs kept in
visual order; per-grapheme-cluster fallback (slot face, theme script
font, OS cascade families, bundled craft-fonts face); GDEF ligature
carets.
text: UAX #9 levels for the whole paragraph (a:pPr/@rtl), itemization
by level, script, face and shaping style (paint-only changes no longer
split words), logical line breaking at cluster boundaries, per-line
L1/L2 reordering (L4 mirroring by the shaper); RTL start edge and
bullets, justLow kashida; caret Affinity, logical/visual movement,
bidi hit testing and selection as the union of visual boxes.
model/pptx: theme a:font script fonts and algn="justLow" round-trip.
engine: format.rtl (Right-to-Left Text Direction), justifyLow align.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Fonts: the bundled script face comes before installed fonts; no Microsoft family names
Arabic, Hebrew, Thai and Devanagari clusters try the craft-fonts face first, so every machine
draws the same, then openly licensed or OS-native installed families, then any installed face.
Installed Microsoft faces are still used through that scan, but not named (AGENTS.md §1.1).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Tayeb <tayeb@192.168.11.179>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>