web engine - experimental web browser

Remove dead raster.rs file (superseded by rasterizer.rs)

The raster.rs file was an earlier draft of the glyph rasterizer that was
never wired into the module system. It contained an incomplete
plot_line_analytic function and a buggy add_quadratic implementation.
The proper implementation lives in rasterizer.rs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

-235
-235
crates/text/src/font/raster.rs
··· 1 - use super::tables::glyf::{Contour, GlyphOutline, Point}; 2 - 3 - /// A rasterized grayscale bitmap of a single glyph. 4 - #[derive(Debug, Clone)] 5 - pub struct GlyphBitmap { 6 - pub width: u32, 7 - pub height: u32, 8 - pub bearing_x: i32, 9 - pub bearing_y: i32, 10 - /// 8-bit coverage values (0 = transparent, 255 = fully opaque). 11 - /// Row-major layout, top-to-bottom. 12 - pub data: Vec<u8>, 13 - } 14 - 15 - /// Convert a physical glyph outline into an anti-aliased bitmap. 16 - pub fn rasterize_glyph( 17 - outline: &GlyphOutline, 18 - scale: f32, 19 - ) -> Option<GlyphBitmap> { 20 - // 1. Flatten the contour into line segments (scaled to pixels). 21 - let mut segments: Vec<(f32, f32, f32, f32)> = Vec::new(); 22 - 23 - for contour in &outline.contours { 24 - if contour.points.is_empty() { 25 - continue; 26 - } 27 - 28 - // TrueType points sequence parsing 29 - let pts = &contour.points; 30 - let mut curr = pts[0]; 31 - 32 - // Find a starting on-curve point 33 - let mut start_idx = 0; 34 - if !curr.on_curve { 35 - let next = pts[1]; 36 - if next.on_curve { 37 - start_idx = 1; 38 - curr = next; 39 - } else { 40 - // If both are off-curve, the implicit point is midway 41 - curr = Point { 42 - x: (curr.x + next.x) / 2, 43 - y: (curr.y + next.y) / 2, 44 - on_curve: true, 45 - }; 46 - } 47 - } 48 - 49 - let first = curr; 50 - let mut i = start_idx + 1; 51 - let n = pts.len(); 52 - 53 - while i <= n { 54 - // Read next point (wrap around up to start_idx) 55 - let next = if i < n { pts[i] } else { pts[i % n] }; 56 - let p1; 57 - 58 - if next.on_curve { 59 - p1 = next; 60 - add_line(&mut segments, curr, p1, scale); 61 - curr = p1; 62 - i += 1; 63 - if i > n { break; } 64 - } else { 65 - // Next is off-curve 66 - let p_ctrl = next; 67 - let mut p2; 68 - i += 1; 69 - 70 - let next2 = if i < n { pts[i] } else { pts[i % n] }; 71 - if next2.on_curve { 72 - p2 = next2; 73 - i += 1; 74 - } else { 75 - // Implicit on-curve point midway between two off-curve 76 - p2 = Point { 77 - x: (p_ctrl.x + next2.x) / 2, 78 - y: (p_ctrl.y + next2.y) / 2, 79 - on_curve: true, 80 - }; 81 - } 82 - 83 - add_quadratic(&mut segments, curr, p_ctrl, p2, scale); 84 - curr = p2; 85 - 86 - if i > n { break; } 87 - } 88 - } 89 - 90 - // Close the contour 91 - add_line(&mut segments, curr, first, scale); 92 - } 93 - 94 - if segments.is_empty() { 95 - return None; 96 - } 97 - 98 - // 2. Determine bounding box 99 - let mut min_x = f32::MAX; 100 - let mut min_y = f32::MAX; 101 - let mut max_x = f32::MIN; 102 - let mut max_y = f32::MIN; 103 - 104 - for &(x0, y0, x1, y1) in &segments { 105 - min_x = min_x.min(x0).min(x1); 106 - min_y = min_y.min(y0).min(y1); 107 - max_x = max_x.max(x0).max(x1); 108 - max_y = max_y.max(y0).max(y1); 109 - } 110 - 111 - if min_x > max_x || min_y > max_y { 112 - return None; 113 - } 114 - 115 - let px_min_x = min_x.floor() as i32; 116 - // Note: TrueType Y goes up. So y_max is the top of the glyph. 117 - // We invert Y so that 0 is at the top of the bitmap. 118 - let px_min_y = (-max_y).floor() as i32; 119 - let px_max_x = max_x.ceil() as i32; 120 - let px_max_y = (-min_y).ceil() as i32; 121 - 122 - let width = (px_max_x - px_min_x).max(1) as u32; 123 - let height = (px_max_y - px_min_y).max(1) as u32; 124 - 125 - let bearing_x = px_min_x; 126 - let bearing_y = px_min_y; // actually -max_y 127 - 128 - // 3. Rasterize using a simple 16x16 oversampling for each pixel 129 - const SUBPIXELS: i32 = 16; 130 - let sub_w = width as usize * SUBPIXELS as usize; 131 - let sub_h = height as usize * SUBPIXELS as usize; 132 - 133 - // An active edge table could be used, but for simplicity 134 - // we use a buffer of wind counts per subpixel row. 135 - let mut coverages = vec![0i32; width as usize * height as usize]; 136 - 137 - // We'll rasterize each segment by drawing lines at subpixel resolution 138 - for &(mut x0, mut y0, mut x1, mut y1) in &segments { 139 - // shift relative to bounding box 140 - x0 -= px_min_x as f32; 141 - x1 -= px_min_x as f32; 142 - // invert Y 143 - y0 = -y0 - px_min_y as f32; 144 - y1 = -y1 - px_min_y as f32; 145 - 146 - plot_line_analytic(&mut coverages, width as usize, height as usize, x0, y0, x1, y1); 147 - } 148 - 149 - // Accumulate coverages and produce final bitmap 150 - let mut data = Vec::with_capacity(width as usize * height as usize); 151 - for row in 0..height as usize { 152 - let mut accum = 0.0; 153 - for col in 0..width as usize { 154 - accum += coverages[row * width as usize + col] as f32 / 256.0; 155 - // non-zero winding rule 156 - let mut alpha = accum.abs(); 157 - if alpha > 1.0 { alpha = 1.0; } 158 - let intensity = (alpha * 255.0).round() as u8; 159 - data.push(intensity); 160 - } 161 - } 162 - 163 - Some(GlyphBitmap { 164 - width, 165 - height, 166 - bearing_x, 167 - bearing_y, 168 - data, 169 - }) 170 - } 171 - 172 - // Analytic anti-aliased line plotting into a coverage buffer. 173 - // Inspired by font-rs and stb_truetype. 174 - fn plot_line_analytic( 175 - coverages: &mut [i32], 176 - w: usize, 177 - h: usize, 178 - mut x0: f32, 179 - mut y0: f32, 180 - mut x1: f32, 181 - mut y1: f32, 182 - ) { 183 - let dx = x1 - x0; 184 - let dy = y1 - y0; 185 - let dir_y = dy.signum() as i32; 186 - 187 - if dir_y == 0 { return; } // horizontal lines cover no vertical area 188 - 189 - let mut ex = x0.floor() as i32; 190 - let mut ey = y0.floor() as i32; 191 - let ext_x = x1.floor() as i32; 192 - let ext_y = y1.floor() as i32; 193 - 194 - // To handle negative directions, step is 1 or -1 195 - let step_x = dx.signum() as i32; 196 - let step_y = dy.signum() as i32; 197 - 198 - // compute intersections with pixel boundaries 199 - // ... 200 - // A much simpler and robust fallback: 16x supersampling 201 - let samples = 16; 202 - } 203 - 204 - fn add_line(segments: &mut Vec<(f32, f32, f32, f32)>, p0: Point, p1: Point, scale: f32) { 205 - segments.push(( 206 - p0.x as f32 * scale, 207 - p0.y as f32 * scale, 208 - p1.x as f32 * scale, 209 - p1.y as f32 * scale, 210 - )); 211 - } 212 - 213 - fn add_quadratic(segments: &mut Vec<(f32, f32, f32, f32)>, p0: Point, p1: Point, p2: Point, scale: f32) { 214 - let mut last_x = p0.x as f32 * scale; 215 - let mut last_y = p0.y as f32 * scale; 216 - 217 - let cx = p1.x as f32 * scale; 218 - let cy = p1.y as f32 * scale; 219 - 220 - let px2 = p2.x as f32 * scale; 221 - let py2 = p2.y as f32 * scale; 222 - 223 - let steps = 8; 224 - for i in 1..=steps { 225 - let t = i as f32 / steps as f32; 226 - let mt = 1.0 - t; 227 - 228 - let x = mt * mt * last_x + 2.0 * mt * t * cx + t * t * px2; 229 - let y = mt * mt * last_y + 2.0 * mt * t * cy + t * t * py2; 230 - 231 - segments.push((last_x, last_y, x, y)); 232 - last_x = x; 233 - last_y = y; 234 - } 235 - }