All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog and this project adheres to Semantic Versioning.
allocbuild feature, forno_stdbuilds with an allocator.Name::to_stringand thegvar-allocheap spill no longer requirestd. Thanks to iriswebb.- (
cmap)Subtable4::codepoints_iterandSubtable12::codepoints_iter. Unlikecodepoints, they allow early exit. Both takeselfby value. Thanks to MoSal. CFFError::SubroutineCallLimitReached. Thanks to scadastrangelove.core::error::Erroris implemented forFaceParsingErrorinno_stdbuilds now. Thanks to iriswebb.- (
CFF)cff::Table::parse_with_upem, which applies the font matrix using the face's units per em.cff::Table::parsekeeps its original one-argument signature. Thanks to LaurenzV. - (
OS/2)os2::Table::panose, returning the ten raw PANOSE digits plusFamilyTypeandis_bold/is_italic/is_monospaced. The digits are public because their meaning depends on the family type and PANOSE defines more values than this crate models.Face::is_bold,Face::is_italicandFace::is_monospaceddeliberately do not consult it: PANOSE is a design classification, not a style flag. Thanks to inferiorhumanorgans.
- (
loca)loca::Table::lenreturnsu32instead ofu16, and theTable::Short/Table::Longpayloads areLazyArray32instead ofLazyArray16. Thanks to asibahi. - The
gvar-allocbuild feature impliesallocinstead ofstdnow. Adefault-features = false, features = ["gvar-alloc"]build no longer satisfies thestd/no-std-floatguard and must select one of them explicitly. Thanks to iriswebb. Face::set_variationreturnsNonefor an axis tag the face does not expose. It previously returnedSome(())unconditionally, contradicting its own documentation. This is a behavioural change and will not produce a compile error. Thanks to asibahi.CFFErroris#[non_exhaustive]now, so that future hardening limits can add variants without breaking downstream code. Together with the newSubroutineCallLimitReachedvariant, this does break existing exhaustive matches on it.Face::is_italicno longer treats a nonzeropost.italicAngleas italic. It now consults the two flags the spec treats as authoritative:OS/2.fsSelectionandhead.macStylebit 1, the latter of which was not parsed at all before. The angle is a slant value that the spec only says "should" be 0 for upright faces, and real fonts violate that while rendering perfectly upright, so it produced false positives. This is a behavioural change and will not produce a compile error.- (
head)head::Tablehas a new publicis_italicfield, which breaks exhaustive struct destructuring of it. - (
COLR)push_clipandpop_clipare called when painting v0 glyphs, matching v1. APainterthat relied on v0 never clipping will render differently. Thanks to valadaptive. - Bump MSRV to 1.88 and move to edition 2024.
- Test fonts and development tools are excluded from the published package, which is substantially smaller as a result. Thanks to weiznich.
- Dependencies are pinned to a minor version rather than an exact one. Thanks to alerque.
- Documented the
Face::stylefallback toStyle::NormalwhenOS/2is absent. Thanks to dereified. - Documented every field of
RawFaceTables.
- (
CFF) Bound the total number of subroutine invocations per glyph.STACK_LIMITbounds nesting depth only, so work grew as fanout^depth: a 255-byteCFFtable hung for over 30 seconds. Thanks to scadastrangelove. - (
GSUB/GPOS) Reject self-referential extension lookups. An extension lookup pointing at the extension type recursed unboundedly: a stack-overflow abort in debug and an infinite loop in release, from 8 bytes of input. Thanks to scadastrangelove. - (
loca) Support tables with 65536 offsets. A well-formed 65535-glyph font was rejected,glyfwas dropped entirely and every outline returnedNone. Thanks to asibahi. - (
glyf/gvar) Cap the total number of component visits when outlining composite glyphs.MAX_COMPONENTSbounds chain depth only, so shared child glyphs let sibling components force branching^depth re-walks under the cap. Thanks to scadastrangelove. - (
COLR) Cap the total number of paint-graph node visits in v1 painting. The recursion stack bounds path depth but not fan-out, andlayers_countis au8, so a small font could force an enormous traversal. Thanks to scadastrangelove. - (
CFF2) Guard theBLENDoperator against an empty argument stack. Thanks to scadastrangelove. - (
CFF) Glyphs containing the deprecateddotsectionoperator are no longer rejected. Previously the whole charstring failed withUnsupportedOperator, so glyphs likei,j,!and.in fonts converted from Type 1 produced no outline at all. Thanks to tobocop2. - (
GSUB/GPOS)LazyOffsetArrayIter16skipsNULLoffsets instead of ending iteration. ANULLoffset hid every later entry, so valid fonts silently lost sequence rule sets. Thanks to asibahi. - (
GSUB/GPOS)LazyOffsetArrayIter16::countno longer over-reports by the number of skipped entries and agrees withcollect().len()now. - (
avar)map_valuearithmetic no longer overflows. Unvalidatedi16coordinates could panic in debug or silently invert the sign in release. Thanks to scadastrangelove. - (
fvar) Read theHIDDEN_AXISflag from bit 0, not bit 3. Hidden axes were never reported for conforming fonts. Thanks to SamusAranX. - (C API)
ttfp_get_glyph_namerejects glyph names longer than the documented 256-byte buffer instead of panicking across theextern "C"boundary, which is a non-unwinding abort. Thanks to scadastrangelove. - (
glyf) Composite components using point matching no longer desync the parser. The two component arguments were consumed only on theARGS_ARE_XY_VALUESpath, so an unsupported point-matching component left the stream positioned mid-arguments and every subsequent read in that glyph decoded from the wrong offset. Point matching itself remains unimplemented, but it no longer corrupts the components that follow it. - (
fvar)Face::set_variationworks on a face with exactly 64 axes. Its guard rejected an axis count equal to the coordinate-storage limit, while every other site clamps to that limit inclusively, so such a face could not be varied on any axis at all. Stream::read_bytesbounds the requested length against the buffer instead of asserting onoffset + len. The assert was meant to catch caller bugs, but malformed fonts reach it just as easily through aCFFINDEX count, acbdtPNG length, aGPOSclass-pair product and others, so debug builds aborted on input that release builds rejected cleanly — noise for anyone fuzzing a debug build. Checking first also makes the addition sound on 32-bit targets, which the assert never did.- (
HVAR/VVAR/COLR) A delta-set index map no longer advances past its buffer before reading.mapCountis a rawu32and the index is scaled by the entry size. - (
COLR) Variation delta indices are added with overflow checking. AvarIndexBasenearu32::MAXaborted in debug and wrapped to an unrelated delta index in release. - (
CFF) Glyph outlines are transformed by the font matrix. Fonts with a non-defaultFontMatrixwere outlined at the wrong scale. Thanks to tbodt. - (
CFF2) Fonts without avstorecan outline glyphs. The Top DICT entry is optional per spec, but variation scalars were resolved at index 0 before the first operator ran, which fails on an absent store — so every glyph of a static CFF2 font returnedNone. Scalars are now resolved on firstblendinstead, which is the only operator that needs them. - (
gvar) Outlining a variable glyph no longer aborts under-Zrandomize-layout. Twodebug_assert!s bounded the size of internal iterator structs, but Rust does not guaranteerepr(Rust)layout and randomization pushed them past the bound, so every debug build of every application using the flag panicked on a budget it could not influence. The bounds are now checked in this crate's own test suite instead.
0.25.1 - 2024-11-29
- Fix some typos and documentation related lints
- Set MSRV in manifest to actual current value (1.63.0)
- Update forge URL for ttf-parser and rustybuzz to harfbuzz org
0.25.0 - 2024-10-04
STATtable parsing. Thanks to inferiorhumanorgans.UnicodeRangesinternal field is public now.cargo-cmetadata to C API. Thanks to lu-zero.
Face::is_italicchecks for italic angle as well.Face::italic_anglereturns just af32and notOption<f32>now.- Bump MSRV to 1.59
- Only apply
avartable to the variation axis being set. Thanks to maxmelander.
0.24.1 - 2024-08-05
- (
glyf)glyf::Table::bbox. Thanks to LaurenzV.
- (
kerx)kerx::SubtablesIterwasn't updating the current subtable index. - (
GPOS)gpos::AnchorMatrixallows nullable/optional matrices now. Thanks to LaurenzV.
0.24.0 - 2024-07-02
- Make
core_mathsdependency optional. When building forno_stdone must enableno-std-floatbuild feature now.
0.23.0 - 2024-07-02
- Use
core_mathsinstead oflibm. Should simplify the build process. Thanks to LaurenzV.
no-std-floatbuild flag. Should be handled automatically now.
0.22.0 - 2024-06-29
Face::glyph_phantom_pointshvar::Table::right_side_bearing_offset. Thanks to LaurenzV.vvar::Table::advance_offset. Thanks to LaurenzV.vvar::Table::top_side_bearing_offset. Thanks to LaurenzV.vvar::Table::bottom_side_bearing_offset. Thanks to LaurenzV.vvar::Table::vertical_origin_offset. Thanks to LaurenzV.colr::Table::clip_box. Thanks to LaurenzV.
no_stdbuild ofttf-parserrequires--features=no-std-floatnow. This is because we need trigonometry functions to flatten transforms inCOLR. Thanks to LaurenzV.colr::Painterno longer haspush_translate,push_scale,push_rotateandpush_skew. Onlypush_transformleft. Thanks to LaurenzV.- Split
hvar::Tableintohvar::Tableandvvar::Table. Previously, we treated bothHVARandVVARtables as identical, butVVARactually has additional fields. Thanks to LaurenzV. - Rename
hvar::Table::side_bearing_offsetintohvar::Table::left_side_bearing_offset. Thanks to LaurenzV.
Face::glyph_hor_advanceandFace::glyph_ver_advanceincludegvar's phantom points whenHVAR/VVARtables are missing. Affects only variable fonts.- (
CFF) Allow MoveTo with width commands in nested subroutines. opentype_layout::LookupFlags::mark_attachment_typeparsing.- (
CFF) Allow empty charsets incff::parse_charset. Thanks to LaurenzV. - (
gvar) Empty sub-glyphs/components is no longer an error. Thanks to LaurenzV. - (
GSUB/GPOS) AllowNULLoffsets inChainedContextLookupFormat2 subtables. Thanks to LaurenzV. Face::glyph_y_originproperly handles variable fonts now. Thanks to LaurenzV.- (
kerx) FixAnchorPointsparsing. Thanks to LaurenzV.
push_translate,push_scale,push_rotateandpush_skewfromcolr::Painter. Usecolr::Painter::push_transforminstead. Thanks to LaurenzV.
0.21.1 - 2024-05-11
- Delta set length calculation in variable fonts.
Thanks to LaurenzV.
Got broken in the previous version.
0.21.0 - 2024-05-10
COLR/CPALv1 support. Thanks to LaurenzV.
- Replace
Face::is_bitmap_embedding_allowedwithFace::is_outline_embedding_allowed. The old one had a bool flag flipped. Thanks to Fuzzyzilla. - Increase lenience of embed permissions for older OS/2 versions. Thanks to Fuzzyzilla.
- Bump MSRV to 1.51
0.20.0 - 2023-10-15
COLR/CPALv0 support. Thanks to laurmaedje.Face::is_color_glyphFace::color_palettescpal::Table::palettes
svg::SvgDocumentsListreturnssvg::SvgDocumentand not just&[u8]now. Thanks to wjian23.Face::set_variationallows duplicated axes now.cpal::Coloris calledcpal::BgraColornow, andcpal::Table::getreturns it.
0.19.2 - 2023-09-13
cff::Table::glyph_cid
0.19.1 - 2023-06-20
cff::Table::glyph_widthreturns a correct width when subroutines are present.
0.19.0 - 2023-04-17
bdat,bloc,EBDTandEBLCtables support. Thanks to dzamkov.BitmapMono,BitmapMonoPacked,BitmapGray2,BitmapGray2Packed,BitmapGray4,BitmapGray4Packed,BitmapGray8andBitmapPremulBgra32variants toRasterImageFormat.
CBLCtable parsing. Thanks to dzamkov.
0.18.1 - 2023-01-10
- (
MATH) Handle NULL offsets. Thanks to laurmaedje.
0.18.0 - 2022-12-25
name::Name::languageLanguageenum with all Windows languages.
0.17.1 - 2022-10-15
Face::permissionsFace::is_subsetting_allowedFace::is_bitmap_embedding_allowedFace::unicode_rangesos2::Table::permissionsos2::Table::is_subsetting_allowedos2::Table::is_bitmap_embedding_allowedos2::Table::unicode_ranges
- Using a non-zero index in
Face::parsefor a regular font will returnFaceParsingError::FaceIndexOutOfBoundsnow. Thanks to Pietrek14.
0.17.0 - 2022-09-28
MATHtable support. Thanks to ruifengx and laurmaedje.
- (CFF) Fix large tables parsing.
0.16.0 - 2022-09-28
- CFF Encoding support.
cff::Table::glyph_indexcff::Table::glyph_index_by_namecff::Table::glyph_widthcff::Table::number_of_glyphscff::Table::matrixpost::Table::glyph_namepost::Table::glyph_index_by_namepost::Table::namesFace::glyph_index_by_nameRawFacefields andTableRecordstruct are public now.
Face::from_slicewas replaced byFace::parse.RawFace::from_slicewas replaced byRawFace::parse.post::Table::namesis a method and not a field now.- Use
post::Table::glyph_nameinstead ofpost::Table::names.get().
- (hmtx/vmtx) Allow missing additional side bearings.
- (loca) Allow incomplete table.
- Reduce strictness of some table length checks.
- (post)
post::Names::lenwas returning a wrong value. Now this method is gone completely. You can usepost::Table::names().count()instead.
0.15.2 - 2022-06-17
- Missing advance and side bearing offsets in
HVAR/VVARis not an error. Simply ignore them.
0.15.1 - 2022-06-04
- (cmap)
cmap::Subtable4::glyph_indexcorrectly handles malformed glyph offsets now. - (cmap)
cmap::Subtable4::codepointsno longer includes0xFFFFcodepoint. - (SVG) Fixed table parsing. Thanks to Shubhamj280
0.15.0 - 2022-02-20
apple-layoutbuild feature.ankr,feat,kerx,morxandtraktables.kernAAT subtable format 1.RawFace
- The
parsermodule is private now again.
0.14.0 - 2021-12-28
- (cmap)
cmap::Subtable::glyph_indexandcmap::Subtable::glyph_variation_indexacceptu32instead ofcharnow. - (glyf) ~7% faster outline parsing.
0.13.4 - 2021-11-23
- (CFF) Panic during
seacresolving. - (CFF) Stack overflow during
seacresolving.
0.13.3 - 2021-11-19
- (glyf) Endless loop during malformed file parsing.
0.13.2 - 2021-10-28
gvar-allocbuild feature that unlocksgvartable limits by using heap. Thanks to OrionNebula
0.13.1 - 2021-10-27
Face::line_gaplogic.
0.13.0 - 2021-10-24
- Complete GSUB and GPOS tables support. Available under the
opentype-layoutfeature. - Public access to all supported TrueType tables. This allows a low-level, but still safe, access to internal data layout, which can be used for performance optimization, like caching.
Styleenum andFace::stylemethod.Face::glyph_namecan be disabled via theglyph-namesfeature to reduce binary size.
- Improved ascender/descender/line_gap resolving logic.
Facemethods:has_glyph_classes,glyph_class,glyph_mark_attachment_class,is_mark_glyphandglyph_variation_deltaare moved togdef::Table.- The
Namesstruct is no longer an iterator, but a container. You have to callinto_iter()manually. - The
VariationAxesstruct is no longer an iterator, but a container. You have to callinto_iter()manually. - Most of the
Namestruct methods become public fields. Face::units_per_emno longer returnsOption.- (
cmap) Improved subtable 12 performance. Thanks to xnuk
- (c-api)
ttfp_glyph_class,ttfp_get_glyph_class,ttfp_get_glyph_mark_attachment_class,ttfp_is_mark_glyph,ttfp_glyph_variation_deltaandttfp_has_table. TableNameenum andFace::has_table. Tables can be access directly now.Face::character_mapping_subtables. UseFace::tables().cmapinstead.Face::kerning_subtables. UseFace::tables().kerninstead.
Iterator::countimplementation forcmap::Subtables,name::NamesandLazyArrayIter32.
0.12.3 - 2021-06-27
- (
glyf) Always use a calculated bbox.
0.12.2 - 2021-06-11
Face::glyph_bounding_boxfor variableglyf.- (
glyf) Do not skip glyphs with zero-sized bbox.
0.12.1 - 2021-05-24
- Support Format 13 subtables in
cmap::Subtable::is_unicode. Thanks to csmulhern - Derive more traits by default. Thanks to dhardy
0.12.0 - 2021-02-14
Face::ascenderandFace::descenderwill use usWinAscent and usWinDescent whenUSE_TYPO_METRICSflag is not set inOS/2table. Previously, those values were ignored and hhea::ascender and hhea::descender were used. Nowhheatable values will be used only whenOS/2table is not present.Face::outline_glyphandFace::glyph_bounding_boxin case of aglyftable can fallback to a calculated bbox when the embedded bbox is malformed now.
0.11.0 - 2021-02-04
FaceTables, which allowed to loadFacenot only from a single chunk of data, but also in a per-table way. Which is useful for WOFF parsing. No changes to the API. Thanks to fschutt
0.10.1 - 2021-01-21
- Update a font used for tests.
0.10.0 - 2021-01-16
variable-fontsbuild feature. Enabled by default. By disabling it you can reducettf-parserbinary size overhead almost twice.
- (
gvar) Increase the maximum number of variation tuples from 16 to 32. Increases stack usage and makesgvarparsing 10% slower now.
- (
CFF) Fixseacprocessing. Thanks to wezm
0.9.0 - 2020-12-05
kernAAT subtable 1 akakern::state_machine. Mainly because it's useless without a proper shaping.
0.8.3 - 2020-11-15
Face::glyph_variation_delta- The
parsermodule is public now. Made private again in 0.15.0. - (C API)
ttfp_glyph_variation_delta
Iterator::nthimplementation forcmap::SubtablesandNames.
0.8.2 - 2020-07-31
cmap::Subtable::codepoints
- (cmap) Incorrectly returning glyph ID
0instead ofNonefor format 0 - (cmap) Possible invalid glyph mapping for format 2
0.8.1 - 2020-07-29
Face::is_monospacedFace::italic_angleFace::typographic_ascenderFace::typographic_descenderFace::typographic_line_gapFace::capital_height
0.8.0 - 2020-07-21
- Allow
truemagic. FaceParsingErrorNormalizedCoordinateFace::variation_coordinatesFace::has_non_default_variation_coordinatesFace::glyph_namecan lookup CFF names too.Face::table_dataFace::character_mapping_subtables
- (CFF,CFF2) 10% faster parsing.
Face::from_slicereturnsResultnow.Name::platform_idreturnsPlatformIdinstead ofOption<PlatformId>now.- The
cmapmodule became public.
Face::widthparsing.- Possible u32 overflow on 32-bit platforms during
Face::from_slice. - (cmap)
Face::glyph_variation_indexprocessing when the encoding table has only one glyph.
0.7.0 - 2020-07-16
- (CFF) CID fonts support.
- (CFF)
seacsupport. Font::global_bounding_box
- Rename
FonttoFace, because this is what it actually is. - Rename
Font::from_datatoFont::from_sliceto match serde and other libraries. - Rename
Name::name_utf8toName::to_string.
Font::family_nameandFont::post_script_name. They were a bit confusing. Prefer:face.names().find(|name| name.name_id() == name_id::FULL_NAME).and_then(|name| name.to_string())
0.6.2 - 2020-07-02
Name::is_unicodeFont::family_namewill load names with Windows Symbol encoding now.
Font::glyph_bounding_boxwill apply variation in case ofgvarfonts.
0.6.1 - 2020-05-19
- (
kern) Support fonts that ignore the subtable size limit.
0.6.0 - 2020-05-18
sbix,CBLC,CBDTandSVGtables support.Font::glyph_raster_imageandFont::glyph_svg_image.Font::kerning_subtableswith subtable formats 0..3 support.
- (c-api) The library doesn't allocate
ttfp_fontanymore. All allocations should be handled by the caller from now.
Font::glyphs_kerning. UseFont::kerning_subtablesinstead.- (c-api)
ttfp_create_fontandttfp_destroy_font. Usettfp_font_size_of+ttfp_font_initinstead.ttfp_font *font = (ttfp_font*)alloca(ttfp_font_size_of()); ttfp_font_init(font_data, font_data_size, 0, font);
- Logging support. We haven't used it anyway.
- (
gvar) Integer overflow. - (
cmap) Integer overflow during subtable format 2 parsing. - (
CFF,CFF2) DICT number parsing. Font::glyph_*_advancewill returnNonewhen glyph ID is larger than the number of metrics in the table.- Ignore variation offset in
Font::glyph_*_advanceandFont::glyph_*_side_bearingwhenHVAR/VVARtables are missing. Previously returnedNonewhich is incorrect.
0.5.0 - 2020-03-19
- Variable fonts support.
- C API.
gvar,CFF2,avar,fvar,HVAR,VVARandMVARtables support.Font::variation_axesFont::set_variationFont::is_variableTagtype.
- Multiple issues due to arithmetic overflow.
0.4.0 - 2020-02-24
A major rewrite.
Font::glyph_bounding_boxFont::glyph_nameFont::has_glyph_classesFont::glyph_classFont::glyph_mark_attachment_classFont::is_mark_glyphFont::glyph_y_originFont::vertical_ascenderFont::vertical_descenderFont::vertical_heightFont::vertical_line_gap- Optional
logdependency.
Font::outline_glyphnow accepts&mut dyn OutlineBuilderand not&mut impl OutlineBuilder.Font::ascender,Font::descenderandFont::line_gapwill checkUSE_TYPO_METRICSflag in OS/2 table now.glyph_hor_metricswas split intoglyph_hor_advanceandglyph_hor_side_bearing.glyph_ver_metricswas split intoglyph_ver_advanceandglyph_ver_side_bearing.CFFErroris no longer public.
Errorenum. All methods will returnOption<T>now.- All
unsafe.
glyph_hor_side_bearingparsing when the number of metrics is less than the total number of glyphs.- Multiple CFF parsing fixes. The parser is more strict now.
0.3.0 - 2019-09-26
no_stdcompatibility.
- The library has one
unsafeblock now. - 35% faster
family_name()method. - 25% faster
from_data()method for TrueType fonts. - The
Namestruct has a new API. Public fields became public functions and data is parsed on demand and not beforehand.
0.2.2 - 2019-08-12
- Allow format 12 subtables with Unicode full repertoire in
cmap.
0.2.1 - 2019-08-12
- Check that
cmapsubtable encoding is Unicode.
0.2.0 - 2019-07-10
- CFF support.
- Basic kerning support.
- All
cmapsubtable formats except Mixed Coverage (8) are supported. - Vertical metrics querying from the
vmtxtable. - OpenType fonts are allowed now.
- A major rewrite. TrueType tables are no longer public.
- Use
GlyphIdinstead ofu16.
GDEFtable parsing.
0.1.0 - 2019-06-18
- Initial release. Parsing of
cmap,glyf,head,hhea,hmtx,loca,maxp,name,OS/2,post,vheaandvmtx, withGDEFand font-collection support.