Skip to content

Instantly share code, notes, and snippets.

@ctrlcctrlv
Created March 24, 2021 02:49
Show Gist options
  • Select an option

  • Save ctrlcctrlv/2b75fd25b6ac531eb2c01670f0541730 to your computer and use it in GitHub Desktop.

Select an option

Save ctrlcctrlv/2b75fd25b6ac531eb2c01670f0541730 to your computer and use it in GitHub Desktop.
Nib stroker from FontForge (WIP 2)
#![feature(fn_traits)]
use fontforge_sys as fontforge;
use glifparser;
use std::fs;
use std::os::raw;
use std::ops::Fn;
use std::ptr;
#[derive(Default, Debug, PartialEq)]
struct SplinePointBitField {
nonextcp: raw::c_uint,
noprevcp: raw::c_uint,
nextcpdef: raw::c_uint,
prevcpdef: raw::c_uint,
selected: raw::c_uint,
nextcpselected: raw::c_uint,
prevcpselected: raw::c_uint,
pointtype: raw::c_uint,
isintersection: raw::c_uint,
flexy: raw::c_uint,
flexx: raw::c_uint,
roundx: raw::c_uint,
roundy: raw::c_uint,
dontinterpolate: raw::c_uint,
ticked: raw::c_uint,
watched: raw::c_uint,
}
#[derive(Default, Debug, PartialEq)]
struct SplineBitField {
islinear: raw::c_uint,
isquadratic: raw::c_uint,
isticked: raw::c_uint,
isneeded: raw::c_uint,
isunneeded: raw::c_uint,
exclude: raw::c_uint,
ishorvert: raw::c_uint,
knowncurved: raw::c_uint,
knownlinear: raw::c_uint,
order2: raw::c_uint,
touched: raw::c_uint,
leftedge: raw::c_uint,
rightedge: raw::c_uint,
acceptableextrema: raw::c_uint,
}
impl SplinePointBitField {
fn to_bitfield(self) -> (u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32) {
return (self.nonextcp, self.noprevcp, self.nextcpdef, self.prevcpdef, self.selected, self.nextcpselected, self.prevcpselected, self.pointtype, self.isintersection, self.flexy, self.flexx, self.roundx, self.roundy, self.dontinterpolate, self.ticked, self.watched);
}
}
impl SplineBitField {
fn to_bitfield(self) -> (u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32) {
return (self.islinear, self.isquadratic, self.isticked, self.isneeded, self.isunneeded, self.exclude, self.ishorvert, self.knowncurved, self.knownlinear, self.order2, self.touched, self.leftedge, self.rightedge, self.acceptableextrema);
}
}
#[derive(Debug)]
struct FFContour {
data: Vec<Box<fontforge::SplinePoint>>,
open: bool
}
// This function isn't close to done, don't bother reading it lol
fn ffsplineset_to_outline(ss_in: fontforge::SplineSet) -> glifparser::Outline<()> {
let ret = glifparser::Outline::new();
let mut splinesets;
unsafe {
let mut ss = ss_in;
splinesets = vec![ss];
while ss.next != 0 as *mut _ {
splinesets.push(*ss.next);
ss = *ss.next
}
}
println!("Splinesets: {:?}", splinesets);
ret
}
fn make_spline(from: *mut fontforge::SplinePoint, to: *mut fontforge::SplinePoint, order2: bool) -> *mut fontforge::Spline {
unsafe {
let s = fontforge::SplineMake(from, to, order2 as raw::c_int);
fontforge::SplineRefigure(s);
s
}
}
fn glif_to_ffsplineset<T>(glif: glifparser::Glif<T>) -> (fontforge::SplineSet, Vec<Vec<fontforge::SplinePoint>>) {
let mut ffsps = vec![];
for c in glif.outline.unwrap().iter() {
let mut cffsps = vec![];
for (idx, p) in c.iter().enumerate() {
let bp0_1 = fontforge::BasePoint {x: p.x as f64, y: p.y as f64};
let (ax, ay) = p.handle_or_colocated(glifparser::WhichHandle::A, |f|f, |f|f);
let bp0_2 = fontforge::BasePoint {x: ax as f64, y: ay as f64};
let (bx, by) = p.handle_or_colocated(glifparser::WhichHandle::B, |f|f, |f|f);
let bp0_3 = fontforge::BasePoint {x: bx as f64, y: by as f64};
let mut spbf = SplinePointBitField{..Default::default()};
spbf.noprevcp = (p.a == glifparser::Handle::Colocated) as u32;
spbf.nonextcp = (p.b == glifparser::Handle::Colocated) as u32;
let bf = Fn::call(&fontforge::splinepoint::new_bitfield_1, spbf.to_bitfield());
let sp = fontforge::SplinePoint {
me: bp0_1,
prevcp: bp0_2,
nextcp: bp0_3,
_bitfield_align_1: [],
_bitfield_1: bf,
ptindex: idx as u16,
// These are for TrueType fonts and don't matter to us.
ttfindex: 0, nextcpindex: 0,
next: 0 as *mut _,
prev: 0 as *mut _,
hintmask: 0 as *mut _,
name: 0 as *mut _
};
cffsps.push(sp);
}
let cffsps_len = cffsps.len();
for idx in 0..cffsps_len {
if idx == 0 {
if c[0].ptype != glifparser::PointType::Move {
cffsps[0].prev = make_spline(&mut cffsps[idx] as *mut _, &mut cffsps[cffsps_len-1] as *mut _, false);
} else {
cffsps[0].prev = 0 as *mut _;
}
cffsps[0].next = make_spline(&mut cffsps[idx] as *mut _, &mut cffsps[idx+1] as *mut _, false);
} else if idx == cffsps_len-1 {
cffsps[idx].prev = make_spline(&mut cffsps[idx] as *mut _, &mut cffsps[idx-1] as *mut _, false);
if c[0].ptype != glifparser::PointType::Move {
cffsps[idx].next = make_spline(&mut cffsps[idx] as *mut _, &mut cffsps[0] as *mut _, false);
} else {
cffsps[idx].next = 0 as *mut _;
}
} else {
cffsps[idx].prev = make_spline(&mut cffsps[idx] as *mut _, &mut cffsps[idx-1] as *mut _, false);
cffsps[idx].next = make_spline(&mut cffsps[idx] as *mut _, &mut cffsps[idx+1] as *mut _, false);
}
println!("{} {:?} {:?}", idx, cffsps[idx].prev, cffsps[idx].next);
}
ffsps.push(cffsps);
}
let mut ffsss = vec![];
for spl in ffsps.iter_mut() {
ffsss.push(fontforge::SplineSet {
first: spl.first_mut().unwrap(),
last: spl.last_mut().unwrap(),
next: 0 as *mut _,
spiros: 0 as *mut _,
spiro_cnt: 0, spiro_max: 0, ticked: 0,
beziers_need_optimizer: 1, is_clip_path: 0,
start_offset: 0,
contour_name: 0 as *mut _
});
}
for idx in 0..ffsss.len() {
if idx == ffsss.len()-1 {
break
} else {
ffsss[idx].next = Box::new(ffsss[idx+1]).as_mut()
}
}
// We return ffsps so its valuable data doesn't go out of scope.
(ffsss[0], ffsps)
}
#[test]
fn convert_glif() {
let nibglif: glifparser::Glif<()> = glifparser::read_ufo_glif(&fs::read_to_string("nib.glif").unwrap());
let (mut nibss_raw, mut _nibss_ffsps) = glif_to_ffsplineset(nibglif);
let ssglif: glifparser::Glif<()> = glifparser::read_ufo_glif(&fs::read_to_string("l.glif").unwrap());
let (mut ss_raw, mut _ss_ffsps) = glif_to_ffsplineset(ssglif);
let mut nibss_boxed = Box::new(nibss_raw);
let mut ss_boxed = Box::new(ss_raw);
let mut nibss = nibss_boxed.as_mut();
let mut ss = ss_boxed.as_mut();
let mut out_ss;
unsafe {
if fontforge::StrokeSetConvex(nibss, 0) == 0 {
panic!("nib not convex");
}
let shape = fontforge::NibIsValid(nibss);
println!("Shape: {}", shape);
let si = fontforge::InitializeStrokeInfo(0 as *mut _);
println!("Stroking...");
let newss = fontforge::SplineSetStroke(ss, si, 0);
println!("{:?}", *newss);
out_ss = *newss;
}
let out = ffsplineset_to_outline(out_ss);
println!("O: {:?}", out);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment