Pure-Rust rewrite of the Linux fontconfig library (no system dependencies) - using ttf-parser and allsorts

Overview

rust-fontconfig

Pure-Rust rewrite of the Linux fontconfig library (no system dependencies) - using allsorts as a font parser in order to parse .woff, .woff2, .ttc, .otf and .ttf

NOTE: Also works on Windows and macOS - without external dependencies!

Motivation

There are a number of reasons why I want to have a pure-Rust version of fontconfig:

  • fontconfig with all dependencies (expat and freetype) is ~190.000 lines of C (extremely bloated for what it does)
  • fontconfig, freetype, expat and basically any kind of parsing in C is a common attack vector (via maliciously crafted fonts). The Rust version (allsorts) checks the boundaries before accessing memory, so attacks via font files should be less common.
  • it gets rid of the cmake / cc dependencies necessary to build azul on Linux
  • fontconfig isn't really a "hard" library to rewrite, it just parses fonts and selects fonts by name
  • Rust has existing xml parsers and font parsers, just use those
  • It allows fontconfig libraries to be purely statically linked
  • Font parsing / loading can be easily multithreaded (parsing font files in parallel)
  • It reduces the number of necessary non-Rust dependencies on Linux for azul to 0
  • fontconfig (or at least the Rust bindings) do not allow you to store an in-memory cache, only an on-disk cache, requiring disk access on every query (= slow)
  • Potential no_std support for minimal binaries?

Now for the more practical reasons:

  • libfontconfig 0.12.x sometimes hangs and crashes (see issue)
  • libfontconfig introduces build issues with cmake / cc (see issue)
  • To support font fallback in CSS selectors and text runs based on Unicode ranges, you have to do several calls into C, since fontconfig doesn't handle that
  • The rust rewrite uses multithreading and memory mapping, since that is faster than reading each file individually
  • The rust rewrite only parses the font tables necessary to select the name, not the entire font
  • The rust rewrite uses very few allocations (some are necessary because of UTF-16 / UTF-8 conversions and multithreading lifetime issues)

Usage

use rust_fontconfig::{FcFontCache, FcPattern};

fn main() {
    let cache = FcFontCache::build(); let result =

    cache.query(&FcPattern {
      name: Some(String::from("Arial")),
      .. Default::default()
    });

    println!("font path: {:?}", result);
}

Performance

  • cache building: ~90ms for ~530 fonts
  • cache query: ~4µs

License

MIT

You might also like...
🦀 Temporary repository for the rewrite of Smoothie in Rust

Warning As with a lot of projects, this one is also a WIP, expect broken code 👍 smoothie-rs Temporary repository hosting the code for Smoothie's futu

Pulls the C/C++ library linking flags from Conan dependencies

conan2-rs Introduction conan2-rs is a Cargo build script wrapper of the Conan C/C++ package manager (version 2.0 only). It automatically pulls the C/C

 Cover your tracks during Linux Exploitation by leaving zero traces on system logs and filesystem timestamps.
Cover your tracks during Linux Exploitation by leaving zero traces on system logs and filesystem timestamps.

moonwalk-back Cover your tracks during Linux Exploitation / Penetration Testing by leaving zero traces on system logs and filesystem timestamps. 📖 Ta

A system fetch tool for Linux, written in Rust.
A system fetch tool for Linux, written in Rust.

fetchit A system fetch tool for Linux, written in Rust. fetchit is a simple system info tool, written in Rust, for Linux based operating systems. It o

Shell Escape for Typst typesetting system. Linux Only.

Shell Escape for Typst This is a simple shell escape for Typst. It allows you to run shell commands directly from Typst compiler. That said, it does n

An interruption-free notification system for Linux

nofi A Rofi-driven notification manager rofi.mp4 nofi is a distraction-free notification center. While most notification daemons make immediate popups

Rust low-level minimalist APNG writer and PNG reader with just a few dependencies with all possible formats coverage (including HDR).

project Wiki https://github.com/js29a/micro_png/wiki at glance use micro_png::*; fn main() { // load an image let image = read_png("tmp/test.

This utility traverses through your filesystem looking for open-source dependencies that are seeking donations by parsing README.md and FUNDING.yml files
This utility traverses through your filesystem looking for open-source dependencies that are seeking donations by parsing README.md and FUNDING.yml files

This utility traverses through your filesystem looking for open-source dependencies that are seeking donations by parsing README.md and FUNDING.yml files

Cucumber testing framework for Rust. Fully native, no external test runners or dependencies.
Cucumber testing framework for Rust. Fully native, no external test runners or dependencies.

Cucumber testing framework for Rust An implementation of the Cucumber testing framework for Rust. Fully native, no external test runners or dependenci

