Don't require users of the library to load OTF tables individually
This commit is contained in:
parent
30daf10cdd
commit
1deaf9136e
|
@ -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 {
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -15,31 +15,27 @@ 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 {
|
||||
try!(reader.jump(glyph_id as usize * 2));
|
||||
Ok(try!(reader.read_u16::<BigEndian>().map_err(drop)) as u32 * 2)
|
||||
} else {
|
||||
try!(reader.jump(glyph_id as usize * 4));
|
||||
reader.read_u32::<BigEndian>().map_err(drop)
|
||||
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)
|
||||
}
|
||||
1 => {
|
||||
try!(reader.jump(glyph_id as usize * 4));
|
||||
reader.read_u32::<BigEndian>().map_err(drop)
|
||||
}
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue