rust-fontconfig 0.1.7

Minimal dependency, pure-Rust alternative to font-loader and servo-fontconfig
Documentation
# 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]https://azul.rs 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]https://github.com/maps4print/azul/issues/110)
- libfontconfig introduces build issues with cmake / cc
  ([see issue]https://github.com/maps4print/azul/issues/206)
- 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

```rust
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