fontdue/
raster.rs

1/* Notice to anyone that wants to repurpose the raster for your library:
2 * Please don't reuse this raster. Fontdue's raster is very unsafe, with nuanced invariants that
3 * need to be accounted for. Fontdue sanitizes the input that the raster will consume to ensure it
4 * is safe. Please be aware of this.
5 */
6
7use crate::math::Line;
8use crate::platform::{abs, as_i32, copysign, f32x4, fract};
9use crate::Glyph;
10use alloc::vec;
11use alloc::vec::*;
12
13pub struct Raster {
14    w: usize,
15    h: usize,
16    a: Vec<f32>,
17}
18
19impl Raster {
20    pub fn new(w: usize, h: usize) -> Raster {
21        Raster {
22            w,
23            h,
24            a: vec![0.0; w * h + 3],
25        }
26    }
27
28    pub(crate) fn draw(&mut self, glyph: &Glyph, scale_x: f32, scale_y: f32, offset_x: f32, offset_y: f32) {
29        let params = f32x4::new(1.0 / scale_x, 1.0 / scale_y, scale_x, scale_y);
30        let scale = f32x4::new(scale_x, scale_y, scale_x, scale_y);
31        let offset = f32x4::new(offset_x, offset_y, offset_x, offset_y);
32        for line in &glyph.v_lines {
33            self.v_line(line, line.coords * scale + offset);
34        }
35        for line in &glyph.m_lines {
36            self.m_line(line, line.coords * scale + offset, line.params * params);
37        }
38    }
39
40    #[inline(always)]
41    fn add(&mut self, index: usize, height: f32, mid_x: f32) {
42        // This is fast and hip.
43        unsafe {
44            let m = height * mid_x;
45            *self.a.get_unchecked_mut(index) += height - m;
46            *self.a.get_unchecked_mut(index + 1) += m;
47        }
48
49        // This is safe but slow.
50        // let m = height * mid_x;
51        // self.a[index] += height - m;
52        // self.a[index + 1] += m;
53    }
54
55    #[inline(always)]
56    fn v_line(&mut self, line: &Line, coords: f32x4) {
57        let (x0, y0, _, y1) = coords.copied();
58        let temp = coords.sub_integer(line.nudge).trunc();
59        let (start_x, start_y, end_x, end_y) = temp.copied();
60        let (_, mut target_y, _, _) = (temp + line.adjustment).copied();
61        let sy = copysign(1f32, y1 - y0);
62        let mut y_prev = y0;
63        let mut index = as_i32(start_x + start_y * self.w as f32);
64        let index_y_inc = as_i32(copysign(self.w as f32, sy));
65        let mut dist = as_i32(abs(start_y - end_y));
66        let mid_x = fract(x0);
67        while dist > 0 {
68            dist -= 1;
69            self.add(index as usize, y_prev - target_y, mid_x);
70            index += index_y_inc;
71            y_prev = target_y;
72            target_y += sy;
73        }
74        self.add(as_i32(end_x + end_y * self.w as f32) as usize, y_prev - y1, mid_x);
75    }
76
77    #[inline(always)]
78    fn m_line(&mut self, line: &Line, coords: f32x4, params: f32x4) {
79        let (x0, y0, x1, y1) = coords.copied();
80        let temp = coords.sub_integer(line.nudge).trunc();
81        let (start_x, start_y, end_x, end_y) = temp.copied();
82        let (tdx, tdy, dx, dy) = params.copied();
83        let (mut target_x, mut target_y, _, _) = (temp + line.adjustment).copied();
84        let sx = copysign(1f32, tdx);
85        let sy = copysign(1f32, tdy);
86        let mut tmx = tdx * (target_x - x0);
87        let mut tmy = tdy * (target_y - y0);
88        let tdx = abs(tdx);
89        let tdy = abs(tdy);
90        let mut x_prev = x0;
91        let mut y_prev = y0;
92        let mut index = as_i32(start_x + start_y * self.w as f32);
93        let index_x_inc = as_i32(sx);
94        let index_y_inc = as_i32(copysign(self.w as f32, sy));
95        let mut dist = as_i32(abs(start_x - end_x) + abs(start_y - end_y));
96        while dist > 0 {
97            dist -= 1;
98            let prev_index = index;
99            let y_next: f32;
100            let x_next: f32;
101            if tmx < tmy {
102                y_next = tmx * dy + y0; // FMA is not faster.
103                x_next = target_x;
104                tmx += tdx;
105                target_x += sx;
106                index += index_x_inc;
107            } else {
108                y_next = target_y;
109                x_next = tmy * dx + x0;
110                tmy += tdy;
111                target_y += sy;
112                index += index_y_inc;
113            }
114            self.add(prev_index as usize, y_prev - y_next, fract((x_prev + x_next) / 2.0));
115            x_prev = x_next;
116            y_prev = y_next;
117        }
118        self.add(as_i32(end_x + end_y * self.w as f32) as usize, y_prev - y1, fract((x_prev + x1) / 2.0));
119    }
120
121    #[inline(always)]
122    pub fn get_bitmap(&self) -> Vec<u8> {
123        crate::platform::get_bitmap(&self.a, self.w * self.h)
124    }
125}