Despite its name, this option only gated 'avar' version 2 support.
FreeType 2.15.0 includes the complete boring-expansion set of proposals,
now released as ISO Open Font Format, fifth edition
(ISO/IEC 14496-22:2026). Gating just avar2 no longer makes sense,
especially since it has also been shipping on Apple platforms for
four years.
* include/freetype/config/ftoption.h, devel/ftoption.h
(TT_CONFIG_OPTION_NO_BORING_EXPANSION): Remove.
* src/truetype/ttgxvar.c (ft_var_load_avar): Remove configuration guards.
* docs/CHANGES: Updated.
All five Meson regression tests pass with the removed macro still
defined. avar1 and avar2 coordinate mapping agrees with FontTools.
Assisted-by: OpenAI Codex
Static VARC fonts can have private variation axes without an 'fvar'
table or public MM metadata. Use the blend's axis count when validating
'avar' and item variation stores, avoiding a null 'mmvar' dereference
when loading HVAR or VVAR for a VARC component.
* src/truetype/ttgxvar.c (ft_var_load_avar,
tt_var_load_item_variation_store): Use blend->num_axis.
* tests/varc/make-hvvar-fonts.py: Generate HVAR and VVAR fixtures from
the static VARC/gvar font using only Python's standard library.
* tests/meson.build: Generate the fixtures and pass them to the VARC test.
* tests/varc/main.c (test_font, main): Test generated fixture paths.
Tests: all five Meson regression tests pass.
Fixes issue #1474.
Assisted-by: OpenAI Codex
With the incremental interface, `tt_glyph_load` accepts glyph indices beyond
`num_glyphs`, but the 'hdmx' records only hold `num_glyphs` widths.
* src/truetype/ttgload.c (TT_Load_Glyph): Don't use `loader.widthp`
for glyph indices outside of the font's glyph range.
This improves performance, fixes#1473.
* src/base/fttrigon.c (ft_trig_pseudo_rotate, ft_trig_pseudo_polarize):
Replace if-else with conditional negation by a mask.
==========================
Tag sources with `VER-2-15-0'.
* docs/VERSION.TXT: Add entry for version 2.15.0.
* docs/CHANGES: Updated.
* docs/release, docs/README, builds/macs/README: Updated.
* README, src/base/ftver.rc, builds/windows/vc2010/index.html,
builds/windows/visualc/index.html, builds/windows/visualce/index.html,
builds/wince/vc2005-ce/index.html, builds/wince/vc2008-ce/index.html,
docs/freetype-config.1: s/2.14.3/2.15.0/, s/2143/2150/.
* include/freetype/freetype.h (FREETYPE_MINOR): Set to 15.
(FREETYPE_PATCH): Set to 0.
* builds/unix/configure.raw (version_info): Set to 26:7:20.
* CMakeLists.txt (VERSION_MINOR): Set to 15.
(VERSION_PATCH): Set to 0.
Reported as
https://issues.oss-fuzz.com/issues/570754474
* src/truetype/ttvarc.c (tt_varc_parse_component): Use `MUL_INT32` for
converting 32-bit packed axis values from `F2DOT14` to `F16DOT16`.
(tt_face_load_varc_glyph): Use `NEG_LONG` when rounding negative axis
values, since the conversion can wrap to `INT32_MIN` and negating that
value overflows on platforms with 32-bit longs.
Assisted-by: OpenAI Codex
`numBlends` comes from the charstring and is attacker-controlled. Check for
overflow before multiplying: a wrapped `numOperands` would bypass the stack
underflow check below and the loop that follows would then run up to 2^32
iterations (CPU exhaustion).
A lookup can be registered under several scripts while substituting inputs
from only one of them. Collecting every output assigns those glyphs to the
first processed script, regardless of the inputs' styles. In Google Sans
this assigns the Latin rvrn alternates to Cyrillic; missing Cyrillic blue
zones then disable their hinting and darkening.
* src/autofit/afshaper.c (af_shaper_get_coverage_hb): Seed default coverage
with glyphs already assigned to the style and compute their substitution
closure through the collected lookups.
Keep the special feature coverages and their style precedence intact.
* src/autofit/ft-hb-decls.h: Add `hb_ot_layout_lookups_substitute_closure`.
* tests/issue-1441/*: New files, adding synthetic regression fonts covering
shared lookups, both feature variation records, chained substitutions,
ligatures, DFLT-only features, unreachable outputs, and preservation of
the small-cap style.
The full Meson test suite passes with linked, dynamic, and disabled
HarfBuzz. The regression fails before the fix. Google Sans alternates
retain Latin styles and stem darkening after the fix.
Assisted-by: OpenAI Codex
Fixes issue #1441.
* src/sfnt/ttcmap.c: Include `freetype/ttnameid.h` for the TrueType
platform and encoding IDs used by `tt_face_find_unicode_dmap`.
The single-object build inherited this include from `sfdriver.c`
and `sfobjs.c`, masking the missing direct dependency.
Assisted-by: OpenAI Codex <noreply@openai.com>
* tests/issue-1469: New directory, containing a test and a script to
generate fonts used by the test, together with a README file.
* tests/meson.build: Updated.
Spec: https://github.com/harfbuzz/boring-expansion-spec/pull/175
Offset-base erratum: https://github.com/harfbuzz/boring-expansion-spec/issues/177
* src/truetype/ttvarc.c (tt_varc_evaluate_region, tt_varc_get_item_deltas):
Read the sparse-region count as uint32, resolve each sparse axis through a
region-relative Offset32, and follow the Offset32 to the delta-set INDEX.
Bound the new offset fields and count arrays before dereferencing them.
* tests/varc/main.c (test_variation_store): New function to check
translated outlines at default, midpoint, and peak coordinates.
(main): Updated.
* tests/data/varc-null-condition.ttf, tests/data/varc-value-conditions.ttf:
Updated to migrate the existing affected fixture without changing its
logical contents or non-VARC tables.
* tests/data/varc-variation-store.ttf: New test file.
Tests: full Meson regression suite (3 passed).
Assisted-by: OpenAI Codex
Condition format 2 tests whether default plus interpolated delta is
positive. Rounding the delta to an integer first loses small positive
fractions and incorrectly hides components.
* src/truetype/ttvarc.c (tt_varc_get_item_deltas): Add argument
`condition_defaults`.
(tt_varc_get_item_deltas, tt_varc_eval_condition): Allow the
MultiItemVariationStore evaluator to initialize condition accumulators
from their defaults and return the unrounded sign. Compare in the
existing 64-bit representation, including the emulated path, so large
int32 deltas need not fit in a signed 16.16 `FT_Long`.
Use ULABS for unsigned magnitudes in emulated multiplication, avoiding
MSVC's warning about unsigned unary negation (see
https://gitlab.freedesktop.org/freetype/freetype/-/merge_requests/458#note_3692404).
Cast to `FT_UInt32` after obtaining the magnitude; no additional
absolute-value helper is needed.
(tt_varc_apply_axis_deltas, tt_varc_apply_transform_deltas): Updated.
* tests/data/varc-value-conditions.ttf: New test font.
* tests/varc/main.c (test_value_conditions): New function, adding a small
fixture and 80 direct/negated condition checks covering positive, zero,
negative, and fractional values.
(main): Updated.
All three Meson targets and the forced-emulated VARC tests pass. All 40
cross-library diagnostic cases and 115 native/emulated arithmetic
comparisons agree. MSVC itself was not available locally.
Assisted-by: OpenAI Codex <codex@openai.com>
* src/truetype/ttvarc.c (tt_varc_get_item_deltas, tt_face_load_varc_glyph):
The emulated `FT_Int64` is a struct: `FT_INT64_ZERO` cannot be assigned as
an expression, and unguarded transform products do not compile. Use
`FT_ARRAY_ZERO` and portable `FT_MulDiv` function for these fallback
operations.
Restrict the fast signed product to its safe range, preserve carries when
adding negative products, and combine both accumulator words when
converting fractional deltas. Explicitly sign-extend the result.
The full Meson suite passes. An isolated build forcing the emulated VARC
path compiles without an initializer bypass; 115 native/emulated condition
and scaled/unscaled transform comparisons agree, including large signed
deltas, cancellation, and carries.
Assisted-by: OpenAI Codex <codex@openai.com>
The OpenType condition rules define an offset of zero as the true
condition. Recognize that value both in the top-level ConditionList and
in nested AND, OR, and NOT conditions.
Add a VARC regression font covering all four cases.
* src/truetype/ttvarc.c (tt_varc_eval_condition): Handle zero offsets.
* tests/data/varc-null-condition.ttf: New test font.
* tests/varc/main.c: Test it.
Assisted-by: OpenAI Codex <codex@openai.com>
OFF permits trailing glyphs to be provided entirely by VARC. Preserve the
SFNT glyph count for CFF2 fonts with VARC, and dispatch those glyphs to VARC
before checking the CFF2 fallback CharString range.
Add a short-CharStrings fixture and verify its glyph count and outline. All
three Meson tests pass.
Assisted-by: OpenAI Codex <noreply@openai.com>
* src/cff/cffgload.c (cff_slot_load): Check agains correct `num_glyphs`
values.
* src/cff/cffobjs.c (cff_face_init) [TT_CONFIG_OPTION_VARC]: Conditionalize
update of `cffface->num_glyphs`.
* tests/varc/main.c (TestFont): New field `glyph_count`.
(test_font): Check number of glyphs.
(main): Updated.
* tests/data/var/short-cff2.otf: New test font.
* src/truetype/ttvarc.c (tt_face_load_varc_glyph): `RESET_UNSPECIFIED_AXES`
also applies to components with no `HAVE_AXES` payload. Previously these
components inherited the parent coordinates because the reset path
required at least one axis value.
* tests/varc/main.c (test_reset_without_axes): Enter the coordinate override
path for reset-only components, restoring the font's current instance
before loading their leaves.
Add a nested VARC regression at default and non-default font coordinates.
(main): Updated.
* tests/data/varc-reset-only.ttf: New test font.
Tests: all three Meson targets pass. Generated reset, explicit-axis, and
inheritance comparisons agree with HarfBuzz and FontTools.
Assisted-by: OpenAI Codex <noreply@openai.com>
* src/base/ftoutln.c (FT_Outline_Reverse): Keeping the first point fixed
changes cubic control-point pairing when that point is off-curve. Reverse
the entire contour in that case, while preserving the existing order for
on-curve and conic starts.
* tests/outline-reverse/main.c: New regression test to cover off-curve
starts, all-off contours, implied endpoints, and the cubic flag on
on-curve points. Check reversed segments, bounding boxes, and a second
reversal. All three Meson tests pass.
* tests/meson.build: Updated.
Assisted-by: OpenAI Codex <noreply@openai.com>
Preserve the cubic flag while loading extended simple glyphs, including
on-curve points whose state can be changed by TrueType instructions.
Teach outline decomposition, stroking, and rasterization to handle cubic
contours with implied on-curve points, including contours with no explicit
on-curve points. Continue to ignore the reserved flag in the classic 'glyf'
table.
Tested with a synthetic font with a 'GLYF' table covering all-off contours,
implied cubic endpoints, gray and monochrome rendering, and stroking. The
full Meson test suite also passes.
Assisted-by: OpenAI Codex <noreply@openai.com>
* include/freetype/ftimage.h (FT_CURVE_TAG): Extended for use with 'GLYF'
table data.
* src/base/ftoutln.c (FT_Outline_Decompose), src/base/ftstroke.c
(FT_Stroker_ParseOutline), src/raster/ftraster.c (Decompose_Curve),
src/smooth/ftgrays.c (FT_Outline_Decompose) [STANDALONE_]: Extend parsing
code to handle 'GLYF' cubic data.
* src/truetype/ttgload.c (CUBIC_FLAG): New flag macro.
(TT_Load_Simple_Glyph): Check new flag.
Parse the optional, cmap-shaped delta map and apply its mappings before the
corresponding 'cmap' mappings. Preserve sparse fallback for nominal
characters and variation sequences, including the variant-list APIs.
Also keep variation-only subtables from becoming the active Unicode
charmap when DMAP supplies the only nominal Unicode mapping.
Tested with the Meson test suite and synthetic fonts covering nominal
and UVS precedence, fallback, iteration, DMAP-only subtables, and
extended glyph IDs.
Assisted-by: OpenAI Codex <noreply@openai.com>
* include/freetype/internal/tttypes.h (TT_Face): New fields `dmap_table`,
`dmap_size`, `dmap_charmaps`, `num_dmap_charmaps`, `dmap_results`,
`dmap_max_results`.
* include/freetype/tttags.h (TTAG_DMAP): New macro.
* src/sfnt/sfobjs.c (sfnt_init_face, sfnt_done_face): Handle 'DMAP' table.
* src/sfnt/ttcmap.h (TT_CMap): Add fields `cmap_class` and `dmap`.
Update function declarations.
* src/sfnt/ttcmap.c (tt_cmap14_is_extended, tt_cmap14_get_info): Updated.
(tt_cmap_free, tt_cmap_new, tt_face_add_dmap, tt_cmap_is_variation,
tt_face_find_unicode_dmap, tt_face_find_dmap, tt_cmap_dmap_done,
tt_cmap_dmap_char_index, tt_cmap_dmap_char_next,
tt_cmap_dmap_char_var_index, tt_cmap_dmap_char_var_isdefault,
tt_cmap_dmap_merge, tt_cmap_dmap_variants, tt_cmap_dmap_char_variants,
tt_cmap_dmap_variant_chars, tt_cmap_dmap_get_info): New functions for
'DMAP' support.
(tt_cmap_dmap_class_rec): New cmap class.
(tt_face_build_cmaps): Rename to...
(tt_face_build_cmaps_from_table): ... this and handle both cmap and dmap
data.
(tt_face_build_cmaps, tt_face_expose_dmap, tt_face_build_dmaps,
tt_face_done_dmaps): New functions.
* src/sfnt/ttload.c (tt_face_load_cmap): Also handle 'DMAP' table.
Like format 14, cmap format 15 is a supplemental Unicode variation-sequence
subtable and cannot be selected as the face's ordinary character map.
Assisted-by: OpenAI Codex <noreply@openai.com>
* src/base/ftobjs.c (FT_Set_Charmap, find_unicode_charmap): Implement it.
Read the 24-bit glyph count in the uppercase header and the 24-bit data
offset in each glyph variation record. Prefer 'GVAR' for 'GLYF' outlines
while preserving 'gvar' behavior.
Assisted-by: OpenAI Codex <noreply@openai.com>
* include/freetype/tttags.h (TTAG_GVAR): New macro.
* src/truetype/ttgxvar.h (GX_BlendRec): New field `gvar_is_extended`.
* src/truetype/ttgxvar.c (GX_GVar_Head): Use `FT_UInt32` for `glyphCount`.
(ft_var_load_gvar): Handle 'GVAR' table.
(TT_Vary_Apply_Glyph_Deltas): Updated.
Also check `dataSize`.
Honor the 'GLYF' table's `GID_IS_24_BIT` component flag without changing the
interpretation of the reserved bit in the 'glyf' table.
Assisted-by: OpenAI Codex <noreply@openai.com>
* src/truetype/ttgload.c (GID_IS_24_BIT): New macro.
(TT_Load_Composite_Glyph): Handle it.
Read the 32-bit metric counts in 'HHEA' and 'VHEA', and use their 'HMTX'
and 'VMTX' companions. Keep the wide counts internally while saturating
the legacy public header fields.
Assisted-by: OpenAI Codex <noreply@openai.com>
* include/freetype/internal/tttypes.h (TT_Face): New fields
`horz_metrics_count`, `horz_metrics_is_extended`, `vert_metrics_count`,
`vert_metrics_is_extended`.
* include/freetype/tttags.h (TTAG_HHEA, TTAG_HMTX, TTAG_VHEA, TTAG_VMTX):
New macros.
* src/sfnt/sfobjc.c (sfnt_load_face): Updated.
* src/sfnt/ttload.c (check_table_dir, tt_face_load_font_dir): Updated.
* src/sfnt/ttmtx.c (tt_face_load_hmtx): Updated.
(tt_face_load_hhea): Handle 'HHEA' and 'VHEA' tables.
(tt_face_get_metrics): Updated.
Prefer 'GLYF' and its 'LOCA' companion over the 'glyf' and 'local' tables.
Allow the extended location table to describe more than 65535 glyphs.
Assisted-by: OpenAI Codex <noreply@openai.com>
* include/freetype/internal/tttypes.h (TT_Face): New field `is_extend_glyf`.
* include/freeetype/tttags.h (TTAG_GLYF, TTAG_LOCA): New macros.
* src/sfnt/sfobjs.c (sfnt_init_face): Prefer 'GLYF' over 'glyf' table.
(sfnt_load_face): Updated.
* src/truetype/ttpload.c (tt_face_load_loca): Allow 'GLYF' table.
Read and prefer the extended table-directory offset list in TTC version 1.1
and 2.1 headers. Account for the version 2 DSIG fields before reading the
extended list, and permit an empty legacy compatibility list.
Assisted-by: OpenAI Codex <noreply@openai.com>
* src/sfnt/sfobjs.c (sfnt_open_font): Implement it.
Handle Coverage formats 3 and 4 when looking up VARC base glyphs. These
formats use 24-bit counts, glyph IDs, and coverage indices.
Assisted-by: OpenAI Codex <noreply@openai.com>
* src/truetype/ttvarc.c (tt_varc_get_coverage): Support formats 3 and 4.
Decode PaintGlyph2's 24-bit glyph ID and expose it through the existing
FT_PaintGlyph API. Normalize the result to the existing public PaintGlyph
format, as is already done for the other equivalent COLR paint variants.
Assisted-by: OpenAI Codex <noreply@openai.com>
* src/sfnt/ttcolr.c (FT_PaintFormat_Internal): New value.
`FT_COLR_PAINTFORMAT_INTERNAL_GLYPH2`.
(read_paint): Handle new paint format.
Since commit a69e39ad9, `ft_var_load_gvar` creates a private blend for
fonts with 'gvar' but no 'fvar' (VARC static component axes) and calls
`tt_done_blend` if loading fails afterwards. That function freed the
blend but left `face->blend` pointing to it while the face stays alive,
causing a heap use-after-free on the next access.
Reported as
https://issues.oss-fuzz.com/issues/564162766
* src/truetype/ttgxvar.c (tt_done_blend): Reset `face->blend`.
* src/truetype/ttobjs.c (tt_face_done): Remove now-redundant reset.
Assisted-By: Claude Fable 5.1 <noreply@anthropic.com>
FT_ABS() can overflow for INT_MIN and LONG_MIN, reported as
https://issues.chromium.org/issues/563962723
We introduce and use ULABS() nd UABS() to avoid that.
* include/freetype/internal/ftcalc.h: Add ULABS and UABS.
* src/base/ftcalc.c (FT_Matrix_Check, ft_corner_orientation): Updated.