On X3 panels, perform a full-sync white flash before rendering the sleep
screen. The previous approach (requestResync condition passes after the
sleep image) reduced ghosting but the first frame still showed residual
content from the reader page. The pre-flash drives the panel to a clean
white state first, so the sleep screen renders ghost-free.
Skipped for OVERLAY mode (frame buffer must stay intact) and BLANK mode
(which renders white anyway).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Picks up fix(x3): use CDI 0x29 in full-sync to prevent black border
pixels — eliminates black border artifacts on x3 when entering sleep.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
instantiateVariableFont with default inplace=False returns a *new*
TTFont; rebinding `font` strands the source TTFont and its file handle
open until GC. The trailing font.close() then closes only the new
pinned-instance object.
Capture the source as a separate reference and close both with nested
try/finally: inner finally closes the static instance after save (or
on save failure), outer finally closes the source unconditionally.
Two related bugs in fontconvert_sdcard.py:
1. SMP filter for ligatures was post-pack, which only checked the
already-masked low half (always ≤ 0xFFFF), didn't check `lc`, and
couldn't catch SMP cps that already had bits truncated by the
mask. Filter at source instead — inside extract_ligatures_fonttools
when building the `filtered` dict — so any seq with an SMP
component or any lig_cp > 0xFFFF is dropped before packing. The
chained 3+ char path is naturally covered because
`intermediate_cp = filtered[prefix].lig_cp` reads from the same
already-filtered table.
2. GPOS kern dispatch checked `actual.LookupType` after unwrapping an
Extension subtable. Format-specific subtables (PairPosFormat1/2)
don't carry `LookupType`, so this fails for any Extension-wrapped
PairPos lookup — i.e. how every modern font (Inter, Source Serif,
Bitter, …) ships kern. Use the effective type instead:
effective_type = getattr(st, "ExtensionLookupType", lookup.LookupType)
so non-Extension lookups read the outer type and Extension lookups
read the inner ExtensionLookupType, and Type-2 PairPos lookups
actually reach _extract_pairpos_subtable in either case.
instantiateVariableFont() in current fontTools doesn't accept a
`static` parameter (signature: varfont, axisLimits, inplace=False,
optimize=True, overlap=…, updateFontNames=False, *, downgradeCFF2=False).
Calling it with static=True raises TypeError, breaking
extract_static_instance() for any sd-fonts.yaml entry that uses the
`variable: {wght: …}` form.
Drop the unsupported kwarg; keep updateFontNames=True (name table
accuracy) and optimize=False (skip wasted gvar work when every axis
is fully pinned). The output is still a fully-pinned static instance
because all yaml-declared axes are pinned in `axes`.