Git Product home page Git Product logo

rust-fontconfig's Introduction

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

rust-fontconfig's People

Contributors

aaron1011 avatar fschutt avatar theapplepiegod avatar zedseven avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

rust-fontconfig's Issues

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

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.

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.