mod edges;
mod segments;
use super::{
metrics::ScaledWidth,
outline::{Direction, Orientation, Point},
};
use crate::collections::SmallVec;
pub(crate) use edges::{compute_blue_edges, compute_edges};
pub(crate) use segments::{compute_segments, link_segments};
const MAX_INLINE_SEGMENTS: usize = 18;
const MAX_INLINE_EDGES: usize = 12;
pub type Dimension = usize;
#[derive(Clone, Default, Debug)]
pub(crate) struct Axis {
pub dim: Dimension,
pub major_dir: Direction,
pub segments: SmallVec<Segment, MAX_INLINE_SEGMENTS>,
pub edges: SmallVec<Edge, MAX_INLINE_EDGES>,
}
impl Axis {
pub const HORIZONTAL: Dimension = 0;
pub const VERTICAL: Dimension = 1;
}
impl Axis {
#[cfg(test)]
pub fn new(dim: Dimension, orientation: Option<Orientation>) -> Self {
let mut axis = Self::default();
axis.reset(dim, orientation);
axis
}
pub fn reset(&mut self, dim: Dimension, orientation: Option<Orientation>) {
self.dim = dim;
self.major_dir = match (dim, orientation) {
(Self::HORIZONTAL, Some(Orientation::Clockwise)) => Direction::Down,
(Self::VERTICAL, Some(Orientation::Clockwise)) => Direction::Right,
(Self::HORIZONTAL, _) => Direction::Up,
(Self::VERTICAL, _) => Direction::Left,
_ => Direction::None,
};
self.segments.clear();
self.edges.clear();
}
}
impl Axis {
pub fn insert_edge(&mut self, edge: Edge, top_to_bottom_hinting: bool) {
self.edges.push(edge);
let edges = self.edges.as_mut_slice();
if edges.len() == 1 {
return;
}
let mut ix = edges.len() - 1;
while ix > 0 {
let prev_ix = ix - 1;
let prev_fpos = edges[prev_ix].fpos;
if (top_to_bottom_hinting && prev_fpos > edge.fpos)
|| (!top_to_bottom_hinting && prev_fpos < edge.fpos)
{
break;
}
if prev_fpos == edge.fpos && edge.dir == self.major_dir {
break;
}
let prev_edge = edges[prev_ix];
edges[ix] = prev_edge;
ix -= 1;
}
edges[ix] = edge;
}
pub fn append_segment_to_edge(&mut self, segment_ix: usize, edge_ix: usize) {
let edge = &mut self.edges[edge_ix];
let first_ix = edge.first_ix;
let last_ix = edge.last_ix;
edge.last_ix = segment_ix as u16;
let segment = &mut self.segments[segment_ix];
segment.edge_next_ix = Some(first_ix);
self.segments[last_ix as usize].edge_next_ix = Some(segment_ix as u16);
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
pub(crate) struct Segment {
pub flags: u8,
pub dir: Direction,
pub pos: i16,
pub delta: i16,
pub min_coord: i16,
pub max_coord: i16,
pub height: i16,
pub score: i32,
pub len: i32,
pub link_ix: Option<u16>,
pub serif_ix: Option<u16>,
pub first_ix: u16,
pub last_ix: u16,
pub edge_ix: Option<u16>,
pub edge_next_ix: Option<u16>,
}
impl Segment {
pub const NORMAL: u8 = 0;
pub const ROUND: u8 = 1;
pub const SERIF: u8 = 2;
pub const DONE: u8 = 4;
pub const NEUTRAL: u8 = 8;
}
impl Segment {
pub fn first(&self) -> usize {
self.first_ix as usize
}
pub fn first_point<'a>(&self, points: &'a [Point]) -> &'a Point {
&points[self.first()]
}
pub fn last(&self) -> usize {
self.last_ix as usize
}
pub fn last_point<'a>(&self, points: &'a [Point]) -> &'a Point {
&points[self.last()]
}
pub fn edge<'a>(&self, edges: &'a [Edge]) -> Option<&'a Edge> {
edges.get(self.edge_ix.map(|ix| ix as usize)?)
}
pub fn next_in_edge<'a>(&self, segments: &'a [Segment]) -> Option<&'a Segment> {
segments.get(self.edge_next_ix.map(|ix| ix as usize)?)
}
pub fn link<'a>(&self, segments: &'a [Segment]) -> Option<&'a Segment> {
segments.get(self.link_ix.map(|ix| ix as usize)?)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
pub(crate) struct Edge {
pub fpos: i16,
pub opos: i32,
pub pos: i32,
pub flags: u8,
pub dir: Direction,
pub blue_edge: Option<ScaledWidth>,
pub link_ix: Option<u16>,
pub serif_ix: Option<u16>,
pub scale: i32,
pub first_ix: u16,
pub last_ix: u16,
}
impl Edge {
pub const NORMAL: u8 = Segment::NORMAL;
pub const ROUND: u8 = Segment::ROUND;
pub const SERIF: u8 = Segment::SERIF;
pub const DONE: u8 = Segment::DONE;
pub const NEUTRAL: u8 = Segment::NEUTRAL;
}
impl Edge {
pub fn link<'a>(&self, edges: &'a [Edge]) -> Option<&'a Edge> {
edges.get(self.link_ix.map(|ix| ix as usize)?)
}
pub fn serif<'a>(&self, edges: &'a [Edge]) -> Option<&'a Edge> {
edges.get(self.serif_ix.map(|ix| ix as usize)?)
}
}