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};
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
pub struct BlueProvenance {
pub index: u16,
pub is_shoot: bool,
}
const MAX_INLINE_SEGMENTS: usize = 18;
const MAX_INLINE_EDGES: usize = 12;
#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
pub enum Dimension {
#[default]
Horizontal = 0,
Vertical = 1,
}
impl<T> core::ops::Index<Dimension> for [T] {
type Output = T;
fn index(&self, index: Dimension) -> &Self::Output {
&self[index as usize]
}
}
#[derive(Clone, Default, Debug)]
pub struct Axis {
pub(crate) dim: Dimension,
pub(crate) major_dir: Direction,
pub(crate) segments: SmallVec<Segment, MAX_INLINE_SEGMENTS>,
pub(crate) edges: SmallVec<Edge, MAX_INLINE_EDGES>,
}
impl Axis {
pub fn dimension(&self) -> Dimension {
self.dim
}
pub fn major_direction(&self) -> Direction {
self.major_dir
}
pub fn segments(&self) -> &[Segment] {
self.segments.as_slice()
}
pub fn edges(&self) -> &[Edge] {
self.edges.as_slice()
}
}
impl Axis {
#[cfg(test)]
pub(crate) fn new(dim: Dimension, orientation: Option<Orientation>) -> Self {
let mut axis = Self::default();
axis.reset(dim, orientation);
axis
}
pub(crate) fn reset(&mut self, dim: Dimension, orientation: Option<Orientation>) {
self.dim = dim;
self.major_dir = match (dim, orientation) {
(Dimension::Horizontal, Some(Orientation::Clockwise)) => Direction::Down,
(Dimension::Vertical, Some(Orientation::Clockwise)) => Direction::Right,
(Dimension::Horizontal, _) => Direction::Up,
(Dimension::Vertical, _) => Direction::Left,
};
self.segments.clear();
self.edges.clear();
}
pub(crate) 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(crate) 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, Default, Debug)]
pub struct TopoFlags(pub(crate) u8);
impl TopoFlags {
pub const NORMAL: Self = Self(0);
pub const ROUND: Self = Self(1);
pub const SERIF: Self = Self(2);
pub const DONE: Self = Self(4);
pub const NEUTRAL: Self = Self(8);
}
impl TopoFlags {
pub const fn from_bits_truncate(bits: u8) -> Self {
Self(bits & 0b1111)
}
pub const fn to_bits(self) -> u8 {
self.0
}
pub const fn contains(self, other: Self) -> bool {
(self.0 & other.0) == other.0
}
pub const fn intersects(self, other: Self) -> bool {
(self.0 & other.0) != 0
}
}
impl core::ops::Not for TopoFlags {
type Output = Self;
fn not(self) -> Self::Output {
Self(!self.0)
}
}
impl core::ops::BitOr for TopoFlags {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
impl core::ops::BitOrAssign for TopoFlags {
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
}
impl core::ops::BitAnd for TopoFlags {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output {
Self(self.0 & rhs.0)
}
}
impl core::ops::BitAndAssign for TopoFlags {
fn bitand_assign(&mut self, rhs: Self) {
self.0 &= rhs.0;
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
pub struct Segment {
pub(crate) flags: TopoFlags,
pub(crate) dir: Direction,
pub(crate) pos: i16,
pub(crate) delta: i16,
pub(crate) min_coord: i16,
pub(crate) max_coord: i16,
pub(crate) height: i16,
pub(crate) score: i32,
pub(crate) len: i32,
pub(crate) link_ix: Option<u16>,
pub(crate) serif_ix: Option<u16>,
pub(crate) first_ix: u16,
pub(crate) last_ix: u16,
pub(crate) edge_ix: Option<u16>,
pub(crate) edge_next_ix: Option<u16>,
}
impl Segment {
pub fn flags(&self) -> TopoFlags {
self.flags
}
pub fn direction(&self) -> Direction {
self.dir
}
pub fn position(&self) -> i16 {
self.pos
}
pub fn delta(&self) -> i16 {
self.delta
}
pub fn min_coord(&self) -> i16 {
self.min_coord
}
pub fn max_coord(&self) -> i16 {
self.max_coord
}
pub fn height(&self) -> i16 {
self.height
}
pub fn score(&self) -> i32 {
self.score
}
pub fn length(&self) -> i32 {
self.len
}
pub fn link_index(&self) -> Option<u16> {
self.link_ix
}
pub fn serif_index(&self) -> Option<u16> {
self.serif_ix
}
pub fn point_indices(&self) -> (u16, u16) {
(self.first_ix, self.last_ix)
}
pub fn edge_index(&self) -> Option<u16> {
self.edge_ix
}
pub fn next_in_edge_index(&self) -> Option<u16> {
self.edge_next_ix
}
}
impl Segment {
pub(crate) fn first(&self) -> usize {
self.first_ix as usize
}
pub(crate) fn first_point<'a>(&self, points: &'a [Point]) -> &'a Point {
&points[self.first()]
}
pub(crate) fn last(&self) -> usize {
self.last_ix as usize
}
pub(crate) fn last_point<'a>(&self, points: &'a [Point]) -> &'a Point {
&points[self.last()]
}
pub(crate) fn edge<'a>(&self, edges: &'a [Edge]) -> Option<&'a Edge> {
edges.get(self.edge_ix.map(|ix| ix as usize)?)
}
pub(crate) fn next_in_edge<'a>(&self, segments: &'a [Segment]) -> Option<&'a Segment> {
segments.get(self.edge_next_ix.map(|ix| ix as usize)?)
}
pub(crate) 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 struct Edge {
pub(crate) fpos: i16,
pub(crate) opos: i32,
pub(crate) pos: i32,
pub(crate) flags: TopoFlags,
pub(crate) dir: Direction,
pub(crate) blue_edge: Option<ScaledWidth>,
pub(crate) blue_provenance: Option<BlueProvenance>,
pub(crate) link_ix: Option<u16>,
pub(crate) serif_ix: Option<u16>,
pub(crate) scale: i32,
pub(crate) first_ix: u16,
pub(crate) last_ix: u16,
}
impl Edge {
pub fn original_position(&self) -> i16 {
self.fpos
}
pub fn scaled_position(&self) -> i32 {
self.opos
}
pub fn position(&self) -> i32 {
self.pos
}
pub fn flags(&self) -> TopoFlags {
self.flags
}
pub fn direction(&self) -> Direction {
self.dir
}
pub fn blue_edge(&self) -> Option<ScaledWidth> {
self.blue_edge
}
pub fn blue_provenance(&self) -> Option<BlueProvenance> {
self.blue_provenance
}
pub fn link_index(&self) -> Option<u16> {
self.link_ix
}
pub fn serif_index(&self) -> Option<u16> {
self.serif_ix
}
pub fn scale(&self) -> i32 {
self.scale
}
pub fn segment_indices(&self) -> (u16, u16) {
(self.first_ix, self.last_ix)
}
}
impl Edge {
pub(crate) fn link<'a>(&self, edges: &'a [Edge]) -> Option<&'a Edge> {
edges.get(self.link_ix.map(|ix| ix as usize)?)
}
pub(crate) fn serif<'a>(&self, edges: &'a [Edge]) -> Option<&'a Edge> {
edges.get(self.serif_ix.map(|ix| ix as usize)?)
}
}