blob: aa2fee8c054777ee6c1c9a8025826d12d39db261 [file] [view] [edit]
# Project Proposal: Frankenfonts — Hybrid Rust Font Parsing & FreeType/AGG Rasterization
**Author:** Tom Sepez (`tsepez@google.com`)
**Target Project:** PDFium (`core/fxge`, standalone, and Chromium integration)
**Status:** Proposed Architecture
---
## 1. Executive Summary
PDFium historically relies on **FreeType** for both binary font table parsing
and glyph pixel rasterization. However, the overwhelming majority of historical
vulnerabilities in font engines stem from **parsing untrusted, malformed font
tables** (such as embedded TrueType, OpenType, and CFF streams in malicious
PDFs).
**Project Frankenfonts** proposes a hybrid font architecture:
1. **Frontend (Parsing & Hinting):** Use Google's memory-safe **Fontations**
(`read-fonts` + `skrifa`) Rust crates to parse font tables, decode CMaps,
compute metrics, and execute TrueType VM / CFF hinting instructions in safe
Rust.
2. **Backend (Rasterization):** Pass the extracted vector outlines directly
into **FreeType**'s scanline rasterizer (`FT_Render_Glyph` in `ftsmooth.c` /
`ftgrays.c`) or PDFium's **AGG** rasterizer to generate anti-aliased bitmap
masks.
3. **Decoupling from Skia:** Remove the `pdf_use_skia` requirement from
`pdf_enable_fontations`, allowing standalone PDFium (including AGG builds)
to benefit from memory-safe font parsing.
---
## 2. Motivation: The FreeType Dilemma
### 2.1. The Vulnerability Surface of Embedded PDF Fonts
PDF files frequently embed custom, subsetted, or heavily modified font files.
Over the last two decades, embedded font parsing in FreeType has been one of the
primary attack vectors for remote code execution and memory corruption in
document viewers (integer overflows in table offsets, malformed CMap subtables,
corrupt CFF charstrings).
### 2.2. Parsing vs. Rasterization
FreeType performs two fundamentally distinct tasks:
* **Task A: Binary Font Parsing & Hinting (High Risk):** Reading raw bytes from
disk/memory into C structs (`CMap`, `Hmtx`, `OS/2`, `Name`, `Post`, `glyf`,
`CFF`) and running Turing-complete bytecode interpreters in C.
* **Task B: Scanline Rasterization (Low Risk / High Fidelity):** Taking
mathematical Bézier curves and generating anti-aliased 8bpp grayscale pixel
masks (`ftgrays.c`) or subpixel LCD masks (`ftsmooth.c`).
FreeType's rasterization math is battle-tested and produces the exact
anti-aliasing curves PDFium expects. The risk is located in **Task A
(Parsing)**.
---
## 3. The Frankenfonts Architecture
```
┌──────────────────────────────────────────────┐
│ Untrusted PDF Font Data │
└──────────────────────┬───────────────────────┘
┌──────────────────────────────────────────────┐
│ Fontations Frontend (Pure Safe Rust) │
│ - `read-fonts`: Safe Table Parsing │
│ - `skrifa`: CMaps, Metrics, BBoxes │
│ - `HintingInstance`: TrueType / CFF VM │
│ - `OutlinePen`: Bézier Curve Extraction │
└──────────────────────┬───────────────────────┘
▼ Extracted `FT_Outline` / `CFX_Path`
┌──────────────────────────────────────────────┐
│ Rasterization Backend (FreeType / AGG) │
│ - Feeds safe Bézier curves into rasterizer│
│ - FreeType `FT_Render_Glyph` or AGG AA │
└──────────────────────┬───────────────────────┘
┌──────────────────────────────────────────────┐
│ CFX_GlyphBitmap │
│ (Anti-Aliased Mask) │
└──────────────────────────────────────────────┘
```
---
## 4. Key Architectural Benefits
### 4.1. Complete Elimination of Font Parsing CVEs
Because `read-fonts` and `skrifa` are written in 100% memory-safe Rust with
strict bounds-checking, zero-copy slicing, and fuzz-tested arithmetic, PDFium
becomes completely immune to font-table parsing vulnerabilities. FreeType is
never exposed to raw untrusted font byte streams.
### 4.2. High Fidelity & Perceptual Parity
By feeding Skrifa's extracted vector outlines into FreeType's existing
rasterizer (`ftsmooth.c` / `ftgrays.c`), the resulting bitmap masks maintain visual fidelity
with legacy FreeType output. Subpixel hinting variances inherent to independent
TrueType VM implementations are handled via windowed MSE fuzzy test matching
and expectation suffixes.
### 4.3. Full Standalone Independence (No Skia Required)
Currently, `pdf_enable_fontations` is artificially gated on `pdf_use_skia =
true`. Frankenfonts decouples Fontations from Skia:
* `skrifa` and `read_fonts` are vendored directly via `gnrt` in
`//third_party/rust/`.
* Standalone PDFium (`pdf_use_agg = true`, `pdf_use_skia = false`) can use
Fontations with zero dependencies on Skia.
---
## 5. Implementation Roadmap
### Phase 1: Decouple GN Flags & Public API
* Updated `pdfium.gni` to assert that `pdf_enable_fontations` only requires
`enable_rust = true`.
* Defined `PDF_ENABLE_FONTATIONS` in `BUILD.gn` whenever
`pdf_enable_fontations` is enabled.
* Exposed `CFX_FontMgr::GetFontBackend()` and `FPDF_InitLibraryWithConfig()`
runtime selection in AGG builds.
* Wired `--fontations` CLI flag into `pdfium_test`, `pdfium_embeddertests`,
and `pdfium_unittests`.
### Phase 2: Route Font Table & Outline Queries to `skrifa`
* Implement `hinted_outline()` in `main.rs` using `skrifa::outline::HintingInstance`.
* Connect `CFX_Face::RenderGlyph()` to extract outlines through Skrifa at
the target display PPEM scale and rasterize through `FT_Render_Glyph()`.
---
## 6. Conclusion
Project Frankenfonts delivers **uncompromising memory safety against hostile
font exploits in untrusted PDFs** paired with **FreeType scanline
rasterization**, keeping standalone PDFium lean, fast, and secure.