Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
480
third-party/vendor/fontdue/src/math.rs
vendored
Normal file
480
third-party/vendor/fontdue/src/math.rs
vendored
Normal file
|
|
@ -0,0 +1,480 @@
|
|||
use crate::platform::{self, abs, atan2, f32x4, sqrt};
|
||||
use crate::{Glyph, OutlineBounds};
|
||||
use alloc::vec;
|
||||
use alloc::vec::*;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
struct AABB {
|
||||
/// Coordinate of the left-most edge.
|
||||
xmin: f32,
|
||||
/// Coordinate of the right-most edge.
|
||||
xmax: f32,
|
||||
/// Coordinate of the bottom-most edge.
|
||||
ymin: f32,
|
||||
/// Coordinate of the top-most edge.
|
||||
ymax: f32,
|
||||
}
|
||||
|
||||
impl Default for AABB {
|
||||
fn default() -> Self {
|
||||
AABB {
|
||||
xmin: 0.0,
|
||||
xmax: 0.0,
|
||||
ymin: 0.0,
|
||||
ymax: 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
struct CubeCurve {
|
||||
a: Point,
|
||||
b: Point,
|
||||
c: Point,
|
||||
d: Point,
|
||||
}
|
||||
|
||||
impl CubeCurve {
|
||||
const fn new(a: Point, b: Point, c: Point, d: Point) -> CubeCurve {
|
||||
CubeCurve {
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
d,
|
||||
}
|
||||
}
|
||||
|
||||
fn scale(&self, scale: f32) -> CubeCurve {
|
||||
CubeCurve {
|
||||
a: self.a.scale(scale),
|
||||
b: self.b.scale(scale),
|
||||
c: self.c.scale(scale),
|
||||
d: self.d.scale(scale),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_flat(&self, threshold: f32) -> bool {
|
||||
let (d1, d2, d3, d4) = f32x4::new(
|
||||
self.a.distance_squared(self.b),
|
||||
self.b.distance_squared(self.c),
|
||||
self.c.distance_squared(self.d),
|
||||
self.a.distance_squared(self.d),
|
||||
)
|
||||
.sqrt()
|
||||
.copied();
|
||||
(d1 + d2 + d3) < threshold * d4
|
||||
}
|
||||
|
||||
fn split(&self) -> (CubeCurve, CubeCurve) {
|
||||
let q0 = self.a.midpoint(self.b);
|
||||
let q1 = self.b.midpoint(self.c);
|
||||
let q2 = self.c.midpoint(self.d);
|
||||
let r0 = q0.midpoint(q1);
|
||||
let r1 = q1.midpoint(q2);
|
||||
let s0 = r0.midpoint(r1);
|
||||
(CubeCurve::new(self.a, q0, r0, s0), CubeCurve::new(s0, r1, q2, self.d))
|
||||
}
|
||||
|
||||
/// The point at time t in the curve.
|
||||
fn point(&self, t: f32) -> Point {
|
||||
let tm = 1.0 - t;
|
||||
let a = tm * tm * tm;
|
||||
let b = 3.0 * (tm * tm) * t;
|
||||
let c = 3.0 * tm * (t * t);
|
||||
let d = t * t * t;
|
||||
|
||||
let x = a * self.a.x + b * self.b.x + c * self.c.x + d * self.d.x;
|
||||
let y = a * self.a.y + b * self.b.y + c * self.c.y + d * self.d.y;
|
||||
Point::new(x, y)
|
||||
}
|
||||
|
||||
/// The slope of the tangent line at time t.
|
||||
fn slope(&self, t: f32) -> (f32, f32) {
|
||||
let tm = 1.0 - t;
|
||||
let a = 3.0 * (tm * tm);
|
||||
let b = 6.0 * tm * t;
|
||||
let c = 3.0 * (t * t);
|
||||
|
||||
let x = a * (self.b.x - self.a.x) + b * (self.c.x - self.b.x) + c * (self.d.x - self.c.x);
|
||||
let y = a * (self.b.y - self.a.y) + b * (self.c.y - self.b.y) + c * (self.d.y - self.c.y);
|
||||
(x, y)
|
||||
}
|
||||
|
||||
/// The angle of the tangent line at time t in rads.
|
||||
fn angle(&self, t: f32) -> f32 {
|
||||
let (x, y) = self.slope(t);
|
||||
abs(atan2(x, y))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
struct QuadCurve {
|
||||
a: Point,
|
||||
b: Point,
|
||||
c: Point,
|
||||
}
|
||||
|
||||
impl QuadCurve {
|
||||
fn new(a: Point, b: Point, c: Point) -> QuadCurve {
|
||||
QuadCurve {
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
}
|
||||
}
|
||||
|
||||
fn scale(&self, scale: f32) -> QuadCurve {
|
||||
QuadCurve {
|
||||
a: self.a.scale(scale),
|
||||
b: self.b.scale(scale),
|
||||
c: self.c.scale(scale),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_flat(&self, threshold: f32) -> bool {
|
||||
let (d1, d2, d3, _) = f32x4::new(
|
||||
self.a.distance_squared(self.b),
|
||||
self.b.distance_squared(self.c),
|
||||
self.a.distance_squared(self.c),
|
||||
1.0,
|
||||
)
|
||||
.sqrt()
|
||||
.copied();
|
||||
(d1 + d2) < threshold * d3
|
||||
}
|
||||
|
||||
fn split(&self) -> (QuadCurve, QuadCurve) {
|
||||
let q0 = self.a.midpoint(self.b);
|
||||
let q1 = self.b.midpoint(self.c);
|
||||
let r0 = q0.midpoint(q1);
|
||||
(QuadCurve::new(self.a, q0, r0), QuadCurve::new(r0, q1, self.c))
|
||||
}
|
||||
|
||||
/// The point at time t in the curve.
|
||||
fn point(&self, t: f32) -> Point {
|
||||
let tm = 1.0 - t;
|
||||
let a = tm * tm;
|
||||
let b = 2.0 * tm * t;
|
||||
let c = t * t;
|
||||
|
||||
let x = a * self.a.x + b * self.b.x + c * self.c.x;
|
||||
let y = a * self.a.y + b * self.b.y + c * self.c.y;
|
||||
Point::new(x, y)
|
||||
}
|
||||
|
||||
/// The slope of the tangent line at time t.
|
||||
fn slope(&self, t: f32) -> (f32, f32) {
|
||||
let tm = 1.0 - t;
|
||||
let a = 2.0 * tm;
|
||||
let b = 2.0 * t;
|
||||
|
||||
let x = a * (self.b.x - self.a.x) + b * (self.c.x - self.b.x);
|
||||
let y = a * (self.b.y - self.a.y) + b * (self.c.y - self.b.y);
|
||||
(x, y)
|
||||
}
|
||||
|
||||
/// The angle of the tangent line at time t in rads.
|
||||
fn angle(&self, t: f32) -> f32 {
|
||||
let (x, y) = self.slope(t);
|
||||
abs(atan2(x, y))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub struct Point {
|
||||
/// Absolute X coordinate.
|
||||
pub x: f32,
|
||||
/// Absolute Y coordinate.
|
||||
pub y: f32,
|
||||
}
|
||||
|
||||
impl Default for Point {
|
||||
fn default() -> Self {
|
||||
Point {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Point {
|
||||
pub const fn new(x: f32, y: f32) -> Point {
|
||||
Point {
|
||||
x,
|
||||
y,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scale(&self, scale: f32) -> Point {
|
||||
Point {
|
||||
x: self.x * scale,
|
||||
y: self.y * scale,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn distance_squared(&self, other: Point) -> f32 {
|
||||
let x = self.x - other.x;
|
||||
let y = self.y - other.y;
|
||||
x * x + y * y
|
||||
}
|
||||
|
||||
pub fn distance(&self, other: Point) -> f32 {
|
||||
let x = self.x - other.x;
|
||||
let y = self.y - other.y;
|
||||
sqrt(x * x + y * y)
|
||||
}
|
||||
|
||||
pub fn midpoint(&self, other: Point) -> Point {
|
||||
Point {
|
||||
x: (self.x + other.x) / 2.0,
|
||||
y: (self.y + other.y) / 2.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Line {
|
||||
/// X0, Y0, X1, Y1.
|
||||
pub coords: f32x4,
|
||||
/// start_x_nudge, start_y_nudge, end_x_nudge, end_y_nudge.
|
||||
pub nudge: f32x4,
|
||||
/// x_first_adj, y_first_adj, none, none.
|
||||
pub adjustment: f32x4,
|
||||
/// tdx, tdy, dx, dy.
|
||||
pub params: f32x4,
|
||||
}
|
||||
|
||||
impl Line {
|
||||
pub fn new(start: Point, end: Point) -> Line {
|
||||
// Floor adjustment and nudge: 0.0, 0
|
||||
// Ceil adjustment and nudge: 1.0, 1
|
||||
const FLOOR_NUDGE: u32 = 0;
|
||||
const CEIL_NUDGE: u32 = 1;
|
||||
|
||||
let (x_start_nudge, x_first_adj) = if end.x >= start.x {
|
||||
(FLOOR_NUDGE, 1.0)
|
||||
} else {
|
||||
(CEIL_NUDGE, 0.0)
|
||||
};
|
||||
let (y_start_nudge, y_first_adj) = if end.y >= start.y {
|
||||
(FLOOR_NUDGE, 1.0)
|
||||
} else {
|
||||
(CEIL_NUDGE, 0.0)
|
||||
};
|
||||
|
||||
let x_end_nudge = if end.x > start.x {
|
||||
CEIL_NUDGE
|
||||
} else {
|
||||
FLOOR_NUDGE
|
||||
};
|
||||
let y_end_nudge = if end.y > start.y {
|
||||
CEIL_NUDGE
|
||||
} else {
|
||||
FLOOR_NUDGE
|
||||
};
|
||||
|
||||
let dx = end.x - start.x;
|
||||
let dy = end.y - start.y;
|
||||
let tdx = if dx == 0.0 {
|
||||
core::f32::MAX
|
||||
} else {
|
||||
1.0 / dx
|
||||
};
|
||||
let tdy = 1.0 / dy;
|
||||
|
||||
Line {
|
||||
coords: f32x4::new(start.x, start.y, end.x, end.y),
|
||||
nudge: f32x4::new_u32(x_start_nudge, y_start_nudge, x_end_nudge, y_end_nudge),
|
||||
adjustment: f32x4::new(x_first_adj, y_first_adj, 0.0, 0.0),
|
||||
params: f32x4::new(tdx, tdy, dx, dy),
|
||||
}
|
||||
}
|
||||
|
||||
fn reposition(&mut self, bounds: AABB, reverse: bool) {
|
||||
let (mut x0, mut y0, mut x1, mut y1) = if !reverse {
|
||||
self.coords.copied()
|
||||
} else {
|
||||
let (x0, y0, x1, y1) = self.coords.copied();
|
||||
(x1, y1, x0, y0)
|
||||
};
|
||||
|
||||
x0 -= bounds.xmin;
|
||||
y0 -= bounds.ymax;
|
||||
y0 = abs(y0);
|
||||
|
||||
x1 -= bounds.xmin;
|
||||
y1 -= bounds.ymax;
|
||||
y1 = abs(y1);
|
||||
|
||||
*self = Self::new(Point::new(x0, y0), Point::new(x1, y1));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Geometry {
|
||||
v_lines: Vec<Line>,
|
||||
m_lines: Vec<Line>,
|
||||
effective_bounds: AABB,
|
||||
start_point: Point,
|
||||
previous_point: Point,
|
||||
area: f32,
|
||||
reverse_points: bool,
|
||||
max_area: f32,
|
||||
}
|
||||
|
||||
struct Segment {
|
||||
a: Point,
|
||||
at: f32,
|
||||
c: Point,
|
||||
ct: f32,
|
||||
}
|
||||
|
||||
impl Segment {
|
||||
const fn new(a: Point, at: f32, c: Point, ct: f32) -> Segment {
|
||||
Segment {
|
||||
a,
|
||||
at,
|
||||
c,
|
||||
ct,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ttf_parser::OutlineBuilder for Geometry {
|
||||
fn move_to(&mut self, x0: f32, y0: f32) {
|
||||
let next_point = Point::new(x0, y0);
|
||||
self.start_point = next_point;
|
||||
self.previous_point = next_point;
|
||||
}
|
||||
|
||||
fn line_to(&mut self, x0: f32, y0: f32) {
|
||||
let next_point = Point::new(x0, y0);
|
||||
self.push(self.previous_point, next_point);
|
||||
self.previous_point = next_point;
|
||||
}
|
||||
|
||||
fn quad_to(&mut self, x0: f32, y0: f32, x1: f32, y1: f32) {
|
||||
let control_point = Point::new(x0, y0);
|
||||
let next_point = Point::new(x1, y1);
|
||||
|
||||
let curve = QuadCurve::new(self.previous_point, control_point, next_point);
|
||||
let mut stack = vec![Segment::new(self.previous_point, 0.0, next_point, 1.0)];
|
||||
while let Some(seg) = stack.pop() {
|
||||
let bt = (seg.at + seg.ct) * 0.5;
|
||||
let b = curve.point(bt);
|
||||
// This is twice the triangle area
|
||||
let area = (b.x - seg.a.x) * (seg.c.y - seg.a.y) - (seg.c.x - seg.a.x) * (b.y - seg.a.y);
|
||||
if platform::abs(area) > self.max_area {
|
||||
stack.push(Segment::new(seg.a, seg.at, b, bt));
|
||||
stack.push(Segment::new(b, bt, seg.c, seg.ct));
|
||||
} else {
|
||||
self.push(seg.a, seg.c);
|
||||
}
|
||||
}
|
||||
|
||||
self.previous_point = next_point;
|
||||
}
|
||||
|
||||
fn curve_to(&mut self, x0: f32, y0: f32, x1: f32, y1: f32, x2: f32, y2: f32) {
|
||||
let first_control = Point::new(x0, y0);
|
||||
let second_control = Point::new(x1, y1);
|
||||
let next_point = Point::new(x2, y2);
|
||||
|
||||
let curve = CubeCurve::new(self.previous_point, first_control, second_control, next_point);
|
||||
let mut stack = vec![Segment::new(self.previous_point, 0.0, next_point, 1.0)];
|
||||
while let Some(seg) = stack.pop() {
|
||||
let bt = (seg.at + seg.ct) * 0.5;
|
||||
let b = curve.point(bt);
|
||||
// This is twice the triangle area
|
||||
let area = (b.x - seg.a.x) * (seg.c.y - seg.a.y) - (seg.c.x - seg.a.x) * (b.y - seg.a.y);
|
||||
if platform::abs(area) > self.max_area {
|
||||
stack.push(Segment::new(seg.a, seg.at, b, bt));
|
||||
stack.push(Segment::new(b, bt, seg.c, seg.ct));
|
||||
} else {
|
||||
self.push(seg.a, seg.c);
|
||||
}
|
||||
}
|
||||
self.previous_point = next_point;
|
||||
}
|
||||
|
||||
fn close(&mut self) {
|
||||
if self.start_point != self.previous_point {
|
||||
self.push(self.previous_point, self.start_point);
|
||||
}
|
||||
self.previous_point = self.start_point;
|
||||
}
|
||||
}
|
||||
|
||||
impl Geometry {
|
||||
// Artisanal bespoke hand carved curves
|
||||
pub fn new(scale: f32, units_per_em: f32) -> Geometry {
|
||||
const ERROR_THRESHOLD: f32 = 3.0; // In pixels.
|
||||
let max_area = ERROR_THRESHOLD * 2.0 * (units_per_em / scale);
|
||||
|
||||
Geometry {
|
||||
v_lines: Vec::new(),
|
||||
m_lines: Vec::new(),
|
||||
effective_bounds: AABB {
|
||||
xmin: core::f32::MAX,
|
||||
xmax: core::f32::MIN,
|
||||
ymin: core::f32::MAX,
|
||||
ymax: core::f32::MIN,
|
||||
},
|
||||
start_point: Point::default(),
|
||||
previous_point: Point::default(),
|
||||
area: 0.0,
|
||||
reverse_points: false,
|
||||
max_area,
|
||||
}
|
||||
}
|
||||
|
||||
fn push(&mut self, start: Point, end: Point) {
|
||||
// We're using to_bits here because we only care if they're _exactly_ the same.
|
||||
if start.y.to_bits() != end.y.to_bits() {
|
||||
self.area += (end.y - start.y) * (end.x + start.x);
|
||||
if start.x.to_bits() == end.x.to_bits() {
|
||||
self.v_lines.push(Line::new(start, end));
|
||||
} else {
|
||||
self.m_lines.push(Line::new(start, end));
|
||||
}
|
||||
Self::recalculate_bounds(&mut self.effective_bounds, start.x, start.y);
|
||||
Self::recalculate_bounds(&mut self.effective_bounds, end.x, end.y);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn finalize(mut self, glyph: &mut Glyph) {
|
||||
if self.v_lines.is_empty() && self.m_lines.is_empty() {
|
||||
self.effective_bounds = AABB::default();
|
||||
} else {
|
||||
self.reverse_points = self.area > 0.0;
|
||||
for line in self.v_lines.iter_mut().chain(self.m_lines.iter_mut()) {
|
||||
line.reposition(self.effective_bounds, self.reverse_points);
|
||||
}
|
||||
self.v_lines.shrink_to_fit();
|
||||
self.m_lines.shrink_to_fit();
|
||||
}
|
||||
glyph.v_lines = self.v_lines;
|
||||
glyph.m_lines = self.m_lines;
|
||||
glyph.bounds = OutlineBounds {
|
||||
xmin: self.effective_bounds.xmin,
|
||||
ymin: self.effective_bounds.ymin,
|
||||
width: self.effective_bounds.xmax - self.effective_bounds.xmin,
|
||||
height: self.effective_bounds.ymax - self.effective_bounds.ymin,
|
||||
};
|
||||
}
|
||||
|
||||
fn recalculate_bounds(bounds: &mut AABB, x: f32, y: f32) {
|
||||
if x < bounds.xmin {
|
||||
bounds.xmin = x;
|
||||
}
|
||||
if x > bounds.xmax {
|
||||
bounds.xmax = x;
|
||||
}
|
||||
if y < bounds.ymin {
|
||||
bounds.ymin = y;
|
||||
}
|
||||
if y > bounds.ymax {
|
||||
bounds.ymax = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue