#![forbid(unsafe_code)]
#![deny(missing_docs)]
use std::fmt::{self, Debug, Formatter};
use std::ops::{Add, Div, Mul, Sub};
use ttf_parser::{Face, GlyphId, OutlineBuilder, Rect};
#[derive(Debug, Clone)]
pub struct Glyph {
units_per_em: u16,
bbox: Rect,
segments: Vec<Segment>,
}
#[derive(Debug, Copy, Clone)]
enum Segment {
Line(Point, Point),
Quad(Point, Point, Point),
Cubic(Point, Point, Point, Point),
}
impl Glyph {
pub fn load(face: &Face, glyph_id: GlyphId) -> Option<Self> {
let mut builder = Builder::default();
Some(Self {
units_per_em: face.units_per_em(),
bbox: face.outline_glyph(glyph_id, &mut builder)?,
segments: builder.segments,
})
}
pub fn rasterize(&self, x: f32, y: f32, size: f32) -> Bitmap {
let s = size / self.units_per_em as f32;
let slack = 0.01;
let left = (x + s * self.bbox.x_min as f32 - slack).floor() as i32;
let right = (x + s * self.bbox.x_max as f32 + slack).ceil() as i32;
let top = (y - s * self.bbox.y_max as f32).floor() as i32;
let bottom = (y - s * self.bbox.y_min as f32).ceil() as i32;
let width = (right - left) as u32;
let height = (bottom - top) as u32;
let dx = x - left as f32;
let dy = y - top as f32;
let t = |p: Point| point(dx + p.x * s, dy - p.y * s);
let mut canvas = Canvas::new(width, height);
for &segment in &self.segments {
match segment {
Segment::Line(p0, p1) => canvas.line(t(p0), t(p1)),
Segment::Quad(p0, p1, p2) => canvas.quad(t(p0), t(p1), t(p2)),
Segment::Cubic(p0, p1, p2, p3) => {
canvas.cubic(t(p0), t(p1), t(p2), t(p3))
}
}
}
Bitmap {
left,
top,
width,
height,
coverage: canvas.accumulate(),
}
}
}
pub struct Bitmap {
pub left: i32,
pub top: i32,
pub width: u32,
pub height: u32,
pub coverage: Vec<u8>,
}
impl Debug for Bitmap {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct("Bitmap")
.field("left", &self.left)
.field("top", &self.top)
.field("width", &self.width)
.field("height", &self.height)
.finish()
}
}
#[derive(Default)]
struct Builder {
segments: Vec<Segment>,
start: Option<Point>,
last: Point,
}
impl OutlineBuilder for Builder {
fn move_to(&mut self, x: f32, y: f32) {
self.start = Some(point(x, y));
self.last = point(x, y);
}
fn line_to(&mut self, x: f32, y: f32) {
self.segments.push(Segment::Line(self.last, point(x, y)));
self.last = point(x, y);
}
fn quad_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32) {
self.segments
.push(Segment::Quad(self.last, point(x1, y1), point(x2, y2)));
self.last = point(x2, y2);
}
fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x3: f32, y3: f32) {
self.segments.push(Segment::Cubic(
self.last,
point(x1, y1),
point(x2, y2),
point(x3, y3),
));
self.last = point(x3, y3);
}
fn close(&mut self) {
if let Some(start) = self.start.take() {
self.segments.push(Segment::Line(self.last, start));
self.last = start;
}
}
}
struct Canvas {
w: usize,
h: usize,
a: Vec<f32>,
}
impl Canvas {
fn new(w: u32, h: u32) -> Self {
Self {
w: w as usize,
h: h as usize,
a: vec![0.0; (w * h + 4) as usize],
}
}
fn accumulate(self) -> Vec<u8> {
let mut acc = 0.0;
self.a[..self.w * self.h]
.iter()
.map(|c| {
acc += c;
(255.0 * acc.abs().min(1.0)) as u8
})
.collect()
}
fn add(&mut self, linestart: usize, x: i32, delta: f32) {
if let Ok(x) = usize::try_from(x) {
if let Some(a) = self.a.get_mut(linestart + x) {
*a += delta;
}
}
}
fn line(&mut self, p0: Point, p1: Point) {
if (p0.y - p1.y).abs() <= core::f32::EPSILON {
return;
}
let (dir, p0, p1) = if p0.y < p1.y { (1.0, p0, p1) } else { (-1.0, p1, p0) };
let dxdy = (p1.x - p0.x) / (p1.y - p0.y);
let mut x = p0.x;
let y0 = p0.y as usize;
if p0.y < 0.0 {
x -= p0.y * dxdy;
}
for y in y0..self.h.min(p1.y.ceil() as usize) {
let linestart = y * self.w;
let dy = ((y + 1) as f32).min(p1.y) - (y as f32).max(p0.y);
let xnext = x + dxdy * dy;
let d = dy * dir;
let (x0, x1) = if x < xnext { (x, xnext) } else { (xnext, x) };
let x0floor = x0.floor();
let x0i = x0floor as i32;
let x1ceil = x1.ceil();
let x1i = x1ceil as i32;
if x1i <= x0i + 1 {
let xmf = 0.5 * (x + xnext) - x0floor;
self.add(linestart, x0i, d - d * xmf);
self.add(linestart, x0i + 1, d * xmf);
} else {
let s = (x1 - x0).recip();
let x0f = x0 - x0floor;
let a0 = 0.5 * s * (1.0 - x0f) * (1.0 - x0f);
let x1f = x1 - x1ceil + 1.0;
let am = 0.5 * s * x1f * x1f;
self.add(linestart, x0i, d * a0);
if x1i == x0i + 2 {
self.add(linestart, x0i + 1, d * (1.0 - a0 - am));
} else {
let a1 = s * (1.5 - x0f);
self.add(linestart, x0i + 1, d * (a1 - a0));
for xi in x0i + 2..x1i - 1 {
self.add(linestart, xi, d * s);
}
let a2 = a1 + (x1i - x0i - 3) as f32 * s;
self.add(linestart, x1i - 1, d * (1.0 - a2 - am));
}
self.add(linestart, x1i, d * am);
}
x = xnext;
}
}
fn quad(&mut self, p0: Point, p1: Point, p2: Point) {
let devsq = hypot2(p0 - 2.0 * p1 + p2);
if devsq < 0.333 {
self.line(p0, p2);
return;
}
let tol = 3.0;
let n = 1.0 + (tol * devsq).sqrt().sqrt().floor().min(30.0);
let nu = n as usize;
let step = n.recip();
let mut t = 0.0;
let mut p = p0;
for _ in 0..nu.saturating_sub(1) {
t += step;
let p01 = lerp(t, p0, p1);
let p12 = lerp(t, p1, p2);
let pt = lerp(t, p01, p12);
self.line(p, pt);
p = pt;
}
self.line(p, p2);
}
}
impl Canvas {
fn cubic(&mut self, p0: Point, p1: Point, p2: Point, p3: Point) {
let p1x2 = 3.0 * p1 - p0;
let p2x2 = 3.0 * p2 - p3;
let err = hypot2(p2x2 - p1x2);
let tol = 0.333;
let max = 432.0 * tol * tol;
let n = (err / max).powf(1.0 / 6.0).ceil().clamp(1.0, 20.0);
let nu = n as usize;
let step = n.recip();
let step4 = step / 4.0;
let dp0 = 3.0 * (p1 - p0);
let dp1 = 3.0 * (p2 - p1);
let dp2 = 3.0 * (p3 - p2);
let mut t = 0.0;
let mut p = p0;
let mut pd = dp0;
for _ in 0..nu {
t += step;
let p01 = lerp(t, p0, p1);
let p12 = lerp(t, p1, p2);
let p23 = lerp(t, p2, p3);
let p012 = lerp(t, p01, p12);
let p123 = lerp(t, p12, p23);
let pt = lerp(t, p012, p123);
let dp01 = lerp(t, dp0, dp1);
let dp12 = lerp(t, dp1, dp2);
let pdt = lerp(t, dp01, dp12);
let pc = (p + pt) / 2.0 + step4 * (pd - pdt);
self.quad(p, pc, pt);
p = pt;
pd = pdt;
}
}
}
fn point(x: f32, y: f32) -> Point {
Point { x, y }
}
fn lerp(t: f32, p1: Point, p2: Point) -> Point {
Point {
x: p1.x + t * (p2.x - p1.x),
y: p1.y + t * (p2.y - p1.y),
}
}
fn hypot2(p: Point) -> f32 {
p.x * p.x + p.y * p.y
}
#[derive(Debug, Default, Copy, Clone)]
struct Point {
x: f32,
y: f32,
}
impl Add for Point {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self { x: self.x + rhs.x, y: self.y + rhs.y }
}
}
impl Sub for Point {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self { x: self.x - rhs.x, y: self.y - rhs.y }
}
}
impl Mul<Point> for f32 {
type Output = Point;
fn mul(self, rhs: Point) -> Self::Output {
Point { x: self * rhs.x, y: self * rhs.y }
}
}
impl Div<f32> for Point {
type Output = Point;
fn div(self, rhs: f32) -> Self::Output {
Point { x: self.x / rhs, y: self.y / rhs }
}
}