- Drop support for EOL Python 3.10; fontTools now requires Python 3.11 or later.
fontTools.misc.enumToolsnow only re-exportsenum.StrEnumand is deprecated. Explicitly test and declare support for Python 3.15 (#4183, #4196). - [unicodedata] Update the bundled script, script extension, block and bidi-mirroring tables to Unicode 18.0.0, and require
unicodedata218.0.0 when it is used (#4192, #4197). - [feaLib] Support
languagestatements listing multiple language tags, e.g.language AZE CRT;, as Glyphs does and as proposed for the spec (adobe-type-tools/feature_file_workshops#8): the following rules and lookup references are registered under every listed language.dfltcannot be combined with other tags.LanguageStatement.languageis still the first tag; all of them are in the newlanguagesattribute (#4201, #4202). - [feaLib] Fix lookups being dropped when a
script/languagepair is repeated within a feature block: the repeated statement replaced the language system's lookups with a fresh copy of the default ones (#4189). - [feaLib] Raise
FeatureLibErrorinstead ofUnboundLocalErrorwhen aSTATtable block lacksElidedFallbackNameorElidedFallbackNameID(#3834, #4179). - [cffLib] Always recompile the CFF2
VarStorewhen saving. Previously the bytes compiled by an earlier save were reused, so a CFF2 variable font that was saved and then modified in place, e.g. by the instancer, was written with a staleVarStorenext to its updated charstrings (#4199). - [ttLib] Support static
VARCfonts that omitfvarwhile retaininggvaror CFF2 variation data for component-internal axes: hidden axes are addressed by index andgvarcan compile, decompile and round-trip through TTX withoutfvar, reading the axis count from a newaxisCountelement (#4187, #4188). - [ttLib] Fix drawing
VARCcomponents whose condition is negated (format 5), which raisedAttributeError(#4191). - [instancer] Fix
VARCaxis references left stale when removing an unrelated axis, reject pinning or restricting axes referenced byVARCcomponents, and stop culling avar2 ranges for component-internal variations, which can reach outside the font-level ranges (#4190, #4193). - [bezierTools] Preserve exact endpoints in
splitQuadraticAtTandsplitCubicAtTCas well, likesplitCubicAtTsince 4.55.4 (#3742, #4194). - [bezierTools] Fix
ZeroDivisionErrorinlineLineIntersectionsfor collinear vertical lines; they are now treated as parallel like horizontal ones (#3515, #4181). - [subset]
pyftsubsetnow preserves the input font's flavor (WOFF, WOFF2) when--flavoris omitted, instead of writing uncompressed sfnt data under the same extension; pass--flavor=noneto force uncompressed output (#3630, #4182). - [merge] Report incompatible
unitsPerEmvalues by name, with the input values, instead of a bare assertion (#2844, #4184). - [designspaceLib] Fix the type annotation and documentation of
DesignSpaceDocument.default, which holds aSourceDescriptor, not a source name (#2994, #4186). - [ttLib.sfnt] Raise
TTLibErrorinstead ofAssertionErrorfor inconsistent WOFF table, metadata and private-data lengths, so the checks also hold underpython -O(#4178). - [misc.etree] Disable entity resolution altogether on lxml >= 5.0 as well: lxml's
resolve_entities="internal"still fetched external parameter entities before lxml 6.1.3, so a crafted DTD could read local files into parsed XML content (#4195). - [cmap] Bound the expansion of format 4 segments and format 12/13 groups when decompiling, like HarfBuzz does: groups are clamped to U+10FFFF, inverted or overlapping groups are skipped with a warning, and groups mapped to the missing glyph are not expanded. A crafted font could previously exhaust memory with a single group ending at 0xFFFFFFFF (#4204).
- [varLib.avar] Escape axis names and tags when
varLib.avar.unbuildemits its designspace snippet, so a crafted font cannot inject markup (#4203).