Skip to main content

A font compiler written in Rust.

Project description

CI Status Crates.io

fontc

Wherein we pursue oxidizing fontmake. For context around where fontmake came from see Mr B goes to Vartown.

Converts source to IR, and then IR to font binary. Aims to be safe and fast.

References

  • Intermediate Representation (IR)
  • Editor perspective note from Just
  • Units
    • Fonts have all the best units; distinguishing between them turns out to matter.

But why?

Two main reasons:

  1. Speed
    • The python compiler is too slow and we don't think we can plausibly make it fast enough
  2. A key part of Google Fonts technical strategy is to get off both Python and C++, consolidating on Rust

So, Rust compiler time!

image

(https://xkcd.com/303/ remix)

Are we there yet?

https://googlefonts.github.io/fontc_crater/ tracks our progress in making the new compiler match the old one.

Getting started

Install the latest version of Rust, https://www.rust-lang.org/tools/install.

Build a simple test font

$ cargo run -p fontc -- resources/testdata/wght_var.designspace

Emit IR

If you pass the --emit-ir option, the IR will be written to disk inside the build working directory. This can be helpful when troubleshooting.

$ cargo run -p fontc -- --emit-ir resources/testdata/wght_var.designspace
$ ls build/

Sources to play with

Google Fonts has lots, you could try https://github.com/rsheeter/google_fonts_sources to get some. Once you have them you could try building them:

cargo run --package fontc -- ../google_fonts_sources/sources/ofl/notosanskayahli/sources/NotoSansKayahLi.designspace

Building lots of fonts at once

There is an included fontc_crater tool that can download and compile multiple fonts at once; this is used for evaluating the compiler. For more information, see fontc_crater/README.md.

Plan

As of 6/4/2023 we intend to:

  • Get to the point where Oswald compilation matches fontmake
  • Get to the point where ever more of the families for which we have source compile to a form that matches fontmake, or differs only in well understood ways
  • Provide a Glyphs plugin to allow push-button use of the new compiler
  • Once there are no known issues, switch Google Fonts to exclusively use fontc

We are discarding our prior plan to make fontmake (Python) call into Rust as it appears to be more complex than initially anticipated and higher risk than migrating on a per-family basis.

For context see https://github.com/googlefonts/oxidize/blob/main/text/2022-07-25-PROPOSAL-build-glyphs-in-rust.md and the discussion on https://github.com/googlefonts/oxidize/pull/33.

Using a local copy of fontations

It is quite common to find we need changes in https://github.com/googlefonts/fontations to add a feature or fix a bug. Prior to a release being available modify the root Cargo.toml to point to either a local clone or a branch:

# Local copy
[patch.crates-io]
font-types =  { path = "../fontations/font-types" }
read-fonts =  { path = "../fontations/read-fonts" }
write-fonts = { path = "../fontations/write-fonts" }
skrifa =  { path = "../fontations/skrifa" }

# Branch
[patch.crates-io]
font-types = { git="https://github.com/googlefonts/fontations.git", branch="box" }
read-fonts = { git="https://github.com/googlefonts/fontations.git", branch="box" }
write-fonts = { git="https://github.com/googlefonts/fontations.git", branch="box" }
skrifa = { git="https://github.com/googlefonts/fontations.git", branch="box" }

Dependency map

Shows the non-dev dependency relationships among the crates in the repo.

%% This is a map of non-dev font-related dependencies.
%% See https://mermaid.live/edit for a lightweight editing environment for
%% mermaid diagrams.
graph
    %% First we define the nodes and give them short descriptions.
    %% We group them into subgraphs by repo so that the visual layout
    %% maps to the source layout, as this is intended for contributors.

   fontc{{fontc\nCLI font compiler}}
   fontra2fontir[fontra2fontir\nconverts .fontra files to our IR]
   glyphs2fontir[glyphs2fontir\nconverts .glyphs files to our IR]
   ufo2fontir[ufo2fontir\nconverts from a \n.designspace to our IR]
   fontir[fontir\nthe IR for fontc]
   fontbe[fontbe\nthe backend of font compilation\nIR -> binary font]
   fea-rs[fea-rs\nParses and compiles\nAdobe OpenType feature files]
   fontdrasil[fontdrasil\nCommon types and functionality\nshared between all layers of fontc]

    %% Now define the edges.
    %% Made by hand on March 20, 2024, probably not completely correct.
    %% Should be easy to automate if we want to, main thing is to
    %% define the crates of interest.
    fontbe --> fontir
    fontbe --> fea-rs
    fontc --> fontbe
    fontc --> fontir
    fontc --> glyphs2fontir
    fontc --> fontra2fontir
    fontc --> ufo2fontir
    fontra2fontir --> fontir
    glyphs2fontir --> fontir
    ufo2fontir --> fontir

Comparing branch performance with hyperfine

Only relatively large changes are effectively detected this way:

To compare current branch to main when building Oswald:

$ hyperfine \
  --parameter-list branch main,$(git rev-parse --abbrev-ref HEAD) \
  --setup "git checkout {branch} && cargo build --release" \
   --warmup 5 --runs 250 \
   --prepare 'rm -rf build/' \
   "target/release/fontc --source ../OswaldFont/sources/Oswald.glyphs"

...noise...

Summary
  target/release/fontc --source ../OswaldFont/sources/Oswald.glyphs (branch = nocs) ran
    1.09 ± 0.09 times faster than target/release/fontc --source ../OswaldFont/sources/Oswald.glyphs (branch = main)

# Yay, it seems to be faster!

Running samply

https://github.com/mstange/samply gives a nice call tree, flame graph, etc. Sample usage:

# Assuming current directory is the root of fontc
$ (cd .. && git clone https://github.com/mstange/samply)
$ (cd ../samply && cargo build --release)
$ ../samply/target/release/samply record target/release/fontc ../OswaldFont/sources/Oswald.glyphs

Running flamegraph

flamegraphs of fontc are very handy. They are most easily created using cargo flamegraph:

# Minimize the impact of logging
$ export RUST_LOG=error
# Symbols are nice, https://github.com/flamegraph-rs/flamegraph#improving-output-when-running-with---release
$ export CARGO_PROFILE_RELEASE_DEBUG=true

# Build something and capture a flamegraph of it
$ rm -rf build/ perf.data flamegraph.svg && cargo flamegraph -p fontc -- ../OswaldFont/sources/Oswald.glyphs

# TIPS

# On macOS you might have to pass `--root` to cargo flamegraph, e.g. cargo flamegraph --root ...as above...

# If you are losing samples you might want to dial down the rayon threadcount
# You'll see a perf error similar to:
Warning:
Processed 5114 events and lost 159 chunks!

Check IO/CPU overload!

Warning:
Processed 5116 samples and lost 35.01%!

# Fix is to lower the threadcount:
$ export RAYON_NUM_THREADS=16

Focused flames

https://blog.anp.lol/rust/2016/07/24/profiling-rust-perf-flamegraph/ offers examples of filtering flamegraphs. This is very useful when you want to zoom in on a specific operation. For example, to dig into fea-rs:

# Generate a perf.data
# You can also use perf record but cargo flamegraph seems to have nice capture settings for Rust rigged
$ rm -rf build/ perf.data flamegraph.svg && cargo flamegraph -p fontc -- ../OswaldFont/sources/Oswald.glyphs

# ^ produced flamegraph.svg but it's very noisy, lets narrow our focus
# Example assumes https://github.com/brendangregg/FlameGraph is cloned in a sibling directory to fontc
$ perf script | ../FlameGraph/stackcollapse-perf.pl | grep fea_rs | ../FlameGraph/flamegraph.pl > fea-flame.svg

Contributing

We have included a few git hooks that you may choose to use to ensure that patches will pass CI; these are in resources/githooks.

To run the pre-push step manually:

$ ./resources/githooks/pre-push

If you would like to have these run automatically when you commit or push changes, you can set this as your git hooksPath:

$ git config core.hooksPath "resources/githooks"

Releasing

See https://github.com/googlefonts/fontations#releasing

To update the Glyphs plugin see https://github.com/googlefonts/fontc-export-plugin.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fontc-0.6.0.tar.gz (1.7 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

fontc-0.6.0-py3-none-win_amd64.whl (6.5 MB view details)

Uploaded Python 3Windows x86-64

fontc-0.6.0-py3-none-win32.whl (6.1 MB view details)

Uploaded Python 3Windows x86

fontc-0.6.0-py3-none-musllinux_1_1_x86_64.whl (7.6 MB view details)

Uploaded Python 3musllinux: musl 1.1+ x86-64

fontc-0.6.0-py3-none-musllinux_1_1_aarch64.whl (7.3 MB view details)

Uploaded Python 3musllinux: musl 1.1+ ARM64

fontc-0.6.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (7.4 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

fontc-0.6.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (7.3 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

fontc-0.6.0-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (14.1 MB view details)

Uploaded Python 3macOS 10.12+ universal2 (ARM64, x86-64)macOS 10.12+ x86-64macOS 11.0+ ARM64

File details

Details for the file fontc-0.6.0.tar.gz.

File metadata

  • Download URL: fontc-0.6.0.tar.gz
  • Upload date:
  • Size: 1.7 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for fontc-0.6.0.tar.gz
Algorithm Hash digest
SHA256 6c848ad7d49c252fbb1abf953a7c0402aeb6ac4943d4304d7809c16532ffe481
MD5 b3b72d5d5507688fb159d293df3cd08e
BLAKE2b-256 6dd79d1cd92c0e89907b4176ead4fba6a2744d1946bd05deddb2654926e711cb

See more details on using hashes here.

Provenance

The following attestation bundles were made for fontc-0.6.0.tar.gz:

Publisher: release.yml on googlefonts/fontc

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fontc-0.6.0-py3-none-win_amd64.whl.

File metadata

  • Download URL: fontc-0.6.0-py3-none-win_amd64.whl
  • Upload date:
  • Size: 6.5 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for fontc-0.6.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 2fb6c347d1fae38f57236eb0ecd42e6a65e35a6dec75ebe3ff98f600abd55766
MD5 dc36d2d9298e69a6781e46cf6ccf2b9a
BLAKE2b-256 b7cc58501ce075061fba7992e574524d35c0e108f1c10c5e66ad31a35c49c926

See more details on using hashes here.

Provenance

The following attestation bundles were made for fontc-0.6.0-py3-none-win_amd64.whl:

Publisher: release.yml on googlefonts/fontc

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fontc-0.6.0-py3-none-win32.whl.

File metadata

  • Download URL: fontc-0.6.0-py3-none-win32.whl
  • Upload date:
  • Size: 6.1 MB
  • Tags: Python 3, Windows x86
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for fontc-0.6.0-py3-none-win32.whl
Algorithm Hash digest
SHA256 aab69ac89c24623ba230e43ebb8de0d033f9b4831c7af0a5b6aee66b5a1dd8e5
MD5 9f512adaec3a02460d2a7c7296710747
BLAKE2b-256 b6b01dd4f7c3324a49572f5f80d7a3f9fab952c414e266b82bbd4b68d2867206

See more details on using hashes here.

Provenance

The following attestation bundles were made for fontc-0.6.0-py3-none-win32.whl:

Publisher: release.yml on googlefonts/fontc

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fontc-0.6.0-py3-none-musllinux_1_1_x86_64.whl.

File metadata

File hashes

Hashes for fontc-0.6.0-py3-none-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 9f567110d42b24f7e6434e5c4da72f87c10b7309fe1229dac6720077e8fc3dc4
MD5 69e604be38ee1e1dbc11a713d1f47c87
BLAKE2b-256 18199e88593c17c2dcf460aa11f4ebf9602a73b703ffd44aa4bf09608e60f753

See more details on using hashes here.

Provenance

The following attestation bundles were made for fontc-0.6.0-py3-none-musllinux_1_1_x86_64.whl:

Publisher: release.yml on googlefonts/fontc

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fontc-0.6.0-py3-none-musllinux_1_1_aarch64.whl.

File metadata

File hashes

Hashes for fontc-0.6.0-py3-none-musllinux_1_1_aarch64.whl
Algorithm Hash digest
SHA256 cf60dc2f8f0710cf34b516c5a7d372b58f998d22024ac10066da43d09378a443
MD5 adf116c83965bf729d4bd6b89fb84d8b
BLAKE2b-256 c8f895efb335557e033df502828a1dce138da4cf8ee21486c37d0ae324fdd3e3

See more details on using hashes here.

Provenance

The following attestation bundles were made for fontc-0.6.0-py3-none-musllinux_1_1_aarch64.whl:

Publisher: release.yml on googlefonts/fontc

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fontc-0.6.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for fontc-0.6.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 b2994df428fa234d8d4be5fa34f1e44320b3c31e979c7b949edaceb42582a8cb
MD5 7f15cd8435e0ac46e8f804fa690d7a2d
BLAKE2b-256 56fbf8a0413dafd34c15237885493aa1bce80701d41c02056cce2f19479251a7

See more details on using hashes here.

Provenance

The following attestation bundles were made for fontc-0.6.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on googlefonts/fontc

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fontc-0.6.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for fontc-0.6.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 32ba2c97d65da2172194fd05cf133fd8ccb4e0fd486ea78153811271c4262c98
MD5 fad95fc9b85412872b72ab09cbae6f65
BLAKE2b-256 9b301983c04c531703ace977ee08a23951e7a2767345d90e7e6c12d94989a4dd

See more details on using hashes here.

Provenance

The following attestation bundles were made for fontc-0.6.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on googlefonts/fontc

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fontc-0.6.0-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl.

File metadata

File hashes

Hashes for fontc-0.6.0-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 7196421f575a42b4dd288648748ce050970821cbd7ad820943ae36bc32931d6b
MD5 1e280e928f1b9bbda083f0d1b92fa7d4
BLAKE2b-256 1aa3e85b572ef3cebda13da831a1508c4a8c1d8133b77cb1863c8901bdb0b944

See more details on using hashes here.

Provenance

The following attestation bundles were made for fontc-0.6.0-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl:

Publisher: release.yml on googlefonts/fontc

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page