Skip to content

Commit

Permalink
copy and modify stb-truetype to fit our needs
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastian Köln committed Jul 29, 2019
1 parent b2c4fbf commit 5f981df
Show file tree
Hide file tree
Showing 5 changed files with 443 additions and 76 deletions.
2 changes: 0 additions & 2 deletions font/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@ edition = "2018"
path = "../encoding"

[dependencies]
sfnt = "0.12"
pathfinder_canvas = {git = "https://github.com/s3bk/pathfinder/" }
pathfinder_export = { git = "https://github.com/s3bk/pathfinder/" }
pathfinder_geometry = { git = "https://github.com/s3bk/pathfinder/" }
stb_truetype = { git = "https://github.com/s3bk/stb_truetype" }
nom = "5.0"
log = "*"
env_logger = "*"
Expand Down
4 changes: 2 additions & 2 deletions font/src/cff.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::error::Error;
use std::collections::HashMap;
use pathfinder_geometry::transform2d::Transform2F;
use crate::{Font, BorrowedFont, Glyph, Glyphs, Value, Context, State, type1, type2, IResultExt, R};
use crate::{Font, BorrowedFont, Glyph, Value, Context, State, type1, type2, IResultExt, R};
use nom::{
number::complete::{be_u8, be_i8, be_u16, be_i16, be_u24, be_u32, be_i32},
number::complete::{be_u8, be_u16, be_i16, be_u24, be_u32, be_i32},
bytes::complete::{take},
multi::{count, many0},
combinator::map,
Expand Down
7 changes: 3 additions & 4 deletions font/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ use pathfinder_geometry::vector::Vector2F;
use pathfinder_geometry::transform2d::Transform2F;
use std::fmt;
use std::borrow::Cow;
use std::path::Path;
use std::convert::TryInto;
use nom::{IResult, Err::*, error::VerboseError};
use tuple::{TupleElements, Map};
use tuple::{TupleElements};
use encoding::Encoding;

#[derive(Clone)]
Expand Down Expand Up @@ -267,8 +266,8 @@ pub fn parse<'a>(data: &'a [u8]) -> Box<dyn BorrowedFont<'a> + 'a> {
info!("font magic: {:?}", magic);
match magic {
&[0x80, 1, _, _] => Box::new(Type1Font::parse_pfb(data)) as _,
b"OTTO" | [0,1,0,0] | [1,0,0,0] => parse_opentype(data, 0),
b"ttcf" | b"typ1" => Box::new(TrueTypeFont::parse(data, 0)) as _,
b"OTTO" | [0,1,0,0] => parse_opentype(data, 0),
b"ttcf" | b"typ1" => unimplemented!(), // Box::new(TrueTypeFont::parse(data, 0)) as _,
b"%!PS" => Box::new(Type1Font::parse_postscript(data)) as _,
&[1, _, _, _] => Box::new(CffFont::parse(data, 0)) as _,
magic => panic!("unknown magic {:?}", magic)
Expand Down
124 changes: 100 additions & 24 deletions font/src/opentype.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,114 @@
use crate::{CffFont, TrueTypeFont, BorrowedFont};
use std::error::Error;
use std::convert::TryInto;
use crate::{CffFont, TrueTypeFont, BorrowedFont, R, IResultExt};
use nom::{
number::complete::{be_i16, be_u16, be_i64, be_i32, be_u32},
multi::count,
combinator::map,
bytes::complete::take,
sequence::tuple
};

pub fn parse_opentype<'a>(data: &'a [u8], idx: u32) -> Box<dyn BorrowedFont<'a> + 'a> {
for (header, block) in tables(data) {
debug!("header: {:?} ({:?})", header, std::str::from_utf8(&header));
match &header {
let tables = parse_tables(data).get();
for &(tag, _) in &tables.entries {
debug!("tag: {:?} ({:?})", tag, std::str::from_utf8(&tag));
}
let table = |tag: &[u8; 4]| tables.get(tag);

for &(tag, block) in &tables.entries {
match &tag {
b"CFF " => return Box::new(CffFont::parse(block, idx)) as _,
b"glyf" => return Box::new(TrueTypeFont::parse(data, idx)) as _,
b"glyf" => {
return Box::new(TrueTypeFont::parse_glyf(block, tables)) as _
}
_ => {}
}
}
panic!("neither CFF nor glyf table found")
}

fn find_table<'a>(data: &'a [u8], tag: &[u8; 4]) -> Option<&'a [u8]> {
let num_tables = u16::from_be_bytes(data[4 .. 6].try_into().unwrap()) as usize;
for i in 0 .. num_tables {
let loc = 12 + 16 * i;
let entry = &data[loc .. loc + 4];
if entry == tag {
let offset = u32::from_be_bytes(data[loc + 8 .. loc + 12].try_into().unwrap()) as usize;
return Some(data.get(offset ..).unwrap());
}
pub struct Tables<'a> {
// (tag, data)
entries: Vec<([u8; 4], &'a [u8])>
}
impl<'a> Tables<'a> {
pub fn get(&self, tag: &[u8; 4]) -> Option<&'a [u8]> {
self.entries.iter().find(|&(t, block)| tag == t).map(|&(tag, block)| block)
}
None
}
// (tag, content)
pub fn parse_tables(data: &[u8]) -> R<Tables> {
let (i, _magic) = take(4usize)(data)?;
let (i, num_tables) = be_u16(i)?;
let (i, _search_range) = be_u16(i)?;
let (i, _entry_selector) = be_u16(i)?;
let (i, _range_shift) = be_u16(i)?;
let (i, entries) = count(
map(
tuple((take(4usize), be_u32, be_u32, be_u32)),
|(tag, _, off, len)| (
tag.try_into().expect("slice too short"),
data.get(off as usize .. off as usize + len as usize).expect("out of bounds")
)
),
num_tables as usize
)(i)?;

Ok((i, Tables { entries }))
}

pub struct Head {
pub units_per_em: u16,
pub index_to_loc_format: i16
}
pub fn parse_head(i: &[u8]) -> R<Head> {
let (i, major) = be_u16(i)?;
assert_eq!(major, 1);
let (i, minor) = be_u16(i)?;
assert_eq!(minor, 0);

let (i, _revision) = be_i32(i)?;
let (i, _cksum) = be_u32(i)?;
let (i, magic) = be_i32(i)?;
assert_eq!(magic, 0x5F0F3CF5);

let (i, _flags) = be_u16(i)?;
let (i, units_per_em) = be_u16(i)?;

// (header, content)
fn tables(data: &[u8]) -> impl Iterator<Item=([u8; 4], &[u8])> {
let num_tables = u16::from_be_bytes(data[4 .. 6].try_into().unwrap()) as usize;
data[12 ..].chunks_exact(16).map(move |chunk| {
let entry: [u8; 4] = chunk[.. 4].try_into().unwrap();
let offset = u32::from_be_bytes(chunk[8 .. 12].try_into().unwrap()) as usize;
(entry, data.get(offset ..).unwrap())
})
let (i, _created) = be_i64(i)?;
let (i, _modified) = be_i64(i)?;

let (i, _x_min) = be_i16(i)?;
let (i, _y_min) = be_i16(i)?;
let (i, _x_max) = be_i16(i)?;
let (i, _y_max) = be_i16(i)?;

let (i, _mac_style) = be_u16(i)?;

let (i, _lowest_rec_ppem) = be_u16(i)?;

let (i, _font_direction_hint) = be_u16(i)?;
let (i, index_to_loc_format) = be_i16(i)?;
let (i, glyph_data_format) = be_u16(i)?;
assert_eq!(glyph_data_format, 0);

Ok((i, Head {
units_per_em,
index_to_loc_format
}))
}
pub struct Maxp {
pub num_glyphs: u16
}
pub fn parse_maxp(i: &[u8]) -> R<Maxp> {
let (i, _version) = be_i32(i)?;
let (i, num_glyphs) = be_u16(i)?;
Ok((i, Maxp { num_glyphs }))
}
pub fn parse_loca<'a>(i: &'a [u8], head: &Head, maxp: &Maxp) -> R<'a, Vec<u32>> {
match head.index_to_loc_format {
0 => count(map(be_u16, |n| 2 * n as u32), maxp.num_glyphs as usize + 1)(i),
1 => count(be_u32, maxp.num_glyphs as usize + 1)(i),
_ => panic!("invalid index_to_loc_format")
}
}
Loading

0 comments on commit 5f981df

Please sign in to comment.