Skip to content

Port resvg to harfrust and fontations#922

Open
nicoburns wants to merge 13 commits into
mainfrom
harfrust
Open

Port resvg to harfrust and fontations#922
nicoburns wants to merge 13 commits into
mainfrom
harfrust

Conversation

@nicoburns

@nicoburns nicoburns commented Jun 11, 2025

Copy link
Copy Markdown
Collaborator

Changes made

  • Replaces rustybuzz with harfrust
  • Replaces ttf_parser with skrifa

Notes

  • This is failing 23 tests. These probably need to be manually checked. I'm waiting on Improve the test harness #954 to investigate these.
  • This requires an MSRV bump from 1.65 to 1.80
  • This will represent a binary size bump for users of resvg.

Production profile

The analysis below uses the following "production" profile:

[profile.production]
inherits = "release"
opt-level = 3
debug = false
lto = true
codegen-units = 1
strip = true
incremental = false

Binary size analysis:

According to cargo-bloat (not the most accurate):

  • harfrust and rustybuzz are both ~250kb
  • ttf_parser and read-fonts are both ~100kb
  • However, ttf_parser includes the metrics outlining functionality of skrifa. And skrifa is another ~250kb.

Compiling the CLI (which is a much more useful test) with the production profile above (cargo build --profile production --bin resvg) I get:

  • 2.4mb for main
  • 2.9mb for this PR

So this PR causes a binary increase of around 500kb

Compile time analysis

Compile times on an M1 Pro (8+2 cores) are shown below (cargo build):

Profile main This PR
debug 4.68s 9.09s
release 7.64s 14.84s
production 24.59s 34.00s

So this PR roughly doubles compile times at regular opt settings
(with the effect being less pronounced with LTO and other production optimisation settings enabled)

@nicoburns nicoburns force-pushed the harfrust branch 2 times, most recently from 02f55d3 to 62c028b Compare June 11, 2025 01:04
@LaurenzV

Copy link
Copy Markdown
Collaborator

Yeah I think we first have to figure out how to deal with fontdb before doing anything with resvg. I don’t think RazrFalcon would want to switch it, and I’m not sure that fontique supports everything we need?

@RazrFalcon

Copy link
Copy Markdown
Collaborator

It's an interesting experiment, but I don't see a point in it. Is there a reason in switching to harfrust?
Last time I have checked it was still a beta, while rustybuzz (with all its faults) is a pretty robust solution.

PS: even if harfrust is faster, it doesn't matter either, because shaping isn't a bottleneck, lack of glyphs caching is.

@RazrFalcon

Copy link
Copy Markdown
Collaborator

Oh wait, it depends on proc-macros/syn?! Burn it with fire! No proc-macros in resvg.

@LaurenzV

Copy link
Copy Markdown
Collaborator

Last time I have checked it was still a beta, while rustybuzz (with all its faults) is a pretty robust solution.

harfrust is rustybuzz, just with ttf-parser switched out by read-fonts. It passes all the same tests, so it should be no less robust than then rustybuzz.

Is there a reason in switching to harfrust?

The reason is that going forward, (most likely) no one will be continually developing ttf-parser/rustybuzz, while harfrust will be actively maintained.

@RazrFalcon

Copy link
Copy Markdown
Collaborator

I would suggest to come back to it in a year. No rush.

And once again, proc-macros are no go. We have to figure out that one as well.

Comment thread .github/workflows/main.yml Outdated
@xStrom

xStrom commented Jun 12, 2025

Copy link
Copy Markdown
Member

Last time I have checked it was still a beta

Not sure about 'beta' type labels, but the first release (0.1.0) of HarfRust happened on June 10, marking a significant milestone.

It's an interesting experiment, but I don't see a point in it. Is there a reason in switching to harfrust?

For an immediate effect, it seems to be far more compliant when tested against the HarfBuzz test suite.

To quote Chad:

We’re still mulling over some public API changes and need to do some serious performance work but this is fully backed by fontations, up to date with HarfBuzz 11.2.1, and passes a significantly larger portion of the HB test suite than RustyBuzz: latest CI shows 5911 tests passing for HarfRust vs 2267 for RustyBuzz.

And the HarfRust introduction post by Behdad contains the following claim:

At the time of this writing, HarfRust passes most of the HarfBuzz shaping test suites, failing just 23 tests out of more than 6,000.


