| 1 | use crate::platform::{self, abs, atan2, f32x4, sqrt}; |
| 2 | use crate::{Glyph, OutlineBounds}; |
| 3 | use alloc::vec; |
| 4 | use alloc::vec::*; |
| 5 | |
| 6 | #[derive (Copy, Clone, PartialEq, Debug)] |
| 7 | struct AABB { |
| 8 | /// Coordinate of the left-most edge. |
| 9 | xmin: f32, |
| 10 | /// Coordinate of the right-most edge. |
| 11 | xmax: f32, |
| 12 | /// Coordinate of the bottom-most edge. |
| 13 | ymin: f32, |
| 14 | /// Coordinate of the top-most edge. |
| 15 | ymax: f32, |
| 16 | } |
| 17 | |
| 18 | impl Default for AABB { |
| 19 | fn default() -> Self { |
| 20 | AABB { |
| 21 | xmin: 0.0, |
| 22 | xmax: 0.0, |
| 23 | ymin: 0.0, |
| 24 | ymax: 0.0, |
| 25 | } |
| 26 | } |
| 27 | } |
| 28 | |
| 29 | #[derive (Copy, Clone, Debug, PartialEq)] |
| 30 | struct CubeCurve { |
| 31 | a: Point, |
| 32 | b: Point, |
| 33 | c: Point, |
| 34 | d: Point, |
| 35 | } |
| 36 | |
| 37 | impl CubeCurve { |
| 38 | const fn new(a: Point, b: Point, c: Point, d: Point) -> CubeCurve { |
| 39 | CubeCurve { |
| 40 | a, |
| 41 | b, |
| 42 | c, |
| 43 | d, |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | fn scale(&self, scale: f32) -> CubeCurve { |
| 48 | CubeCurve { |
| 49 | a: self.a.scale(scale), |
| 50 | b: self.b.scale(scale), |
| 51 | c: self.c.scale(scale), |
| 52 | d: self.d.scale(scale), |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | fn is_flat(&self, threshold: f32) -> bool { |
| 57 | let (d1, d2, d3, d4) = f32x4::new( |
| 58 | self.a.distance_squared(self.b), |
| 59 | self.b.distance_squared(self.c), |
| 60 | self.c.distance_squared(self.d), |
| 61 | self.a.distance_squared(self.d), |
| 62 | ) |
| 63 | .sqrt() |
| 64 | .copied(); |
| 65 | (d1 + d2 + d3) < threshold * d4 |
| 66 | } |
| 67 | |
| 68 | fn split(&self) -> (CubeCurve, CubeCurve) { |
| 69 | let q0 = self.a.midpoint(self.b); |
| 70 | let q1 = self.b.midpoint(self.c); |
| 71 | let q2 = self.c.midpoint(self.d); |
| 72 | let r0 = q0.midpoint(q1); |
| 73 | let r1 = q1.midpoint(q2); |
| 74 | let s0 = r0.midpoint(r1); |
| 75 | (CubeCurve::new(self.a, q0, r0, s0), CubeCurve::new(s0, r1, q2, self.d)) |
| 76 | } |
| 77 | |
| 78 | /// The point at time t in the curve. |
| 79 | fn point(&self, t: f32) -> Point { |
| 80 | let tm = 1.0 - t; |
| 81 | let a = tm * tm * tm; |
| 82 | let b = 3.0 * (tm * tm) * t; |
| 83 | let c = 3.0 * tm * (t * t); |
| 84 | let d = t * t * t; |
| 85 | |
| 86 | let x = a * self.a.x + b * self.b.x + c * self.c.x + d * self.d.x; |
| 87 | let y = a * self.a.y + b * self.b.y + c * self.c.y + d * self.d.y; |
| 88 | Point::new(x, y) |
| 89 | } |
| 90 | |
| 91 | /// The slope of the tangent line at time t. |
| 92 | fn slope(&self, t: f32) -> (f32, f32) { |
| 93 | let tm = 1.0 - t; |
| 94 | let a = 3.0 * (tm * tm); |
| 95 | let b = 6.0 * tm * t; |
| 96 | let c = 3.0 * (t * t); |
| 97 | |
| 98 | let x = a * (self.b.x - self.a.x) + b * (self.c.x - self.b.x) + c * (self.d.x - self.c.x); |
| 99 | let y = a * (self.b.y - self.a.y) + b * (self.c.y - self.b.y) + c * (self.d.y - self.c.y); |
| 100 | (x, y) |
| 101 | } |
| 102 | |
| 103 | /// The angle of the tangent line at time t in rads. |
| 104 | fn angle(&self, t: f32) -> f32 { |
| 105 | let (x, y) = self.slope(t); |
| 106 | abs(atan2(x, y)) |
| 107 | } |
| 108 | } |
| 109 | |
| 110 | #[derive (Copy, Clone, Debug, PartialEq)] |
| 111 | struct QuadCurve { |
| 112 | a: Point, |
| 113 | b: Point, |
| 114 | c: Point, |
| 115 | } |
| 116 | |
| 117 | impl QuadCurve { |
| 118 | fn new(a: Point, b: Point, c: Point) -> QuadCurve { |
| 119 | QuadCurve { |
| 120 | a, |
| 121 | b, |
| 122 | c, |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | fn scale(&self, scale: f32) -> QuadCurve { |
| 127 | QuadCurve { |
| 128 | a: self.a.scale(scale), |
| 129 | b: self.b.scale(scale), |
| 130 | c: self.c.scale(scale), |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | fn is_flat(&self, threshold: f32) -> bool { |
| 135 | let (d1, d2, d3, _) = f32x4::new( |
| 136 | self.a.distance_squared(self.b), |
| 137 | self.b.distance_squared(self.c), |
| 138 | self.a.distance_squared(self.c), |
| 139 | 1.0, |
| 140 | ) |
| 141 | .sqrt() |
| 142 | .copied(); |
| 143 | (d1 + d2) < threshold * d3 |
| 144 | } |
| 145 | |
| 146 | fn split(&self) -> (QuadCurve, QuadCurve) { |
| 147 | let q0 = self.a.midpoint(self.b); |
| 148 | let q1 = self.b.midpoint(self.c); |
| 149 | let r0 = q0.midpoint(q1); |
| 150 | (QuadCurve::new(self.a, q0, r0), QuadCurve::new(r0, q1, self.c)) |
| 151 | } |
| 152 | |
| 153 | /// The point at time t in the curve. |
| 154 | fn point(&self, t: f32) -> Point { |
| 155 | let tm = 1.0 - t; |
| 156 | let a = tm * tm; |
| 157 | let b = 2.0 * tm * t; |
| 158 | let c = t * t; |
| 159 | |
| 160 | let x = a * self.a.x + b * self.b.x + c * self.c.x; |
| 161 | let y = a * self.a.y + b * self.b.y + c * self.c.y; |
| 162 | Point::new(x, y) |
| 163 | } |
| 164 | |
| 165 | /// The slope of the tangent line at time t. |
| 166 | fn slope(&self, t: f32) -> (f32, f32) { |
| 167 | let tm = 1.0 - t; |
| 168 | let a = 2.0 * tm; |
| 169 | let b = 2.0 * t; |
| 170 | |
| 171 | let x = a * (self.b.x - self.a.x) + b * (self.c.x - self.b.x); |
| 172 | let y = a * (self.b.y - self.a.y) + b * (self.c.y - self.b.y); |
| 173 | (x, y) |
| 174 | } |
| 175 | |
| 176 | /// The angle of the tangent line at time t in rads. |
| 177 | fn angle(&self, t: f32) -> f32 { |
| 178 | let (x, y) = self.slope(t); |
| 179 | abs(atan2(x, y)) |
| 180 | } |
| 181 | } |
| 182 | |
| 183 | #[derive (Copy, Clone, Debug, PartialEq)] |
| 184 | pub struct Point { |
| 185 | /// Absolute X coordinate. |
| 186 | pub x: f32, |
| 187 | /// Absolute Y coordinate. |
| 188 | pub y: f32, |
| 189 | } |
| 190 | |
| 191 | impl Default for Point { |
| 192 | fn default() -> Self { |
| 193 | Point { |
| 194 | x: 0.0, |
| 195 | y: 0.0, |
| 196 | } |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | impl Point { |
| 201 | pub const fn new(x: f32, y: f32) -> Point { |
| 202 | Point { |
| 203 | x, |
| 204 | y, |
| 205 | } |
| 206 | } |
| 207 | |
| 208 | pub fn scale(&self, scale: f32) -> Point { |
| 209 | Point { |
| 210 | x: self.x * scale, |
| 211 | y: self.y * scale, |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | pub fn distance_squared(&self, other: Point) -> f32 { |
| 216 | let x = self.x - other.x; |
| 217 | let y = self.y - other.y; |
| 218 | x * x + y * y |
| 219 | } |
| 220 | |
| 221 | pub fn distance(&self, other: Point) -> f32 { |
| 222 | let x = self.x - other.x; |
| 223 | let y = self.y - other.y; |
| 224 | sqrt(x * x + y * y) |
| 225 | } |
| 226 | |
| 227 | pub fn midpoint(&self, other: Point) -> Point { |
| 228 | Point { |
| 229 | x: (self.x + other.x) / 2.0, |
| 230 | y: (self.y + other.y) / 2.0, |
| 231 | } |
| 232 | } |
| 233 | } |
| 234 | |
| 235 | #[derive (Copy, Clone)] |
| 236 | pub struct Line { |
| 237 | /// X0, Y0, X1, Y1. |
| 238 | pub coords: f32x4, |
| 239 | /// start_x_nudge, start_y_nudge, end_x_nudge, end_y_nudge. |
| 240 | pub nudge: f32x4, |
| 241 | /// x_first_adj, y_first_adj, none, none. |
| 242 | pub adjustment: f32x4, |
| 243 | /// tdx, tdy, dx, dy. |
| 244 | pub params: f32x4, |
| 245 | } |
| 246 | |
| 247 | impl Line { |
| 248 | pub fn new(start: Point, end: Point) -> Line { |
| 249 | // Floor adjustment and nudge: 0.0, 0 |
| 250 | // Ceil adjustment and nudge: 1.0, 1 |
| 251 | const FLOOR_NUDGE: u32 = 0; |
| 252 | const CEIL_NUDGE: u32 = 1; |
| 253 | |
| 254 | let (x_start_nudge, x_first_adj) = if end.x >= start.x { |
| 255 | (FLOOR_NUDGE, 1.0) |
| 256 | } else { |
| 257 | (CEIL_NUDGE, 0.0) |
| 258 | }; |
| 259 | let (y_start_nudge, y_first_adj) = if end.y >= start.y { |
| 260 | (FLOOR_NUDGE, 1.0) |
| 261 | } else { |
| 262 | (CEIL_NUDGE, 0.0) |
| 263 | }; |
| 264 | |
| 265 | let x_end_nudge = if end.x > start.x { |
| 266 | CEIL_NUDGE |
| 267 | } else { |
| 268 | FLOOR_NUDGE |
| 269 | }; |
| 270 | let y_end_nudge = if end.y > start.y { |
| 271 | CEIL_NUDGE |
| 272 | } else { |
| 273 | FLOOR_NUDGE |
| 274 | }; |
| 275 | |
| 276 | let dx = end.x - start.x; |
| 277 | let dy = end.y - start.y; |
| 278 | let tdx = if dx == 0.0 { |
| 279 | core::f32::MAX |
| 280 | } else { |
| 281 | 1.0 / dx |
| 282 | }; |
| 283 | let tdy = 1.0 / dy; |
| 284 | |
| 285 | Line { |
| 286 | coords: f32x4::new(start.x, start.y, end.x, end.y), |
| 287 | nudge: f32x4::new_u32(x_start_nudge, y_start_nudge, x_end_nudge, y_end_nudge), |
| 288 | adjustment: f32x4::new(x_first_adj, y_first_adj, 0.0, 0.0), |
| 289 | params: f32x4::new(tdx, tdy, dx, dy), |
| 290 | } |
| 291 | } |
| 292 | |
| 293 | fn reposition(&mut self, bounds: AABB, reverse: bool) { |
| 294 | let (mut x0, mut y0, mut x1, mut y1) = if !reverse { |
| 295 | self.coords.copied() |
| 296 | } else { |
| 297 | let (x0, y0, x1, y1) = self.coords.copied(); |
| 298 | (x1, y1, x0, y0) |
| 299 | }; |
| 300 | |
| 301 | x0 -= bounds.xmin; |
| 302 | y0 -= bounds.ymax; |
| 303 | y0 = abs(y0); |
| 304 | |
| 305 | x1 -= bounds.xmin; |
| 306 | y1 -= bounds.ymax; |
| 307 | y1 = abs(y1); |
| 308 | |
| 309 | *self = Self::new(Point::new(x0, y0), Point::new(x1, y1)); |
| 310 | } |
| 311 | } |
| 312 | |
| 313 | #[derive (Clone)] |
| 314 | pub struct Geometry { |
| 315 | v_lines: Vec<Line>, |
| 316 | m_lines: Vec<Line>, |
| 317 | effective_bounds: AABB, |
| 318 | start_point: Point, |
| 319 | previous_point: Point, |
| 320 | area: f32, |
| 321 | reverse_points: bool, |
| 322 | max_area: f32, |
| 323 | } |
| 324 | |
| 325 | struct Segment { |
| 326 | a: Point, |
| 327 | at: f32, |
| 328 | c: Point, |
| 329 | ct: f32, |
| 330 | } |
| 331 | |
| 332 | impl Segment { |
| 333 | const fn new(a: Point, at: f32, c: Point, ct: f32) -> Segment { |
| 334 | Segment { |
| 335 | a, |
| 336 | at, |
| 337 | c, |
| 338 | ct, |
| 339 | } |
| 340 | } |
| 341 | } |
| 342 | |
| 343 | impl ttf_parser::OutlineBuilder for Geometry { |
| 344 | fn move_to(&mut self, x0: f32, y0: f32) { |
| 345 | let next_point = Point::new(x0, y0); |
| 346 | self.start_point = next_point; |
| 347 | self.previous_point = next_point; |
| 348 | } |
| 349 | |
| 350 | fn line_to(&mut self, x0: f32, y0: f32) { |
| 351 | let next_point = Point::new(x0, y0); |
| 352 | self.push(self.previous_point, next_point); |
| 353 | self.previous_point = next_point; |
| 354 | } |
| 355 | |
| 356 | fn quad_to(&mut self, x0: f32, y0: f32, x1: f32, y1: f32) { |
| 357 | let control_point = Point::new(x0, y0); |
| 358 | let next_point = Point::new(x1, y1); |
| 359 | |
| 360 | let curve = QuadCurve::new(self.previous_point, control_point, next_point); |
| 361 | let mut stack = vec![Segment::new(self.previous_point, 0.0, next_point, 1.0)]; |
| 362 | while let Some(seg) = stack.pop() { |
| 363 | let bt = (seg.at + seg.ct) * 0.5; |
| 364 | let b = curve.point(bt); |
| 365 | // This is twice the triangle area |
| 366 | let area = (b.x - seg.a.x) * (seg.c.y - seg.a.y) - (seg.c.x - seg.a.x) * (b.y - seg.a.y); |
| 367 | if platform::abs(area) > self.max_area { |
| 368 | stack.push(Segment::new(seg.a, seg.at, b, bt)); |
| 369 | stack.push(Segment::new(b, bt, seg.c, seg.ct)); |
| 370 | } else { |
| 371 | self.push(seg.a, seg.c); |
| 372 | } |
| 373 | } |
| 374 | |
| 375 | self.previous_point = next_point; |
| 376 | } |
| 377 | |
| 378 | fn curve_to(&mut self, x0: f32, y0: f32, x1: f32, y1: f32, x2: f32, y2: f32) { |
| 379 | let first_control = Point::new(x0, y0); |
| 380 | let second_control = Point::new(x1, y1); |
| 381 | let next_point = Point::new(x2, y2); |
| 382 | |
| 383 | let curve = CubeCurve::new(self.previous_point, first_control, second_control, next_point); |
| 384 | let mut stack = vec![Segment::new(self.previous_point, 0.0, next_point, 1.0)]; |
| 385 | while let Some(seg) = stack.pop() { |
| 386 | let bt = (seg.at + seg.ct) * 0.5; |
| 387 | let b = curve.point(bt); |
| 388 | // This is twice the triangle area |
| 389 | let area = (b.x - seg.a.x) * (seg.c.y - seg.a.y) - (seg.c.x - seg.a.x) * (b.y - seg.a.y); |
| 390 | if platform::abs(area) > self.max_area { |
| 391 | stack.push(Segment::new(seg.a, seg.at, b, bt)); |
| 392 | stack.push(Segment::new(b, bt, seg.c, seg.ct)); |
| 393 | } else { |
| 394 | self.push(seg.a, seg.c); |
| 395 | } |
| 396 | } |
| 397 | self.previous_point = next_point; |
| 398 | } |
| 399 | |
| 400 | fn close(&mut self) { |
| 401 | if self.start_point != self.previous_point { |
| 402 | self.push(self.previous_point, self.start_point); |
| 403 | } |
| 404 | self.previous_point = self.start_point; |
| 405 | } |
| 406 | } |
| 407 | |
| 408 | impl Geometry { |
| 409 | // Artisanal bespoke hand carved curves |
| 410 | pub fn new(scale: f32, units_per_em: f32) -> Geometry { |
| 411 | const ERROR_THRESHOLD: f32 = 3.0; // In pixels. |
| 412 | let max_area = ERROR_THRESHOLD * 2.0 * (units_per_em / scale); |
| 413 | |
| 414 | Geometry { |
| 415 | v_lines: Vec::new(), |
| 416 | m_lines: Vec::new(), |
| 417 | effective_bounds: AABB { |
| 418 | xmin: core::f32::MAX, |
| 419 | xmax: core::f32::MIN, |
| 420 | ymin: core::f32::MAX, |
| 421 | ymax: core::f32::MIN, |
| 422 | }, |
| 423 | start_point: Point::default(), |
| 424 | previous_point: Point::default(), |
| 425 | area: 0.0, |
| 426 | reverse_points: false, |
| 427 | max_area, |
| 428 | } |
| 429 | } |
| 430 | |
| 431 | fn push(&mut self, start: Point, end: Point) { |
| 432 | // We're using to_bits here because we only care if they're _exactly_ the same. |
| 433 | if start.y.to_bits() != end.y.to_bits() { |
| 434 | self.area += (end.y - start.y) * (end.x + start.x); |
| 435 | if start.x.to_bits() == end.x.to_bits() { |
| 436 | self.v_lines.push(Line::new(start, end)); |
| 437 | } else { |
| 438 | self.m_lines.push(Line::new(start, end)); |
| 439 | } |
| 440 | Self::recalculate_bounds(&mut self.effective_bounds, start.x, start.y); |
| 441 | Self::recalculate_bounds(&mut self.effective_bounds, end.x, end.y); |
| 442 | } |
| 443 | } |
| 444 | |
| 445 | pub(crate) fn finalize(mut self, glyph: &mut Glyph) { |
| 446 | if self.v_lines.is_empty() && self.m_lines.is_empty() { |
| 447 | self.effective_bounds = AABB::default(); |
| 448 | } else { |
| 449 | self.reverse_points = self.area > 0.0; |
| 450 | for line in self.v_lines.iter_mut().chain(self.m_lines.iter_mut()) { |
| 451 | line.reposition(self.effective_bounds, self.reverse_points); |
| 452 | } |
| 453 | self.v_lines.shrink_to_fit(); |
| 454 | self.m_lines.shrink_to_fit(); |
| 455 | } |
| 456 | glyph.v_lines = self.v_lines; |
| 457 | glyph.m_lines = self.m_lines; |
| 458 | glyph.bounds = OutlineBounds { |
| 459 | xmin: self.effective_bounds.xmin, |
| 460 | ymin: self.effective_bounds.ymin, |
| 461 | width: self.effective_bounds.xmax - self.effective_bounds.xmin, |
| 462 | height: self.effective_bounds.ymax - self.effective_bounds.ymin, |
| 463 | }; |
| 464 | } |
| 465 | |
| 466 | fn recalculate_bounds(bounds: &mut AABB, x: f32, y: f32) { |
| 467 | if x < bounds.xmin { |
| 468 | bounds.xmin = x; |
| 469 | } |
| 470 | if x > bounds.xmax { |
| 471 | bounds.xmax = x; |
| 472 | } |
| 473 | if y < bounds.ymin { |
| 474 | bounds.ymin = y; |
| 475 | } |
| 476 | if y > bounds.ymax { |
| 477 | bounds.ymax = y; |
| 478 | } |
| 479 | } |
| 480 | } |
| 481 | |