8 个版本
0.1.7 | 2024 年 1 月 18 日 |
---|---|
0.1.6 | 2023 年 4 月 28 日 |
0.1.5 | 2021 年 4 月 18 日 |
0.1.3 | 2021 年 3 月 6 日 |
0.1.2 | 2021 年 2 月 28 日 |
#103 in GUI
832 每月下载量
用于 bestool
25KB
490 行
rust-fontconfig
Linux fontconfig 库的纯 Rust 重写(无系统依赖) - 使用 allsorts 作为字体解析器来解析 .woff
、.woff2
、.ttc
、.otf
和 .ttf
注意:也适用于 Windows 和 macOS - 无外部依赖!
动机
我有几个原因想要拥有一个纯 Rust 版本的 fontconfig
- 带有所有依赖的 fontconfig(expat 和 freetype)大约有 190,000 行 C 代码(对于其功能来说过于庞大)
- fontconfig、freetype、expat 以及基本上任何 C 中的解析都是一个常见的攻击向量(通过恶意制作的字体)。Rust 版本(allsorts)在访问内存之前检查边界,因此通过字体文件进行的攻击应该更少。
- 它消除了在 Linux 上构建 azul 所需的 cmake / cc 依赖
- fontconfig 实际上不是一个“硬”库来重写,它只是解析字体并根据名称选择字体
- Rust 有现有的 xml 解析器和字体解析器,只需使用它们即可
- 它允许 fontconfig 库完全静态链接
- 字体解析/加载可以很容易地进行多线程(并行解析字体文件)
- 它将 azul 在 Linux 上所需的非 Rust 依赖项数量减少到 0
- fontconfig(或至少 Rust 绑定)不允许你存储内存缓存,只能存储磁盘缓存,每次查询都需要磁盘访问(较慢)
- 是否有潜在的对
no_std
的支持,以生成最小二进制文件?
现在来说一些更实际的原因
- libfontconfig 0.12.x 有时会出现挂起和崩溃(查看问题)
- libfontconfig 与 cmake / cc 引入了构建问题(查看问题)
- 为了支持基于 Unicode 范围的 CSS 选择器和文本运行中的字体回退,你必须对 C 进行多次调用,因为 fontconfig 无法处理该功能
- Rust 重写使用多线程和内存映射,因为这样可以比逐个读取文件更快
- Rust 重写只解析选择名称所需的字体表,而不是整个字体
- 该Rust重写版本使用的分配非常少(一些是必要的,因为涉及UTF-16/UTF-8转换和多线程生命周期问题)
用法
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);
}
性能
- 缓存构建:约90毫秒,用于约530种字体
- 缓存查询:约4微秒
许可
MIT
依赖项
约12MB
约285K SLoC