Moving forward, HarfRust will receive active development and continuous sync with HarfBuzz, while RustyBuzz is likely to only see critical fixes.

@RazrFalcon

Copy link
Copy Markdown
Collaborator

latest CI shows 5911 tests passing for HarfRust vs 2267 for RustyBuzz.

Apples and oranges, but sure.

Either way, proc-macros is the current major roadblock.

@mattfbacon

Copy link
Copy Markdown
Contributor

@RazrFalcon Seems like the proc-macros are coming from font-types which uses bytemuck and serde derive macros. Do we want to talk to them about converting to manual implementations?

@RazrFalcon

Copy link
Copy Markdown
Collaborator

@mattfbacon if it's an easy fix - sure.

@mattfbacon

Copy link
Copy Markdown
Contributor

No it wouldn't be at all, since the bytemuck derive macros generate unsafe code so they would need to allow unsafe code back into the codebase.

But what is your plan here? Earlier you said wait, but for what?

@RazrFalcon

Copy link
Copy Markdown
Collaborator

No it wouldn't be at all, since the bytemuck derive macros generate unsafe code so they would need to allow unsafe code back into the codebase.

I would call it easy. It's not like the code deeply depends on proc-macros.

But what is your plan here? Earlier you said wait, but for what?

Adoption, etc. I don't see a point/reason in switching to 0.1. Especially if we would keep ttf-parser around. It just doesn't make any sense.

@Shnatsel

Copy link
Copy Markdown
Contributor

There are derive helpers based on macro_rules! rather than proc macros: https://matx.com/research/rules_derive

It is likely possible to implement an alternative derive for bytemuck traits using such helpers. These can then be published as a separate crate such as bytemuck_derive_lite to avoid any potential backward compatibility issues with the proc macro implementation.

@nicoburns nicoburns force-pushed the harfrust branch 4 times, most recently from e29cfbe to 0973b97 Compare August 31, 2025 11:18
@nicoburns nicoburns changed the title Port resvg to harfrust Port resvg to harfrust and fontations Aug 31, 2025
@nicoburns nicoburns force-pushed the harfrust branch 3 times, most recently from 3c5c998 to c05e2fd Compare August 31, 2025 19:20
@xStrom

xStrom commented Sep 4, 2025

Copy link
Copy Markdown
Member

Is there a reason in switching to harfrust?

As some months have passed another benefit has appeared - performance. In the last month the HarfRust vs HarfBuzz OpenType shaping performance difference has gone from ~4x to ~1.2x, which is a massive boost. Not quite on par with HarfBuzz yet, but getting a lot closer. More importantly for this PR here though, HarfRust is now a lot faster than RustyBuzz.

@Enivex

Enivex commented Sep 10, 2025

Copy link
Copy Markdown

The geometric mean of the last result is ~1.16, meaning Harfrust is now only 16% slower than Harfbuzz.

@behdad

behdad commented Sep 10, 2025

Copy link
Copy Markdown

The geometric mean of the last result is ~1.16, meaning Harfrust is now only 16% slower than Harfbuzz.

It's even better than that. See the comment:
harfbuzz/harfrust#257 (comment)

In short, there's some hb-harfrust overhead included in the spreadsheet number.

@nicoburns nicoburns force-pushed the harfrust branch 2 times, most recently from da2754d to 7e549e1 Compare September 13, 2025 12:17
@dfrg

dfrg commented Feb 5, 2026

Copy link
Copy Markdown

The variable diffs look reasonable to me and likely result from differences in fixed point vs floating point when processing deltas.

@Enivex

Enivex commented Apr 10, 2026

Copy link
Copy Markdown

I don't know what the status of this is, but harfrust 0.6.0 was released today

https://github.com/harfbuzz/harfrust/releases/tag/0.6.0

@nicoburns

Copy link
Copy Markdown
Collaborator Author

harfrust 0.6.0 was released today

Indeed, although it's just a dep bump release.

I don't know what the status of this is

