harfbuzz / harfbuzz/ttf-parser
chore: release 0.26.0
- Dominant language
- Rust
- Stars
- 792
- Forks
- 88
- PR merge metrics
- No merged PRs in 30d
Description
`main` is ready to ship as 0.26.0, but I cannot publish it: I have GitHub `maintain` on this repo, which does not carry crates.io ownership. The crate's owners are @RazrFalcon, @alerque, @LaurenzV and @khaledhosny.
@alerque — could you add me as a crates.io owner (or whichever existing owner is easiest to reach)? I'll follow up with my crates.io handle. That is the only thing standing between the current `main` and a release.
Also flagging this for visibility rather than landing a release unannounced: the backlog was large and some of it is behavioural.
### What is on `main`
14 PRs merged, from 8 contributors, some open for over a year. Tests went 153 -> 196; the suite now runs in both debug and release.
Six of these are denial-of-service fixes against malformed input, with measured impact:
- A 255-byte `CFF` table hung for over 30 seconds. `STACK_LIMIT` bounded subroutine nesting depth but not total invocations, so work grew as fanout^depth.
- 8 bytes of `GSUB` caused a self-referential extension lookup to recurse unboundedly — a stack-overflow abort in debug, an infinite loop in release.
- The same depth-vs-total-work mistake appeared independently in `glyf`/`gvar` composite outlining and in the COLRv1 paint graph.
The pattern is worth naming, because it recurred three times: **a depth limit does not bound total work.** With fan-out `b` and depth `d`, a small font forces `b^d` visits while never exceeding the cap. Each of these now bounds visits, not just depth.
One correctness bug is worth calling out separately: a well-formed 65535-glyph font was rejected outright, `glyf` was dropped, and every outline returned `None` (#226).
### Breaking changes
Four, all listed under `### Changed` in the changelog. The two that produce no compile error, and so need the most visibility:
- `Face::set_variation` now returns `None` for an axis the face does not expose. It previously returned `Some(())` unconditionally, contradicting its own documentation.
- `gvar-alloc` now implies `alloc` rather than `std`, so `default-features = false, features = ["gvar-alloc"]` no longer satisfies the float guard and must select `std` or `no-std-float` explicitly.
### Infrastructure
CI was structurally unable to see some failures. `cargo test --release` was red on `main` and had been for months — a `#[should_panic]` had enshrined a `debug_assert!`, which is compiled out in release. CI ran debug only. Likewise the `c-api` crate's Rust tests had never run in CI at all, because the repo root is not a workspace and a root `cargo test` never reaches it. Both now run, along with the `alloc`-without-`std` feature permutation, which no other leg covered.
MSRV is 1.88 and all four crates are on edition 2024. `CONTRIBUTING.md` did not exist and now does.
Contributor guide
Assessment
This issue has not been assessed yet.