Don't require users of the library to load OTF tables individually

This commit is contained in:
Patrick Walton 2017-01-26 10:27:38 -08:00
parent 30daf10cdd
commit 1deaf9136e
6 changed files with 90 additions and 98 deletions

View File

@ -9,20 +9,16 @@ use euclid::Point2D;
use memmap::{Mmap, Protection};
use pathfinder::batch::GlyphRange;
use pathfinder::charmap::CodepointRange;
use pathfinder::otf::FontData;
use pathfinder::otf::Font;
use std::char;
use std::env;
fn main() {
let file = Mmap::open_path(env::args().nth(1).unwrap(), Protection::Read).unwrap();
unsafe {
let font = FontData::new(file.as_slice());
let cmap = font.cmap_table().unwrap();
let glyf = font.glyf_table().unwrap();
let head = font.head_table().unwrap();
let loca = font.loca_table(&head).unwrap();
let font = Font::new(file.as_slice()).unwrap();
let codepoint_ranges = [CodepointRange::new('!' as u32, '~' as u32)];
let glyph_ranges = cmap.glyph_ranges_for_codepoint_ranges(&codepoint_ranges).unwrap();
let glyph_ranges = font.cmap.glyph_ranges_for_codepoint_ranges(&codepoint_ranges).unwrap();
for (codepoint, glyph_id) in
codepoint_ranges.iter()
.flat_map(CodepointRange::iter)
@ -34,7 +30,10 @@ fn main() {
let mut last_point: Option<Point2D<i16>> = None;
let mut last_point_was_off_curve = false;
glyf.for_each_point(&loca, glyph_id as u32, |point| {
font.glyf.as_ref().unwrap().for_each_point(&font.head,
font.loca.as_ref().unwrap(),
glyph_id as u32,
|point| {
if point.first_point_in_contour {
println!("M {},{}", point.position.x, point.position.y);
} else {

View File

@ -20,7 +20,7 @@ use pathfinder::batch::{BatchBuilder, GlyphRange};
use pathfinder::charmap::CodepointRange;
use pathfinder::coverage::CoverageBuffer;
use pathfinder::glyph_buffer::GlyphBufferBuilder;
use pathfinder::otf::FontData;
use pathfinder::otf::Font;
use pathfinder::rasterizer::{Rasterizer, RasterizerOptions};
use std::env;
use std::os::raw::c_void;
@ -54,16 +54,12 @@ fn main() {
let file = Mmap::open_path(env::args().nth(1).unwrap(), Protection::Read).unwrap();
unsafe {
let font = FontData::new(file.as_slice());
let cmap = font.cmap_table().unwrap();
let glyf = font.glyf_table().unwrap();
let head = font.head_table().unwrap();
let loca = font.loca_table(&head).unwrap();
let font = Font::new(file.as_slice()).unwrap();
let codepoint_ranges = [CodepointRange::new('!' as u32, '~' as u32)];
let glyph_ranges = cmap.glyph_ranges_for_codepoint_ranges(&codepoint_ranges).unwrap();
let glyph_ranges = font.cmap.glyph_ranges_for_codepoint_ranges(&codepoint_ranges).unwrap();
for (glyph_index, glyph_id) in glyph_ranges.iter().flat_map(GlyphRange::iter).enumerate() {
glyph_buffer_builder.add_glyph(glyph_id as u32, &head, &loca, &glyf).unwrap();
glyph_buffer_builder.add_glyph(&font, glyph_id as u32).unwrap();
batch_builder.add_glyph(&glyph_buffer_builder, glyph_index as u32, POINT_SIZE).unwrap()
}
}

View File

@ -11,9 +11,7 @@
use euclid::{Point2D, Rect, Size2D};
use gl::types::{GLsizeiptr, GLuint};
use gl;
use otf::glyf::GlyfTable;
use otf::head::HeadTable;
use otf::loca::LocaTable;
use otf::Font;
use std::mem;
use std::os::raw::c_void;
@ -39,12 +37,7 @@ impl GlyphBufferBuilder {
}
}
pub fn add_glyph(&mut self,
glyph_id: u32,
head_table: &HeadTable,
loca_table: &LocaTable,
glyf_table: &GlyfTable)
-> Result<(), ()> {
pub fn add_glyph(&mut self, font: &Font, glyph_id: u32) -> Result<(), ()> {
let glyph_index = self.descriptors.len() as u16;
let mut point_index = self.vertices.len() as u32;
@ -52,7 +45,10 @@ impl GlyphBufferBuilder {
let start_point = point_index;
let mut last_point_on_curve = true;
try!(glyf_table.for_each_point(loca_table, glyph_id, |point| {
let glyf_table = try!(font.glyf.ok_or(()));
let loca_table = try!(font.loca.as_ref().ok_or(()));
try!(glyf_table.for_each_point(&font.head, loca_table, glyph_id, |point| {
self.vertices.push(Vertex {
x: point.position.x,
y: point.position.y,
@ -73,13 +69,13 @@ impl GlyphBufferBuilder {
}));
// Add a glyph descriptor.
let bounding_rect = try!(glyf_table.bounding_rect(loca_table, glyph_id));
let bounding_rect = try!(glyf_table.bounding_rect(&font.head, loca_table, glyph_id));
self.descriptors.push(GlyphDescriptor {
left: bounding_rect.origin.x as i32,
bottom: bounding_rect.origin.y as i32,
right: bounding_rect.max_x() as i32,
top: bounding_rect.max_y() as i32,
units_per_em: head_table.units_per_em as u32,
units_per_em: font.head.units_per_em as u32,
start_point: start_point as u32,
start_index: start_index,
pad: 0,

View File

@ -11,6 +11,7 @@
use byteorder::{BigEndian, ReadBytesExt};
use euclid::{Point2D, Rect, Size2D};
use otf::FontTable;
use otf::head::HeadTable;
use otf::loca::LocaTable;
use std::mem;
use util::Jump;
@ -47,10 +48,14 @@ impl<'a> GlyfTable<'a> {
}
}
pub fn for_each_point<F>(&self, loca_table: &LocaTable, glyph_id: u32, mut callback: F)
pub fn for_each_point<F>(&self,
head_table: &HeadTable,
loca_table: &LocaTable,
glyph_id: u32,
mut callback: F)
-> Result<(), ()> where F: FnMut(&Point) {
let mut reader = self.table.bytes;
let offset = try!(loca_table.location_of(glyph_id));
let offset = try!(loca_table.location_of(head_table, glyph_id));
try!(reader.jump(offset as usize));
let number_of_contours = try!(reader.read_i16::<BigEndian>().map_err(drop));
@ -144,9 +149,10 @@ impl<'a> GlyfTable<'a> {
Ok(())
}
pub fn bounding_rect(&self, loca_table: &LocaTable, glyph_id: u32) -> Result<Rect<i16>, ()> {
pub fn bounding_rect(&self, head_table: &HeadTable, loca_table: &LocaTable, glyph_id: u32)
-> Result<Rect<i16>, ()> {
let mut reader = self.table.bytes;
let offset = try!(loca_table.location_of(glyph_id));
let offset = try!(loca_table.location_of(head_table, glyph_id));
try!(reader.jump(offset as usize));
let number_of_contours = try!(reader.read_i16::<BigEndian>().map_err(drop));

View File

@ -15,32 +15,28 @@ use util::Jump;
pub struct LocaTable<'a> {
table: FontTable<'a>,
pub long: bool,
}
impl<'a> LocaTable<'a> {
pub fn new(loca_table: FontTable<'a>, head_table: &HeadTable) -> Result<LocaTable<'a>, ()> {
let long = match head_table.index_to_loc_format {
0 => false,
1 => true,
_ => return Err(()),
};
pub fn new(loca_table: FontTable<'a>) -> Result<LocaTable<'a>, ()> {
Ok(LocaTable {
table: loca_table,
long: long,
})
}
pub fn location_of(&self, glyph_id: u32) -> Result<u32, ()> {
pub fn location_of(&self, head_table: &HeadTable, glyph_id: u32) -> Result<u32, ()> {
let mut reader = self.table.bytes;
if !self.long {
match head_table.index_to_loc_format {
0 => {
try!(reader.jump(glyph_id as usize * 2));
Ok(try!(reader.read_u16::<BigEndian>().map_err(drop)) as u32 * 2)
} else {
}
1 => {
try!(reader.jump(glyph_id as usize * 4));
reader.read_u32::<BigEndian>().map_err(drop)
}
_ => Err(()),
}
}
}

View File

@ -34,14 +34,24 @@ const HEAD: u32 = ((b'h' as u32) << 24) |
((b'e' as u32) << 16) |
((b'a' as u32) << 8) |
(b'd' as u32);
const HMTX: u32 = ((b'h' as u32) << 24) |
((b'm' as u32) << 16) |
((b't' as u32) << 8) |
(b'x' as u32);
const LOCA: u32 = ((b'l' as u32) << 24) |
((b'o' as u32) << 16) |
((b'c' as u32) << 8) |
(b'a' as u32);
#[derive(Clone, Copy, Debug)]
pub struct FontData<'a> {
pub struct Font<'a> {
pub bytes: &'a [u8],
pub cmap: CmapTable<'a>,
pub head: HeadTable,
pub hmtx: FontTable<'a>,
pub glyf: Option<GlyfTable<'a>>,
pub loca: Option<LocaTable<'a>>,
}
#[derive(Clone, Copy, Debug)]
@ -49,16 +59,11 @@ pub struct FontTable<'a> {
pub bytes: &'a [u8],
}
impl<'a> FontData<'a> {
impl<'a> Font<'a> {
#[inline]
pub fn new<'b>(bytes: &'b [u8]) -> FontData<'b> {
FontData {
bytes: bytes,
}
}
fn table(&self, table_id: u32) -> Result<Option<FontTable>, ()> {
let mut reader = self.bytes;
pub fn new<'b>(bytes: &'b [u8]) -> Result<Font<'b>, ()> {
// Read the tables we care about.
let mut reader = bytes;
let sfnt_version = try!(reader.read_u32::<BigEndian>().map_err(drop));
if sfnt_version != 0x10000 {
return Err(())
@ -67,58 +72,52 @@ impl<'a> FontData<'a> {
let num_tables = try!(reader.read_u16::<BigEndian>().map_err(drop));
try!(reader.jump(mem::size_of::<u16>() * 3));
let (mut low, mut high) = (0, num_tables);
while low < high {
let mut reader = reader;
let mid = (low + high) / 2;
try!(reader.jump(mid as usize * mem::size_of::<u32>() * 4));
let (mut cmap_table, mut head_table, mut hmtx_table) = (None, None, None);
let (mut glyf_table, mut loca_table) = (None, None);
let current_table_id = try!(reader.read_u32::<BigEndian>().map_err(drop));
if table_id < current_table_id {
high = mid;
continue
}
if table_id > current_table_id {
low = mid + 1;
continue
}
for _ in 0..num_tables {
let table_id = try!(reader.read_u32::<BigEndian>().map_err(drop));
// Skip the checksum, and slurp the offset and length.
// Skip over the checksum.
try!(reader.read_u32::<BigEndian>().map_err(drop));
let offset = try!(reader.read_u32::<BigEndian>().map_err(drop)) as usize;
let length = try!(reader.read_u32::<BigEndian>().map_err(drop)) as usize;
let end = offset + length;
if end > self.bytes.len() {
let mut slot = match table_id {
CMAP => &mut cmap_table,
HEAD => &mut head_table,
HMTX => &mut hmtx_table,
GLYF => &mut glyf_table,
LOCA => &mut loca_table,
_ => continue,
};
// Make sure there isn't more than one copy of the table.
if slot.is_some() {
return Err(())
}
return Ok(Some(FontTable {
bytes: &self.bytes[offset..end],
}))
*slot = Some(FontTable {
bytes: &bytes[offset..offset + length],
})
}
Ok(None)
}
let loca_table = match loca_table {
None => None,
Some(loca_table) => Some(try!(LocaTable::new(loca_table))),
};
#[inline]
pub fn cmap_table(&self) -> Result<CmapTable, ()> {
self.table(CMAP).and_then(|table| table.ok_or(()).map(CmapTable::new))
}
Ok(Font {
bytes: bytes,
#[inline]
pub fn glyf_table(&self) -> Result<GlyfTable, ()> {
self.table(GLYF).and_then(|table| table.ok_or(()).map(GlyfTable::new))
}
cmap: CmapTable::new(try!(cmap_table.ok_or(()))),
head: try!(HeadTable::new(try!(head_table.ok_or(())))),
hmtx: try!(hmtx_table.ok_or(())),
#[inline]
pub fn head_table(&self) -> Result<HeadTable, ()> {
self.table(HEAD).and_then(|table| table.ok_or(()).and_then(HeadTable::new))
}
#[inline]
pub fn loca_table(&self, head_table: &HeadTable) -> Result<LocaTable, ()> {
let loca_table = try!(self.table(LOCA).and_then(|table| table.ok_or(())));
LocaTable::new(loca_table, head_table)
glyf: glyf_table.map(GlyfTable::new),
loca: loca_table,
})
}
}