The remaining blocker is switching resvg to use fontique instead of fontdb (see: https://xi.zulipchat.com/#narrow/channel/465085-resvg/topic/Moving.20resvg.20to.20fontations.2Fharfrust/with/572344735). I have some half-baked (not even compiling yet) changes for this locally, but it's unfortunately not top of my priority queue right now.

@Enivex

Enivex commented Apr 10, 2026

Copy link
Copy Markdown

Indeed, although it's just a dep bump release.

The numbering is a bit strange. There were more changes in 0.5.1 and 0.5.2.

Edit: I just realized that you were the one who bumped it 😂

@laurmaedje

Copy link
Copy Markdown
Contributor

The numbering is a bit strange. There were more changes in 0.5.1 and 0.5.2.

Just normal SemVer I would assume. It looks like read_fonts is in the public API of harfrust, so bumping its minor version is a breaking change for harfrust users.

@behdad

behdad commented Jun 5, 2026

Copy link
Copy Markdown

Can we make a move here?

@nicoburns

nicoburns commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator Author

@behdad The latest discussion on this is https://xi.zulipchat.com/#narrow/channel/465085-resvg/topic/Moving.20resvg.20to.20fontations.2Fharfrust/with/572344735.

TLDR is that we need to find a solution for the "font database". Either switching to Fontique (preferred but more work), or porting fontdb to fontations and publishing a fork as we don't control that project (less work, but not ideal to have two "font database" crates on the go).

I have a branch on top of this one (https://github.com/nicoburns/resvg/commits/fontique) that partially moves resvg to fontique. However, that still needs a bunch of design work. Porting fontdb to fontations and publishing it as a fork would definitely be easier/quicker if there is time urgency (I also have a branch for that which only needs minor tweaks - https://github.com/nicoburns/fontdb/tree/fontations)

@LaurenzV

LaurenzV commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

@RazrFalcon are you open to moving fontdb towards read-fonts?

@nicoburns

Copy link
Copy Markdown
Collaborator Author

Just looked at this again, and the "blockers" (things that need to be worked out) for porting to Fontique are:

  • fontdb has unique IDs (64bit Copy type) for every font in the database, and resvg/usvg currently assume that the font database works like this and that one can store an ID (returned from the lookup/query/fallback phase) and then cheaply lookup the actual raw font data using that ID. Fontique doesn't not currently assign fonts a unique ID, and the Collection does not even always have the actual font data (that can sometimes live in the SourceCache).

  • The custom "font resolver" functions that allow users of resvg to customise font querying/fallback will need Fontique versions.

@yisibl

yisibl commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Perhaps we could start by migrating to harfrust, and handle the rest separately.

@behdad How does harfrust compare to rustybuzz in terms of performance currently?

@nicoburns

nicoburns commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator Author

Perhaps we could start by migrating to harfrust, and handle the rest separately.

This is also an option. Just this PR as-is would eliminate rustybuzz from the dependency tree. We'd still have ttf-parser, but that's relatively small.

@behdad

behdad commented Jun 5, 2026

Copy link
Copy Markdown

@behdad How does harfrust compare to rustybuzz in terms of performance currently?

In our measurement, it's multiple times faster on a variety of benchmarks. Benchmarks from last year:

https://docs.google.com/spreadsheets/d/1lyPPZHXIF8gE0Tpx7_IscwhwaZa4KOpdt7vnV0jQT9o/preview

We have improved it more since.

nicoburns added 11 commits June 5, 2026 15:11
Signed-off-by: Nico Burns <nico@nicoburns.com>
Signed-off-by: Nico Burns <nico@nicoburns.com>
Signed-off-by: Nico Burns <nico@nicoburns.com>
Signed-off-by: Nico Burns <nico@nicoburns.com>
Signed-off-by: Nico Burns <nico@nicoburns.com>
Signed-off-by: Nico Burns <nico@nicoburns.com>
Signed-off-by: Nico Burns <nico@nicoburns.com>
Signed-off-by: Nico Burns <nico@nicoburns.com>
Signed-off-by: Nico Burns <nico@nicoburns.com>
@nicoburns

Copy link
Copy Markdown
Collaborator Author

I have:

  • Updated this to Skrifa 0.42 and HarfRust 0.8
  • Rebased on latest main
  • Finished off the fontdb fontations port, and linked this PR to it using a git dep.

@RazrFalcon

Copy link
Copy Markdown
Collaborator

I think fontdb should simply use minimal ttf-parser fork. We need to parse just a couple of fields. ttf-parser become an overkill a long time ago. And read-fonts looks like a way too heavy dependency for that too.

As for repo, I can transfer it to someone. No need for a fork.

Otherwise I'm fine with switching to harfrust. Not like there is a choice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.