Comments
  • Use 'allsorts' instead of 'allsorts_no_std'

    Use 'allsorts' instead of 'allsorts_no_std'

    The 'allsorts_no_std' fork is unmaintained. It was only used inside 'cfg(feature = 'std")', so the fact that 'allsorts' depends on libstd won't cause any changes for consumers of this library.

    opened by Aaron1011 1
  • Monospace search doesn't work

    Monospace search doesn't work

    The following code fails at the second assertion:

    let cache = FcFontCache::build();
    
    assert!(cache
        .query(&FcPattern {
            name: Some("DejaVu Sans Mono".into()),
            ..Default::default()
        })
        .is_none());
    
    assert!(cache
        .query(&FcPattern {
            monospace: PatternMatch::True,
            ..Default::default()
        })
        .is_some());
    

    Is it an expected behavior?

    Also seems the issue related to #3

    opened by l4l 2
  • Scope / plan?

    Scope / plan?

    The README claims this is "Pure-Rust rewrite of the Linux fontconfig library" and "Also works on Windows and macOS". But it's not fontconfig.

    Fontconfig does quite a bit: not just locating font files, but matching fonts from generic or specific family names, with name alias rules, fallback fonts for non-latin glyphs, matching based on language, and even some configuration of rendering (not sure if that's still used today).

    This library currently only enumerates font files, extracts some basic properties, and does basic matching (not even implementing CSS matching rules).

    So, what is the planned scope? A more complete re-implementation of fontconfig including matching/aliases/fallbacks could be really useful.

    opened by dhardy 1
  • Properties: doesn't detect monospace / oblique / condensed?

    Properties: doesn't detect monospace / oblique / condensed?

    On my system this lib detects 194 fonts. Of these:

    • The "bold" property appears to be detected correctly
    • "italic" is set true for any "oblique" font while the "oblique" property is always DontCare (to be honest I'm not sure what behaviour is expected here)
    • The "monospace" property is always DontCare
    • Some fonts are "condensed"; the lib has no property for this

    I was considering how to select fonts using CSS-like properties (as in font-kit, implemented here and here). It appears that currently not enough properties are detected to do this. Are you planning on adding selection/matching logic?

    Example: the DejaVu family:

    name | family | italic | oblique | bold | monospace | path | index -- | -- | -- | -- | -- | -- | -- | -- DejaVu Sans | DejaVu Sans | FALSE | DontCare | FALSE | DontCare | /usr/share/fonts/dejavu-sans-fonts/DejaVuSans.ttf | 0 DejaVu Sans Bold | DejaVu Sans | FALSE | DontCare | TRUE | DontCare | /usr/share/fonts/dejavu-sans-fonts/DejaVuSans-Bold.ttf | 0 DejaVu Sans Bold Oblique | DejaVu Sans | TRUE | DontCare | TRUE | DontCare | /usr/share/fonts/dejavu-sans-fonts/DejaVuSans-BoldOblique.ttf | 0 DejaVu Sans Condensed | DejaVu Sans Condensed | FALSE | DontCare | FALSE | DontCare | /usr/share/fonts/dejavu-sans-fonts/DejaVuSansCondensed.ttf | 0 DejaVu Sans Condensed Bold | DejaVu Sans Condensed | FALSE | DontCare | TRUE | DontCare | /usr/share/fonts/dejavu-sans-fonts/DejaVuSansCondensed-Bold.ttf | 0 DejaVu Sans Condensed Bold Oblique | DejaVu Sans Condensed | TRUE | DontCare | TRUE | DontCare | /usr/share/fonts/dejavu-sans-fonts/DejaVuSansCondensed-BoldOblique.ttf | 0 DejaVu Sans Condensed Oblique | DejaVu Sans Condensed | TRUE | DontCare | FALSE | DontCare | /usr/share/fonts/dejavu-sans-fonts/DejaVuSansCondensed-Oblique.ttf | 0 DejaVu Sans ExtraLight | DejaVu Sans Light | FALSE | DontCare | FALSE | DontCare | /usr/share/fonts/dejavu-sans-fonts/DejaVuSans-ExtraLight.ttf | 0 DejaVu Sans Mono | DejaVu Sans Mono | FALSE | DontCare | FALSE | DontCare | /usr/share/fonts/dejavu-sans-mono-fonts/DejaVuSansMono.ttf | 0 DejaVu Sans Mono Bold | DejaVu Sans Mono | FALSE | DontCare | TRUE | DontCare | /usr/share/fonts/dejavu-sans-mono-fonts/DejaVuSansMono-Bold.ttf | 0 DejaVu Sans Mono Bold Oblique | DejaVu Sans Mono | TRUE | DontCare | TRUE | DontCare | /usr/share/fonts/dejavu-sans-mono-fonts/DejaVuSansMono-BoldOblique.ttf | 0 DejaVu Sans Mono Oblique | DejaVu Sans Mono | TRUE | DontCare | FALSE | DontCare | /usr/share/fonts/dejavu-sans-mono-fonts/DejaVuSansMono-Oblique.ttf | 0 DejaVu Sans Oblique | DejaVu Sans | TRUE | DontCare | FALSE | DontCare | /usr/share/fonts/dejavu-sans-fonts/DejaVuSans-Oblique.ttf | 0 DejaVu Serif | DejaVu Serif | FALSE | DontCare | FALSE | DontCare | /usr/share/fonts/dejavu-serif-fonts/DejaVuSerif.ttf | 0 DejaVu Serif Bold | DejaVu Serif | FALSE | DontCare | TRUE | DontCare | /usr/share/fonts/dejavu-serif-fonts/DejaVuSerif-Bold.ttf | 0 DejaVu Serif Bold Italic | DejaVu Serif | TRUE | DontCare | TRUE | DontCare | /usr/share/fonts/dejavu-serif-fonts/DejaVuSerif-BoldItalic.ttf | 0 DejaVu Serif Condensed | DejaVu Serif Condensed | FALSE | DontCare | FALSE | DontCare | /usr/share/fonts/dejavu-serif-fonts/DejaVuSerifCondensed.ttf | 0 DejaVu Serif Condensed Bold | DejaVu Serif Condensed | FALSE | DontCare | TRUE | DontCare | /usr/share/fonts/dejavu-serif-fonts/DejaVuSerifCondensed-Bold.ttf | 0 DejaVu Serif Condensed Bold Italic | DejaVu Serif Condensed | TRUE | DontCare | TRUE | DontCare | /usr/share/fonts/dejavu-serif-fonts/DejaVuSerifCondensed-BoldItalic.ttf | 0 DejaVu Serif Condensed Italic | DejaVu Serif Condensed | TRUE | DontCare | FALSE | DontCare | /usr/share/fonts/dejavu-serif-fonts/DejaVuSerifCondensed-Italic.ttf | 0 DejaVu Serif Italic | DejaVu Serif | TRUE | DontCare | FALSE | DontCare | /usr/share/fonts/dejavu-serif-fonts/DejaVuSerif-Italic.ttf | 0

    opened by dhardy 3
Owner
Felix Schütt
Felix Schütt
Cold Clear 2 is a modern Tetris versus bot and a complete rewrite and evolution of Cold Clear.

Cold Clear 2 Cold Clear 2 is a modern Tetris versus bot and a complete rewrite and evolution of Cold Clear. It implements the Tetris Bot Protocol for

Mark Carlson 27 Dec 28, 2022
TMM is a Linux native game modding tool. it allows to install and depoly mods for Linux native and wine games.

Tux Mod Manager TMM is a Linux native mod manager made with the Tauri toolkit. It can install, load, remove and deploy mods for both Linux native and

Mathiew May 119 Dec 27, 2022
XP rust rewrite "v8" with serenity, focused on maintainability, stability and performance.

XP v8 The official XP v8 rewrite built with Rust and serenity-rs. Contributions We're always looking for contributors! If you want to contribute, plea

XP Discord Bot 3 Aug 28, 2023
A language parser tool to build recursive descent top down parser.

lang-pt A language parser tool to generate recursive descent top down parser. Overview Parsers written for the languages like Javascript are often cus

Creative Forest 7 Jan 4, 2023
A CLI tool that allow you to create a temporary new rust project using cargo with already installed dependencies

cargo-temp A CLI tool that allow you to create a new rust project in a temporary directory with already installed dependencies. Install Requires Rust

Yohan Boogaert 61 Oct 31, 2022
A complete imgui-rs example using dependencies only from crates.io.

Dear imgui-rs, hello. This is a fairly basic, but complete and standalone example application for the Rust version of dear imgui (https://github.com/o

null 0 Nov 30, 2022
Rust library to convert RGB 24-bit colors into ANSI 256 (8-bit) color codes with zero dependencies and at compile-time.

rgb2ansi256 rgb2ansi256 is a small Rust library to convert RGB 24-bit colors into ANSI 256 (8-bit) color codes with zero dependencies and const fn. Th

Linda_pp 7 Nov 17, 2022
A simple Rust library for OpenAI API, free from complex async operations and redundant dependencies.

OpenAI API for Rust A community-maintained library provides a simple and convenient way to interact with the OpenAI API. No complex async and redundan

null 6 Apr 4, 2023
Cross-platform Rust rewrite of the GNU coreutils

Cross-platform Rust rewrite of the GNU coreutils

null 13k Jan 8, 2023
rewrite of hosts-creator in rust

hc-rs -> hosts-creator-rust fetch and merge multiple hosts files this is a WIP whats done fetching hosts files merging hosts files removing duplicate

null 2 Nov 20, 2022