Skip to main content

A compiler for fonts.

Project description

fontc

Where in we pursue oxidizing (context: https://github.com/googlefonts/oxidize) 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, incremental, 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?

image

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

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 to enable incremental builds

If you pass the --incremental (or -i) option, the IR will be written to disk inside the build working directory, so that the next time you run fontc with the same source file only what changed will be rebuilt.

$ cargo run -p fontc -- --incremental 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

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:

# On each branch, typically main and your branch run hyperfine:
$ cargo build --release && hyperfine --warmup 3 --runs 250 --prepare 'rm -rf build/' 'target/release/fontc ../OswaldFont/sources/Oswald.glyphs'

# Ideally mean+σ of the improved branch is < mean-σ for main.
# For example, p2s is probably faster here:
# main Time (mean ± σ):     154.8 ms ±   8.2 ms
# p2s Time (mean ± σ):     132.7 ms ±   6.4 ms

# Report similar to ^ if claiming this as proof your branch is a win.

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/ && 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 && 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

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.0.1.tar.gz (1.2 MB view details)

Uploaded Source

Built Distributions

fontc-0.0.1-py3-none-win_amd64.whl (4.9 MB view details)

Uploaded Python 3 Windows x86-64

fontc-0.0.1-py3-none-win32.whl (4.6 MB view details)

Uploaded Python 3 Windows x86

fontc-0.0.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (6.6 MB view details)

Uploaded Python 3 manylinux: glibc 2.17+ ARM64

fontc-0.0.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl (6.6 MB view details)

Uploaded Python 3 manylinux: glibc 2.17+ ARM64 musllinux: musl 1.1+ ARM64

fontc-0.0.1-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl (6.8 MB view details)

Uploaded Python 3 manylinux: glibc 2.12+ x86-64 musllinux: musl 1.1+ x86-64

fontc-0.0.1-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl (6.8 MB view details)

Uploaded Python 3 manylinux: glibc 2.5+ x86-64

fontc-0.0.1-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (10.8 MB view details)

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

File details

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

File metadata

  • Download URL: fontc-0.0.1.tar.gz
  • Upload date:
  • Size: 1.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.0.0 CPython/3.11.0

File hashes

Hashes for fontc-0.0.1.tar.gz
Algorithm Hash digest
SHA256 54b8bc0fa35e6010ac8bc61ea92b78103038f46c82d42f7c0e140e061380bd97
MD5 ecb51df02eb7f13c38ebee83eccc0e1e
BLAKE2b-256 75506f413db3254ddf84d63b4124380846b6097be043e96f005b789431b340a2

See more details on using hashes here.

File details

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

File metadata

  • Download URL: fontc-0.0.1-py3-none-win_amd64.whl
  • Upload date:
  • Size: 4.9 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.0.0 CPython/3.11.0

File hashes

Hashes for fontc-0.0.1-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 97a17e559a9320b673eb41ca7efc9f4d45b78bdfcfd843a527e279c62cf9539e
MD5 4724d21a9faea14e048bfa1aadff35ed
BLAKE2b-256 41b8cda7986ece09fa664bf5323440235f98531c03661cb3fb961ad23695186f

See more details on using hashes here.

File details

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

File metadata

  • Download URL: fontc-0.0.1-py3-none-win32.whl
  • Upload date:
  • Size: 4.6 MB
  • Tags: Python 3, Windows x86
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.0.0 CPython/3.11.0

File hashes

Hashes for fontc-0.0.1-py3-none-win32.whl
Algorithm Hash digest
SHA256 27e506974d6fcce9ab88f8d740d087d509a78119c63cc87de5ac27c54d6713d0
MD5 e9eaaf159a7625018b8b5953dbeb1523
BLAKE2b-256 51f346dee908227886dd5e67871f8868b54d2014acf93b35828015740f1519b9

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for fontc-0.0.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 237ab9b09e8b9797547e162fa4ac0eb4e600e4dc20c1b114e70bd0800dc569c4
MD5 da8229eb2dffc03d339f02b6dcbbbf10
BLAKE2b-256 cfea0ca7ff58354905dc7b61f2d868a4bc40f95cef2ae7de85d69e57b14cb059

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for fontc-0.0.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl
Algorithm Hash digest
SHA256 8f0ef0503fc618ed88cc6b0535e7ebef487e518146e57ec2c953bd0c92615910
MD5 430f29436a891ef480714c0827738a68
BLAKE2b-256 ed2c0b38b2ac6c0f0faab7476ab20f5705ceba78dd5885f7b3ee6caee7fc20b2

See more details on using hashes here.

File details

Details for the file fontc-0.0.1-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl.

File metadata

File hashes

Hashes for fontc-0.0.1-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 e0d0b2bf27789fb39ef2fd7af36c9506419b267cb152736886d7d3dbfcefd2b7
MD5 8c605bdba9580e94b0b33fbc214e1966
BLAKE2b-256 09bc586d2b37ba70482a7c543ad3373c8c80f4296bf0dd330f637dc543da5321

See more details on using hashes here.

File details

Details for the file fontc-0.0.1-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl.

File metadata

File hashes

Hashes for fontc-0.0.1-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 638d6405ebd019836f9bf0131b717d719c0e21a6bd9e5ee70154ad4900d50cfe
MD5 98e8b61bb15f6640168ffe0d32245165
BLAKE2b-256 6c9e971ee2458334673c1bdf3891d27e9e043ff750c33fbea08e405b20f5cd83

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for fontc-0.0.1-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 bb2eab57a2bb9d3d7720cb8f72f8a9d109acf4997d1e33e2baa4e1f3eb992909
MD5 b9fe5753467371632d3ce9712c1437d2
BLAKE2b-256 3163ccd67e84df60211145c22255570a675942dc9517b0387d381f9546c5fb2f

See more details on using hashes here.

Supported by

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