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 | |
7 | use crate::math::Line; |
8 | use crate::platform::{abs, as_i32, copysign, f32x4, fract}; |
9 | use crate::Glyph; |
10 | use alloc::vec; |
11 | use alloc::vec::*; |
12 | |
13 | pub struct Raster { |
14 | w: usize, |
15 | h: usize, |
16 | a: Vec<f32>, |
17 | } |
18 | |
19 | impl 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 | } |
126 | |