Add error handling to the OTF format
This commit is contained in:
parent
23fa035178
commit
316123123a
|
@ -11,7 +11,7 @@
|
||||||
use byteorder::{BigEndian, ReadBytesExt};
|
use byteorder::{BigEndian, ReadBytesExt};
|
||||||
use charmap::CodepointRange;
|
use charmap::CodepointRange;
|
||||||
use glyph_range::{GlyphRange, GlyphRanges, MappedGlyphRange};
|
use glyph_range::{GlyphRange, GlyphRanges, MappedGlyphRange};
|
||||||
use otf::FontTable;
|
use otf::{Error, FontTable};
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::u16;
|
use std::u16;
|
||||||
|
@ -40,30 +40,30 @@ impl<'a> CmapTable<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn glyph_ranges_for_codepoint_ranges(&self, codepoint_ranges: &[CodepointRange])
|
pub fn glyph_ranges_for_codepoint_ranges(&self, codepoint_ranges: &[CodepointRange])
|
||||||
-> Result<GlyphRanges, ()> {
|
-> Result<GlyphRanges, Error> {
|
||||||
let mut cmap_reader = self.table.bytes;
|
let mut cmap_reader = self.table.bytes;
|
||||||
|
|
||||||
// Check version.
|
// Check version.
|
||||||
if try!(cmap_reader.read_u16::<BigEndian>().map_err(drop)) != 0 {
|
if try!(cmap_reader.read_u16::<BigEndian>().map_err(Error::eof)) != 0 {
|
||||||
return Err(())
|
return Err(Error::UnsupportedCmapVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
let num_tables = try!(cmap_reader.read_u16::<BigEndian>().map_err(drop));
|
let num_tables = try!(cmap_reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
|
|
||||||
// Check platform ID and encoding.
|
// Check platform ID and encoding.
|
||||||
// TODO(pcwalton): Handle more.
|
// TODO(pcwalton): Handle more.
|
||||||
let mut table_found = false;
|
let mut table_found = false;
|
||||||
for _ in 0..num_tables {
|
for _ in 0..num_tables {
|
||||||
let platform_id = try!(cmap_reader.read_u16::<BigEndian>().map_err(drop));
|
let platform_id = try!(cmap_reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
let encoding_id = try!(cmap_reader.read_u16::<BigEndian>().map_err(drop));
|
let encoding_id = try!(cmap_reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
let offset = try!(cmap_reader.read_u32::<BigEndian>().map_err(drop));
|
let offset = try!(cmap_reader.read_u32::<BigEndian>().map_err(Error::eof));
|
||||||
match (platform_id, encoding_id) {
|
match (platform_id, encoding_id) {
|
||||||
(PLATFORM_ID_UNICODE, _) |
|
(PLATFORM_ID_UNICODE, _) |
|
||||||
(PLATFORM_ID_MICROSOFT, MICROSOFT_ENCODING_ID_UNICODE_BMP) |
|
(PLATFORM_ID_MICROSOFT, MICROSOFT_ENCODING_ID_UNICODE_BMP) |
|
||||||
(PLATFORM_ID_MICROSOFT, MICROSOFT_ENCODING_ID_UNICODE_UCS4) => {
|
(PLATFORM_ID_MICROSOFT, MICROSOFT_ENCODING_ID_UNICODE_UCS4) => {
|
||||||
// Move to the mapping table.
|
// Move to the mapping table.
|
||||||
cmap_reader = self.table.bytes;
|
cmap_reader = self.table.bytes;
|
||||||
try!(cmap_reader.jump(offset as usize));
|
try!(cmap_reader.jump(offset as usize).map_err(Error::eof));
|
||||||
table_found = true;
|
table_found = true;
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -72,22 +72,22 @@ impl<'a> CmapTable<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !table_found {
|
if !table_found {
|
||||||
return Err(())
|
return Err(Error::UnsupportedCmapEncoding)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the mapping table format.
|
// Check the mapping table format.
|
||||||
let format = try!(cmap_reader.read_u16::<BigEndian>().map_err(drop));
|
let format = try!(cmap_reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
if format != FORMAT_SEGMENT_MAPPING_TO_DELTA_VALUES {
|
if format != FORMAT_SEGMENT_MAPPING_TO_DELTA_VALUES {
|
||||||
return Err(())
|
return Err(Error::UnsupportedCmapFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the mapping table header.
|
// Read the mapping table header.
|
||||||
let _length = try!(cmap_reader.read_u16::<BigEndian>().map_err(drop));
|
let _length = try!(cmap_reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
let _language = try!(cmap_reader.read_u16::<BigEndian>().map_err(drop));
|
let _language = try!(cmap_reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
let seg_count = try!(cmap_reader.read_u16::<BigEndian>().map_err(drop)) / 2;
|
let seg_count = try!(cmap_reader.read_u16::<BigEndian>().map_err(Error::eof)) / 2;
|
||||||
let _search_range = try!(cmap_reader.read_u16::<BigEndian>().map_err(drop));
|
let _search_range = try!(cmap_reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
let _entry_selector = try!(cmap_reader.read_u16::<BigEndian>().map_err(drop));
|
let _entry_selector = try!(cmap_reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
let _range_shift = try!(cmap_reader.read_u16::<BigEndian>().map_err(drop));
|
let _range_shift = try!(cmap_reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
|
|
||||||
// Set up parallel array pointers.
|
// Set up parallel array pointers.
|
||||||
//
|
//
|
||||||
|
@ -95,13 +95,15 @@ impl<'a> CmapTable<'a> {
|
||||||
// respectively in a few places. I believe this is a mistake, and `startCode` and `endCode`
|
// respectively in a few places. I believe this is a mistake, and `startCode` and `endCode`
|
||||||
// are the correct names.
|
// are the correct names.
|
||||||
let (end_codes, mut start_codes) = (cmap_reader, cmap_reader);
|
let (end_codes, mut start_codes) = (cmap_reader, cmap_reader);
|
||||||
try!(start_codes.jump((seg_count as usize + 1) * mem::size_of::<u16>()));
|
try!(start_codes.jump((seg_count as usize + 1) * mem::size_of::<u16>())
|
||||||
|
.map_err(Error::eof));
|
||||||
let mut id_deltas = start_codes;
|
let mut id_deltas = start_codes;
|
||||||
try!(id_deltas.jump(seg_count as usize * mem::size_of::<u16>()));
|
try!(id_deltas.jump(seg_count as usize * mem::size_of::<u16>()).map_err(Error::eof));
|
||||||
let mut id_range_offsets = id_deltas;
|
let mut id_range_offsets = id_deltas;
|
||||||
try!(id_range_offsets.jump(seg_count as usize * mem::size_of::<u16>()));
|
try!(id_range_offsets.jump(seg_count as usize * mem::size_of::<u16>())
|
||||||
|
.map_err(Error::eof));
|
||||||
let mut glyph_ids = id_range_offsets;
|
let mut glyph_ids = id_range_offsets;
|
||||||
try!(glyph_ids.jump(seg_count as usize * mem::size_of::<u16>()));
|
try!(glyph_ids.jump(seg_count as usize * mem::size_of::<u16>()).map_err(Error::eof));
|
||||||
|
|
||||||
// Now perform the lookups.
|
// Now perform the lookups.
|
||||||
let mut glyph_ranges = GlyphRanges::new();
|
let mut glyph_ranges = GlyphRanges::new();
|
||||||
|
@ -130,16 +132,16 @@ impl<'a> CmapTable<'a> {
|
||||||
let mid = (low + high) / 2;
|
let mid = (low + high) / 2;
|
||||||
|
|
||||||
let mut end_code = end_codes;
|
let mut end_code = end_codes;
|
||||||
try!(end_code.jump(mid as usize * 2));
|
try!(end_code.jump(mid as usize * 2).map_err(Error::eof));
|
||||||
let end_code = try!(end_code.read_u16::<BigEndian>().map_err(drop));
|
let end_code = try!(end_code.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
if start_codepoint_range > end_code {
|
if start_codepoint_range > end_code {
|
||||||
low = mid + 1;
|
low = mid + 1;
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut start_code = start_codes;
|
let mut start_code = start_codes;
|
||||||
try!(start_code.jump(mid as usize * 2));
|
try!(start_code.jump(mid as usize * 2).map_err(Error::eof));
|
||||||
let start_code = try!(start_code.read_u16::<BigEndian>().map_err(drop));
|
let start_code = try!(start_code.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
if start_codepoint_range < start_code {
|
if start_codepoint_range < start_code {
|
||||||
high = mid;
|
high = mid;
|
||||||
continue
|
continue
|
||||||
|
@ -169,14 +171,15 @@ impl<'a> CmapTable<'a> {
|
||||||
let mut end_code = end_codes;
|
let mut end_code = end_codes;
|
||||||
let mut id_range_offset = id_range_offsets;
|
let mut id_range_offset = id_range_offsets;
|
||||||
let mut id_delta = id_deltas;
|
let mut id_delta = id_deltas;
|
||||||
try!(start_code.jump(segment_index as usize * 2));
|
try!(start_code.jump(segment_index as usize * 2).map_err(Error::eof));
|
||||||
try!(end_code.jump(segment_index as usize * 2));
|
try!(end_code.jump(segment_index as usize * 2).map_err(Error::eof));
|
||||||
try!(id_range_offset.jump(segment_index as usize * 2));
|
try!(id_range_offset.jump(segment_index as usize * 2).map_err(Error::eof));
|
||||||
try!(id_delta.jump(segment_index as usize * 2));
|
try!(id_delta.jump(segment_index as usize * 2).map_err(Error::eof));
|
||||||
let start_code = try!(start_code.read_u16::<BigEndian>().map_err(drop));
|
let start_code = try!(start_code.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
let end_code = try!(end_code.read_u16::<BigEndian>().map_err(drop));
|
let end_code = try!(end_code.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
let id_range_offset = try!(id_range_offset.read_u16::<BigEndian>().map_err(drop));
|
let id_range_offset = try!(id_range_offset.read_u16::<BigEndian>()
|
||||||
let id_delta = try!(id_delta.read_i16::<BigEndian>().map_err(drop));
|
.map_err(Error::eof));
|
||||||
|
let id_delta = try!(id_delta.read_i16::<BigEndian>().map_err(Error::eof));
|
||||||
|
|
||||||
end_codepoint_range = cmp::min(end_codepoint_range, end_code);
|
end_codepoint_range = cmp::min(end_codepoint_range, end_code);
|
||||||
codepoint_range.start = (end_codepoint_range + 1) as u32;
|
codepoint_range.start = (end_codepoint_range + 1) as u32;
|
||||||
|
@ -203,8 +206,9 @@ impl<'a> CmapTable<'a> {
|
||||||
// Otherwise, look up the glyphs individually.
|
// Otherwise, look up the glyphs individually.
|
||||||
for code_offset in start_code_offset..(end_code_offset + 1) {
|
for code_offset in start_code_offset..(end_code_offset + 1) {
|
||||||
let mut glyph_id = glyph_ids;
|
let mut glyph_id = glyph_ids;
|
||||||
try!(glyph_id.jump((id_range_offset as usize + code_offset as usize) * 2));
|
try!(glyph_id.jump((id_range_offset as usize + code_offset as usize) * 2)
|
||||||
let mut glyph_id = try!(glyph_id.read_u16::<BigEndian>().map_err(drop));
|
.map_err(Error::eof));
|
||||||
|
let mut glyph_id = try!(glyph_id.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
if glyph_id == 0 {
|
if glyph_id == 0 {
|
||||||
glyph_ranges.ranges.push(MappedGlyphRange {
|
glyph_ranges.ranges.push(MappedGlyphRange {
|
||||||
codepoint_start: start_code as u32 + code_offset as u32,
|
codepoint_start: start_code as u32 + code_offset as u32,
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
|
|
||||||
use byteorder::{BigEndian, ReadBytesExt};
|
use byteorder::{BigEndian, ReadBytesExt};
|
||||||
use euclid::Point2D;
|
use euclid::Point2D;
|
||||||
use otf::FontTable;
|
|
||||||
use otf::head::HeadTable;
|
use otf::head::HeadTable;
|
||||||
use otf::loca::LocaTable;
|
use otf::loca::LocaTable;
|
||||||
|
use otf::{Error, FontTable};
|
||||||
use outline::GlyphBounds;
|
use outline::GlyphBounds;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use util::Jump;
|
use util::Jump;
|
||||||
|
@ -54,7 +54,7 @@ impl<'a> GlyfTable<'a> {
|
||||||
loca_table: &LocaTable,
|
loca_table: &LocaTable,
|
||||||
glyph_id: u16,
|
glyph_id: u16,
|
||||||
mut callback: F)
|
mut callback: F)
|
||||||
-> Result<(), ()> where F: FnMut(&Point) {
|
-> Result<(), Error> where F: FnMut(&Point) {
|
||||||
let mut reader = self.table.bytes;
|
let mut reader = self.table.bytes;
|
||||||
|
|
||||||
match try!(loca_table.location_of(head_table, glyph_id)) {
|
match try!(loca_table.location_of(head_table, glyph_id)) {
|
||||||
|
@ -62,24 +62,25 @@ impl<'a> GlyfTable<'a> {
|
||||||
// No points.
|
// No points.
|
||||||
return Ok(())
|
return Ok(())
|
||||||
}
|
}
|
||||||
Some(offset) => try!(reader.jump(offset as usize)),
|
Some(offset) => try!(reader.jump(offset as usize).map_err(Error::eof)),
|
||||||
}
|
}
|
||||||
|
|
||||||
let number_of_contours = try!(reader.read_i16::<BigEndian>().map_err(drop));
|
let number_of_contours = try!(reader.read_i16::<BigEndian>().map_err(Error::eof));
|
||||||
if number_of_contours < 0 {
|
if number_of_contours < 0 {
|
||||||
// TODO(pcwalton): Composite glyphs.
|
// TODO(pcwalton): Composite glyphs.
|
||||||
return Err(())
|
return Err(Error::CompositeGlyph)
|
||||||
}
|
}
|
||||||
try!(reader.jump(mem::size_of::<i16>() * 4));
|
try!(reader.jump(mem::size_of::<i16>() * 4).map_err(Error::eof));
|
||||||
|
|
||||||
// Find out how many points we have.
|
// Find out how many points we have.
|
||||||
let mut endpoints_reader = reader;
|
let mut endpoints_reader = reader;
|
||||||
try!(reader.jump(mem::size_of::<u16>() as usize * (number_of_contours as usize - 1)));
|
try!(reader.jump(mem::size_of::<u16>() as usize * (number_of_contours as usize - 1))
|
||||||
let number_of_points = try!(reader.read_u16::<BigEndian>().map_err(drop)) + 1;
|
.map_err(Error::eof));
|
||||||
|
let number_of_points = try!(reader.read_u16::<BigEndian>().map_err(Error::eof)) + 1;
|
||||||
|
|
||||||
// Skip over hinting instructions.
|
// Skip over hinting instructions.
|
||||||
let instruction_length = try!(reader.read_u16::<BigEndian>().map_err(drop));
|
let instruction_length = try!(reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
try!(reader.jump(instruction_length as usize));
|
try!(reader.jump(instruction_length as usize).map_err(Error::eof));
|
||||||
|
|
||||||
// Find the offsets of the X and Y coordinates.
|
// Find the offsets of the X and Y coordinates.
|
||||||
let flags_reader = reader;
|
let flags_reader = reader;
|
||||||
|
@ -89,14 +90,14 @@ impl<'a> GlyfTable<'a> {
|
||||||
// Set up the streams.
|
// Set up the streams.
|
||||||
let mut flag_parser = try!(FlagParser::new(flags_reader));
|
let mut flag_parser = try!(FlagParser::new(flags_reader));
|
||||||
let mut x_coordinate_reader = reader;
|
let mut x_coordinate_reader = reader;
|
||||||
try!(reader.jump(x_coordinate_length as usize));
|
try!(reader.jump(x_coordinate_length as usize).map_err(Error::eof));
|
||||||
let mut y_coordinate_reader = reader;
|
let mut y_coordinate_reader = reader;
|
||||||
|
|
||||||
// Now parse the contours.
|
// Now parse the contours.
|
||||||
let (mut position, mut point_index) = (Point2D::new(0, 0), 0);
|
let (mut position, mut point_index) = (Point2D::new(0, 0), 0);
|
||||||
for _ in 0..number_of_contours {
|
for _ in 0..number_of_contours {
|
||||||
let contour_point_count =
|
let contour_point_count = try!(endpoints_reader.read_u16::<BigEndian>()
|
||||||
try!(endpoints_reader.read_u16::<BigEndian>().map_err(drop)) - point_index + 1;
|
.map_err(Error::eof)) - point_index + 1;
|
||||||
|
|
||||||
let mut first_on_curve_point = None;
|
let mut first_on_curve_point = None;
|
||||||
let mut initial_off_curve_point = None;
|
let mut initial_off_curve_point = None;
|
||||||
|
@ -109,20 +110,20 @@ impl<'a> GlyfTable<'a> {
|
||||||
|
|
||||||
let mut delta = Point2D::new(0, 0);
|
let mut delta = Point2D::new(0, 0);
|
||||||
if flags.contains(X_SHORT_VECTOR) {
|
if flags.contains(X_SHORT_VECTOR) {
|
||||||
delta.x = try!(x_coordinate_reader.read_u8().map_err(drop)) as i16;
|
delta.x = try!(x_coordinate_reader.read_u8().map_err(Error::eof)) as i16;
|
||||||
if !flags.contains(THIS_X_IS_SAME) {
|
if !flags.contains(THIS_X_IS_SAME) {
|
||||||
delta.x = -delta.x
|
delta.x = -delta.x
|
||||||
}
|
}
|
||||||
} else if !flags.contains(THIS_X_IS_SAME) {
|
} else if !flags.contains(THIS_X_IS_SAME) {
|
||||||
delta.x = try!(x_coordinate_reader.read_i16::<BigEndian>().map_err(drop))
|
delta.x = try!(x_coordinate_reader.read_i16::<BigEndian>().map_err(Error::eof))
|
||||||
}
|
}
|
||||||
if flags.contains(Y_SHORT_VECTOR) {
|
if flags.contains(Y_SHORT_VECTOR) {
|
||||||
delta.y = try!(y_coordinate_reader.read_u8().map_err(drop)) as i16;
|
delta.y = try!(y_coordinate_reader.read_u8().map_err(Error::eof)) as i16;
|
||||||
if !flags.contains(THIS_Y_IS_SAME) {
|
if !flags.contains(THIS_Y_IS_SAME) {
|
||||||
delta.y = -delta.y
|
delta.y = -delta.y
|
||||||
}
|
}
|
||||||
} else if !flags.contains(THIS_Y_IS_SAME) {
|
} else if !flags.contains(THIS_Y_IS_SAME) {
|
||||||
delta.y = try!(y_coordinate_reader.read_i16::<BigEndian>().map_err(drop))
|
delta.y = try!(y_coordinate_reader.read_i16::<BigEndian>().map_err(Error::eof))
|
||||||
}
|
}
|
||||||
|
|
||||||
if last_point_was_off_curve && !flags.contains(ON_CURVE) {
|
if last_point_was_off_curve && !flags.contains(ON_CURVE) {
|
||||||
|
@ -189,7 +190,7 @@ impl<'a> GlyfTable<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn glyph_bounds(&self, head_table: &HeadTable, loca_table: &LocaTable, glyph_id: u16)
|
pub fn glyph_bounds(&self, head_table: &HeadTable, loca_table: &LocaTable, glyph_id: u16)
|
||||||
-> Result<GlyphBounds, ()> {
|
-> Result<GlyphBounds, Error> {
|
||||||
let mut reader = self.table.bytes;
|
let mut reader = self.table.bytes;
|
||||||
|
|
||||||
match try!(loca_table.location_of(head_table, glyph_id)) {
|
match try!(loca_table.location_of(head_table, glyph_id)) {
|
||||||
|
@ -202,16 +203,16 @@ impl<'a> GlyfTable<'a> {
|
||||||
top: 0,
|
top: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Some(offset) => try!(reader.jump(offset as usize)),
|
Some(offset) => try!(reader.jump(offset as usize).map_err(Error::eof)),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip over the number of contours.
|
// Skip over the number of contours.
|
||||||
try!(reader.read_i16::<BigEndian>().map_err(drop));
|
try!(reader.read_i16::<BigEndian>().map_err(Error::eof));
|
||||||
|
|
||||||
let x_min = try!(reader.read_i16::<BigEndian>().map_err(drop));
|
let x_min = try!(reader.read_i16::<BigEndian>().map_err(Error::eof));
|
||||||
let y_min = try!(reader.read_i16::<BigEndian>().map_err(drop));
|
let y_min = try!(reader.read_i16::<BigEndian>().map_err(Error::eof));
|
||||||
let x_max = try!(reader.read_i16::<BigEndian>().map_err(drop));
|
let x_max = try!(reader.read_i16::<BigEndian>().map_err(Error::eof));
|
||||||
let y_max = try!(reader.read_i16::<BigEndian>().map_err(drop));
|
let y_max = try!(reader.read_i16::<BigEndian>().map_err(Error::eof));
|
||||||
Ok(GlyphBounds {
|
Ok(GlyphBounds {
|
||||||
left: x_min as i32,
|
left: x_min as i32,
|
||||||
bottom: y_min as i32,
|
bottom: y_min as i32,
|
||||||
|
@ -225,14 +226,14 @@ impl<'a> GlyfTable<'a> {
|
||||||
// of X coordinates and positions the reader at the start of that list.
|
// of X coordinates and positions the reader at the start of that list.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn calculate_size_of_x_coordinates<'a, 'b>(reader: &'a mut &'b [u8], number_of_points: u16)
|
fn calculate_size_of_x_coordinates<'a, 'b>(reader: &'a mut &'b [u8], number_of_points: u16)
|
||||||
-> Result<u16, ()> {
|
-> Result<u16, Error> {
|
||||||
let (mut x_coordinate_length, mut points_left) = (0, number_of_points);
|
let (mut x_coordinate_length, mut points_left) = (0, number_of_points);
|
||||||
while points_left > 0 {
|
while points_left > 0 {
|
||||||
let flags = Flags::from_bits_truncate(try!(reader.read_u8().map_err(drop)));
|
let flags = Flags::from_bits_truncate(try!(reader.read_u8().map_err(Error::eof)));
|
||||||
let repeat_count = if !flags.contains(REPEAT) {
|
let repeat_count = if !flags.contains(REPEAT) {
|
||||||
1
|
1
|
||||||
} else {
|
} else {
|
||||||
try!(reader.read_u8().map_err(drop)) as u16 + 1
|
try!(reader.read_u8().map_err(Error::eof)) as u16 + 1
|
||||||
};
|
};
|
||||||
|
|
||||||
if flags.contains(X_SHORT_VECTOR) {
|
if flags.contains(X_SHORT_VECTOR) {
|
||||||
|
@ -255,7 +256,7 @@ struct FlagParser<'a> {
|
||||||
|
|
||||||
impl<'a> FlagParser<'a> {
|
impl<'a> FlagParser<'a> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn new(buffer: &[u8]) -> Result<FlagParser, ()> {
|
fn new(buffer: &[u8]) -> Result<FlagParser, Error> {
|
||||||
let mut parser = FlagParser {
|
let mut parser = FlagParser {
|
||||||
next: buffer,
|
next: buffer,
|
||||||
current: &buffer[0],
|
current: &buffer[0],
|
||||||
|
@ -266,18 +267,26 @@ impl<'a> FlagParser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next(&mut self) -> Result<(), ()> {
|
fn next(&mut self) -> Result<(), Error> {
|
||||||
if self.repeats_left > 0 {
|
if self.repeats_left > 0 {
|
||||||
self.repeats_left -= 1;
|
self.repeats_left -= 1;
|
||||||
return Ok(())
|
return Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
self.current = try!(self.next.get(0).ok_or(()));
|
self.current = match self.next.get(0) {
|
||||||
|
Some(value) => value,
|
||||||
|
None => return Err(Error::UnexpectedEof),
|
||||||
|
};
|
||||||
|
|
||||||
let flags = Flags::from_bits_truncate(*self.current);
|
let flags = Flags::from_bits_truncate(*self.current);
|
||||||
self.next = &self.next[1..];
|
self.next = &self.next[1..];
|
||||||
|
|
||||||
if flags.contains(REPEAT) {
|
if flags.contains(REPEAT) {
|
||||||
self.repeats_left = *try!(self.next.get(0).ok_or(()));
|
self.repeats_left = match self.next.get(0) {
|
||||||
|
Some(&value) => value,
|
||||||
|
None => return Err(Error::UnexpectedEof),
|
||||||
|
};
|
||||||
|
|
||||||
self.next = &self.next[1..];
|
self.next = &self.next[1..];
|
||||||
} else {
|
} else {
|
||||||
self.repeats_left = 0
|
self.repeats_left = 0
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use byteorder::{BigEndian, ReadBytesExt};
|
use byteorder::{BigEndian, ReadBytesExt};
|
||||||
use otf::FontTable;
|
use otf::{Error, FontTable};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use util::Jump;
|
use util::Jump;
|
||||||
|
|
||||||
|
@ -22,38 +22,38 @@ pub struct HeadTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HeadTable {
|
impl HeadTable {
|
||||||
pub fn new(table: FontTable) -> Result<HeadTable, ()> {
|
pub fn new(table: FontTable) -> Result<HeadTable, Error> {
|
||||||
let mut reader = table.bytes;
|
let mut reader = table.bytes;
|
||||||
|
|
||||||
// Check the version.
|
// Check the version.
|
||||||
let major_version = try!(reader.read_u16::<BigEndian>().map_err(drop));
|
let major_version = try!(reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
let minor_version = try!(reader.read_u16::<BigEndian>().map_err(drop));
|
let minor_version = try!(reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
if (major_version, minor_version) != (1, 0) {
|
if (major_version, minor_version) != (1, 0) {
|
||||||
return Err(())
|
return Err(Error::UnsupportedHeadVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the magic number.
|
// Check the magic number.
|
||||||
try!(reader.jump(mem::size_of::<u32>() * 2));
|
try!(reader.jump(mem::size_of::<u32>() * 2).map_err(Error::eof));
|
||||||
let magic_number = try!(reader.read_u32::<BigEndian>().map_err(drop));
|
let magic_number = try!(reader.read_u32::<BigEndian>().map_err(Error::eof));
|
||||||
if magic_number != MAGIC_NUMBER {
|
if magic_number != MAGIC_NUMBER {
|
||||||
return Err(())
|
return Err(Error::UnknownFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the units per em.
|
// Read the units per em.
|
||||||
try!(reader.jump(mem::size_of::<u16>()));
|
try!(reader.jump(mem::size_of::<u16>()).map_err(Error::eof));
|
||||||
let units_per_em = try!(reader.read_u16::<BigEndian>().map_err(drop));
|
let units_per_em = try!(reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
|
|
||||||
// Read the index-to-location format.
|
// Read the index-to-location format.
|
||||||
try!(reader.jump(mem::size_of::<i64>() * 2 +
|
try!(reader.jump(mem::size_of::<i64>() * 2 +
|
||||||
mem::size_of::<i16>() * 4 +
|
mem::size_of::<i16>() * 4 +
|
||||||
mem::size_of::<u16>() * 2 +
|
mem::size_of::<u16>() * 2 +
|
||||||
mem::size_of::<i16>()));
|
mem::size_of::<i16>()).map_err(Error::eof));
|
||||||
let index_to_loc_format = try!(reader.read_i16::<BigEndian>().map_err(drop));
|
let index_to_loc_format = try!(reader.read_i16::<BigEndian>().map_err(Error::eof));
|
||||||
|
|
||||||
// Check the glyph data format.
|
// Check the glyph data format.
|
||||||
let glyph_data_format = try!(reader.read_i16::<BigEndian>().map_err(drop));
|
let glyph_data_format = try!(reader.read_i16::<BigEndian>().map_err(Error::eof));
|
||||||
if glyph_data_format != 0 {
|
if glyph_data_format != 0 {
|
||||||
return Err(())
|
return Err(Error::UnsupportedGlyphFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(HeadTable {
|
Ok(HeadTable {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use byteorder::{BigEndian, ReadBytesExt};
|
use byteorder::{BigEndian, ReadBytesExt};
|
||||||
use otf::FontTable;
|
use otf::{Error, FontTable};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use util::Jump;
|
use util::Jump;
|
||||||
|
|
||||||
|
@ -19,19 +19,19 @@ pub struct HheaTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HheaTable {
|
impl HheaTable {
|
||||||
pub fn new(table: FontTable) -> Result<HheaTable, ()> {
|
pub fn new(table: FontTable) -> Result<HheaTable, Error> {
|
||||||
let mut reader = table.bytes;
|
let mut reader = table.bytes;
|
||||||
|
|
||||||
// Check the version.
|
// Check the version.
|
||||||
let major_version = try!(reader.read_u16::<BigEndian>().map_err(drop));
|
let major_version = try!(reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
let minor_version = try!(reader.read_u16::<BigEndian>().map_err(drop));
|
let minor_version = try!(reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
if (major_version, minor_version) != (1, 0) {
|
if (major_version, minor_version) != (1, 0) {
|
||||||
return Err(())
|
return Err(Error::UnsupportedHheaVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the number of `hmtx` entries.
|
// Read the number of `hmtx` entries.
|
||||||
try!(reader.jump(mem::size_of::<u16>() * 15));
|
try!(reader.jump(mem::size_of::<u16>() * 15).map_err(Error::eof));
|
||||||
let number_of_h_metrics = try!(reader.read_u16::<BigEndian>().map_err(drop));
|
let number_of_h_metrics = try!(reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
|
|
||||||
Ok(HheaTable {
|
Ok(HheaTable {
|
||||||
number_of_h_metrics: number_of_h_metrics,
|
number_of_h_metrics: number_of_h_metrics,
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use byteorder::{BigEndian, ReadBytesExt};
|
use byteorder::{BigEndian, ReadBytesExt};
|
||||||
use otf::FontTable;
|
|
||||||
use otf::hhea::HheaTable;
|
use otf::hhea::HheaTable;
|
||||||
|
use otf::{Error, FontTable};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use util::Jump;
|
use util::Jump;
|
||||||
|
|
||||||
|
@ -27,23 +27,23 @@ impl<'a> HmtxTable<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn metrics_for_glyph(&self, hhea_table: &HheaTable, glyph_id: u16)
|
pub fn metrics_for_glyph(&self, hhea_table: &HheaTable, glyph_id: u16)
|
||||||
-> Result<HorizontalMetrics, ()> {
|
-> Result<HorizontalMetrics, Error> {
|
||||||
let mut reader = self.table.bytes;
|
let mut reader = self.table.bytes;
|
||||||
|
|
||||||
// Read the advance width.
|
// Read the advance width.
|
||||||
let advance_width;
|
let advance_width;
|
||||||
if glyph_id < hhea_table.number_of_h_metrics {
|
if glyph_id < hhea_table.number_of_h_metrics {
|
||||||
try!(reader.jump(mem::size_of::<u16>() * 2 * glyph_id as usize));
|
try!(reader.jump(mem::size_of::<u16>() * 2 * glyph_id as usize).map_err(Error::eof));
|
||||||
advance_width = try!(reader.read_u16::<BigEndian>().map_err(drop))
|
advance_width = try!(reader.read_u16::<BigEndian>().map_err(Error::eof))
|
||||||
} else {
|
} else {
|
||||||
try!(reader.jump(mem::size_of::<u16>() * 2 *
|
try!(reader.jump(mem::size_of::<u16>() * 2 *
|
||||||
(hhea_table.number_of_h_metrics - 1) as usize));
|
(hhea_table.number_of_h_metrics - 1) as usize).map_err(Error::eof));
|
||||||
advance_width = try!(reader.read_u16::<BigEndian>().map_err(drop));
|
advance_width = try!(reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
try!(reader.jump(mem::size_of::<i16>() * glyph_id as usize));
|
try!(reader.jump(mem::size_of::<i16>() * glyph_id as usize).map_err(Error::eof));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the left-side bearing.
|
// Read the left-side bearing.
|
||||||
let lsb = try!(reader.read_i16::<BigEndian>().map_err(drop));
|
let lsb = try!(reader.read_i16::<BigEndian>().map_err(Error::eof));
|
||||||
|
|
||||||
Ok(HorizontalMetrics {
|
Ok(HorizontalMetrics {
|
||||||
advance_width: advance_width,
|
advance_width: advance_width,
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use byteorder::{BigEndian, ReadBytesExt};
|
use byteorder::{BigEndian, ReadBytesExt};
|
||||||
use otf::FontTable;
|
|
||||||
use otf::head::HeadTable;
|
use otf::head::HeadTable;
|
||||||
|
use otf::{Error, FontTable};
|
||||||
use util::Jump;
|
use util::Jump;
|
||||||
|
|
||||||
pub struct LocaTable<'a> {
|
pub struct LocaTable<'a> {
|
||||||
|
@ -18,31 +18,33 @@ pub struct LocaTable<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LocaTable<'a> {
|
impl<'a> LocaTable<'a> {
|
||||||
pub fn new(loca_table: FontTable<'a>) -> Result<LocaTable<'a>, ()> {
|
pub fn new(loca_table: FontTable<'a>) -> Result<LocaTable<'a>, Error> {
|
||||||
Ok(LocaTable {
|
Ok(LocaTable {
|
||||||
table: loca_table,
|
table: loca_table,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn location_of(&self, head_table: &HeadTable, glyph_id: u16) -> Result<Option<u32>, ()> {
|
pub fn location_of(&self, head_table: &HeadTable, glyph_id: u16)
|
||||||
|
-> Result<Option<u32>, Error> {
|
||||||
let mut reader = self.table.bytes;
|
let mut reader = self.table.bytes;
|
||||||
let (this_location, next_location) = match head_table.index_to_loc_format {
|
let (this_location, next_location) = match head_table.index_to_loc_format {
|
||||||
0 => {
|
0 => {
|
||||||
try!(reader.jump(glyph_id as usize * 2));
|
try!(reader.jump(glyph_id as usize * 2).map_err(Error::eof));
|
||||||
let this_location = try!(reader.read_u16::<BigEndian>().map_err(drop)) as u32 * 2;
|
let this_location =
|
||||||
let next_location = match reader.read_u16::<BigEndian>().map_err(drop) {
|
try!(reader.read_u16::<BigEndian>().map_err(Error::eof)) as u32 * 2;
|
||||||
|
let next_location = match reader.read_u16::<BigEndian>() {
|
||||||
Ok(next_location) => Ok(next_location as u32 * 2),
|
Ok(next_location) => Ok(next_location as u32 * 2),
|
||||||
Err(_) => Err(()),
|
Err(_) => Err(Error::UnexpectedEof),
|
||||||
};
|
};
|
||||||
(this_location, next_location)
|
(this_location, next_location)
|
||||||
}
|
}
|
||||||
1 => {
|
1 => {
|
||||||
try!(reader.jump(glyph_id as usize * 4));
|
try!(reader.jump(glyph_id as usize * 4).map_err(Error::eof));
|
||||||
let this_location = try!(reader.read_u32::<BigEndian>().map_err(drop));
|
let this_location = try!(reader.read_u32::<BigEndian>().map_err(Error::eof));
|
||||||
let next_location = reader.read_u32::<BigEndian>().map_err(drop);
|
let next_location = reader.read_u32::<BigEndian>().map_err(Error::eof);
|
||||||
(this_location, next_location)
|
(this_location, next_location)
|
||||||
}
|
}
|
||||||
_ => return Err(()),
|
_ => return Err(Error::UnknownFormat),
|
||||||
};
|
};
|
||||||
|
|
||||||
if next_location == Ok(this_location) {
|
if next_location == Ok(this_location) {
|
||||||
|
|
156
src/otf/mod.rs
156
src/otf/mod.rs
|
@ -86,59 +86,59 @@ pub struct FontTable<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Font<'a> {
|
impl<'a> Font<'a> {
|
||||||
pub fn new<'b>(bytes: &'b [u8]) -> Result<Font<'b>, ()> {
|
pub fn new<'b>(bytes: &'b [u8]) -> Result<Font<'b>, Error> {
|
||||||
// Check magic number.
|
// Check magic number.
|
||||||
let mut reader = bytes;
|
let mut reader = bytes;
|
||||||
let mut magic_number = try!(reader.read_u32::<BigEndian>().map_err(drop));
|
let mut magic_number = try!(reader.read_u32::<BigEndian>().map_err(Error::eof));
|
||||||
match magic_number {
|
match magic_number {
|
||||||
TTCF => {
|
TTCF => {
|
||||||
// This is a font collection. Read the first font.
|
// This is a font collection. Read the first font.
|
||||||
//
|
//
|
||||||
// TODO(pcwalton): Provide a mechanism to read others.
|
// TODO(pcwalton): Provide a mechanism to read others.
|
||||||
let major_version = try!(reader.read_u16::<BigEndian>().map_err(drop));
|
let major_version = try!(reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
let minor_version = try!(reader.read_u16::<BigEndian>().map_err(drop));
|
let minor_version = try!(reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
if (major_version != 1 && major_version != 2) || minor_version != 0 {
|
if (major_version != 1 && major_version != 2) || minor_version != 0 {
|
||||||
return Err(())
|
return Err(Error::UnsupportedVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
let num_fonts = try!(reader.read_u32::<BigEndian>().map_err(drop));
|
let num_fonts = try!(reader.read_u32::<BigEndian>().map_err(Error::eof));
|
||||||
if num_fonts == 0 {
|
if num_fonts == 0 {
|
||||||
return Err(())
|
return Err(Error::Failed)
|
||||||
}
|
}
|
||||||
|
|
||||||
let table_offset = try!(reader.read_u32::<BigEndian>().map_err(drop));
|
let table_offset = try!(reader.read_u32::<BigEndian>().map_err(Error::eof));
|
||||||
Font::from_otf(&bytes[table_offset as usize..])
|
Font::from_otf(&bytes[table_offset as usize..])
|
||||||
}
|
}
|
||||||
magic_number if SFNT_VERSIONS.contains(&magic_number) => Font::from_otf(bytes),
|
magic_number if SFNT_VERSIONS.contains(&magic_number) => Font::from_otf(bytes),
|
||||||
0x0100 => Font::from_dfont(bytes),
|
0x0100 => Font::from_dfont(bytes),
|
||||||
_ => Err(()),
|
_ => Err(Error::UnknownFormat),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_otf<'b>(bytes: &'b [u8]) -> Result<Font<'b>, ()> {
|
pub fn from_otf<'b>(bytes: &'b [u8]) -> Result<Font<'b>, Error> {
|
||||||
let mut reader = bytes;
|
let mut reader = bytes;
|
||||||
let mut magic_number = try!(reader.read_u32::<BigEndian>().map_err(drop));
|
let mut magic_number = try!(reader.read_u32::<BigEndian>().map_err(Error::eof));
|
||||||
|
|
||||||
// Check version.
|
// Check version.
|
||||||
if !SFNT_VERSIONS.contains(&magic_number) {
|
if !SFNT_VERSIONS.contains(&magic_number) {
|
||||||
return Err(())
|
return Err(Error::UnknownFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
let num_tables = try!(reader.read_u16::<BigEndian>().map_err(drop));
|
let num_tables = try!(reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
try!(reader.jump(mem::size_of::<u16>() * 3));
|
try!(reader.jump(mem::size_of::<u16>() * 3).map_err(Error::eof));
|
||||||
|
|
||||||
let (mut cmap_table, mut head_table) = (None, None);
|
let (mut cmap_table, mut head_table) = (None, None);
|
||||||
let (mut hhea_table, mut hmtx_table) = (None, None);
|
let (mut hhea_table, mut hmtx_table) = (None, None);
|
||||||
let (mut glyf_table, mut loca_table) = (None, None);
|
let (mut glyf_table, mut loca_table) = (None, None);
|
||||||
|
|
||||||
for _ in 0..num_tables {
|
for _ in 0..num_tables {
|
||||||
let table_id = try!(reader.read_u32::<BigEndian>().map_err(drop));
|
let table_id = try!(reader.read_u32::<BigEndian>().map_err(Error::eof));
|
||||||
|
|
||||||
// Skip over the checksum.
|
// Skip over the checksum.
|
||||||
try!(reader.read_u32::<BigEndian>().map_err(drop));
|
try!(reader.read_u32::<BigEndian>().map_err(Error::eof));
|
||||||
|
|
||||||
let offset = try!(reader.read_u32::<BigEndian>().map_err(drop)) as usize;
|
let offset = try!(reader.read_u32::<BigEndian>().map_err(Error::eof)) as usize;
|
||||||
let length = try!(reader.read_u32::<BigEndian>().map_err(drop)) as usize;
|
let length = try!(reader.read_u32::<BigEndian>().map_err(Error::eof)) as usize;
|
||||||
|
|
||||||
let mut slot = match table_id {
|
let mut slot = match table_id {
|
||||||
CMAP => &mut cmap_table,
|
CMAP => &mut cmap_table,
|
||||||
|
@ -152,7 +152,7 @@ impl<'a> Font<'a> {
|
||||||
|
|
||||||
// Make sure there isn't more than one copy of the table.
|
// Make sure there isn't more than one copy of the table.
|
||||||
if slot.is_some() {
|
if slot.is_some() {
|
||||||
return Err(())
|
return Err(Error::Failed)
|
||||||
}
|
}
|
||||||
|
|
||||||
*slot = Some(FontTable {
|
*slot = Some(FontTable {
|
||||||
|
@ -168,10 +168,10 @@ impl<'a> Font<'a> {
|
||||||
Ok(Font {
|
Ok(Font {
|
||||||
bytes: bytes,
|
bytes: bytes,
|
||||||
|
|
||||||
cmap: CmapTable::new(try!(cmap_table.ok_or(()))),
|
cmap: CmapTable::new(try!(cmap_table.ok_or(Error::RequiredTableMissing))),
|
||||||
head: try!(HeadTable::new(try!(head_table.ok_or(())))),
|
head: try!(HeadTable::new(try!(head_table.ok_or(Error::RequiredTableMissing)))),
|
||||||
hhea: try!(HheaTable::new(try!(hhea_table.ok_or(())))),
|
hhea: try!(HheaTable::new(try!(hhea_table.ok_or(Error::RequiredTableMissing)))),
|
||||||
hmtx: HmtxTable::new(try!(hmtx_table.ok_or(()))),
|
hmtx: HmtxTable::new(try!(hmtx_table.ok_or(Error::RequiredTableMissing))),
|
||||||
|
|
||||||
glyf: glyf_table.map(GlyfTable::new),
|
glyf: glyf_table.map(GlyfTable::new),
|
||||||
loca: loca_table,
|
loca: loca_table,
|
||||||
|
@ -179,35 +179,36 @@ impl<'a> Font<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://github.com/kreativekorp/ksfl/wiki/Macintosh-Resource-File-Format
|
/// https://github.com/kreativekorp/ksfl/wiki/Macintosh-Resource-File-Format
|
||||||
pub fn from_dfont<'b>(bytes: &'b [u8]) -> Result<Font<'b>, ()> {
|
pub fn from_dfont<'b>(bytes: &'b [u8]) -> Result<Font<'b>, Error> {
|
||||||
let mut reader = bytes;
|
let mut reader = bytes;
|
||||||
|
|
||||||
// Read the Mac resource file header.
|
// Read the Mac resource file header.
|
||||||
let resource_data_offset = try!(reader.read_u32::<BigEndian>().map_err(drop));
|
let resource_data_offset = try!(reader.read_u32::<BigEndian>().map_err(Error::eof));
|
||||||
let resource_map_offset = try!(reader.read_u32::<BigEndian>().map_err(drop));
|
let resource_map_offset = try!(reader.read_u32::<BigEndian>().map_err(Error::eof));
|
||||||
let resource_data_size = try!(reader.read_u32::<BigEndian>().map_err(drop));
|
let resource_data_size = try!(reader.read_u32::<BigEndian>().map_err(Error::eof));
|
||||||
let resource_map_size = try!(reader.read_u32::<BigEndian>().map_err(drop));
|
let resource_map_size = try!(reader.read_u32::<BigEndian>().map_err(Error::eof));
|
||||||
|
|
||||||
// Move to the fields we care about in the resource map.
|
// Move to the fields we care about in the resource map.
|
||||||
reader = bytes;
|
reader = bytes;
|
||||||
try!(reader.jump(resource_map_offset as usize + mem::size_of::<u32>() * 5 +
|
try!(reader.jump(resource_map_offset as usize + mem::size_of::<u32>() * 5 +
|
||||||
mem::size_of::<u16>() * 2));
|
mem::size_of::<u16>() * 2).map_err(Error::eof));
|
||||||
|
|
||||||
// Read the type list and name list offsets.
|
// Read the type list and name list offsets.
|
||||||
let type_list_offset = try!(reader.read_u16::<BigEndian>().map_err(drop));
|
let type_list_offset = try!(reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
let name_list_offset = try!(reader.read_u16::<BigEndian>().map_err(drop));
|
let name_list_offset = try!(reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
|
|
||||||
// Move to the type list.
|
// Move to the type list.
|
||||||
reader = bytes;
|
reader = bytes;
|
||||||
try!(reader.jump(resource_map_offset as usize + type_list_offset as usize));
|
try!(reader.jump(resource_map_offset as usize + type_list_offset as usize)
|
||||||
|
.map_err(Error::eof));
|
||||||
|
|
||||||
// Find the 'sfnt' type.
|
// Find the 'sfnt' type.
|
||||||
let type_count = (try!(reader.read_i16::<BigEndian>().map_err(drop)) + 1) as usize;
|
let type_count = (try!(reader.read_i16::<BigEndian>().map_err(Error::eof)) + 1) as usize;
|
||||||
let mut resource_count_and_list_offset = None;
|
let mut resource_count_and_list_offset = None;
|
||||||
for type_index in 0..type_count {
|
for type_index in 0..type_count {
|
||||||
let type_id = try!(reader.read_u32::<BigEndian>().map_err(drop));
|
let type_id = try!(reader.read_u32::<BigEndian>().map_err(Error::eof));
|
||||||
let resource_count = try!(reader.read_u16::<BigEndian>().map_err(drop));
|
let resource_count = try!(reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
let resource_list_offset = try!(reader.read_u16::<BigEndian>().map_err(drop));
|
let resource_list_offset = try!(reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
if type_id == SFNT {
|
if type_id == SFNT {
|
||||||
resource_count_and_list_offset = Some((resource_count, resource_list_offset));
|
resource_count_and_list_offset = Some((resource_count, resource_list_offset));
|
||||||
break
|
break
|
||||||
|
@ -217,12 +218,12 @@ impl<'a> Font<'a> {
|
||||||
// Unpack the resource count and list offset.
|
// Unpack the resource count and list offset.
|
||||||
let resource_count;
|
let resource_count;
|
||||||
match resource_count_and_list_offset {
|
match resource_count_and_list_offset {
|
||||||
None => return Err(()),
|
None => return Err(Error::Failed),
|
||||||
Some((count, resource_list_offset)) => {
|
Some((count, resource_list_offset)) => {
|
||||||
resource_count = count;
|
resource_count = count;
|
||||||
reader = bytes;
|
reader = bytes;
|
||||||
try!(reader.jump(resource_map_offset as usize + type_list_offset as usize +
|
try!(reader.jump(resource_map_offset as usize + type_list_offset as usize +
|
||||||
resource_list_offset as usize));
|
resource_list_offset as usize).map_err(Error::eof));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,45 +231,54 @@ impl<'a> Font<'a> {
|
||||||
//
|
//
|
||||||
// TODO(pcwalton): This only gets the first one. Allow the user of this library to select
|
// TODO(pcwalton): This only gets the first one. Allow the user of this library to select
|
||||||
// others.
|
// others.
|
||||||
let sfnt_id = try!(reader.read_u16::<BigEndian>().map_err(drop));
|
let sfnt_id = try!(reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
let sfnt_name_offset = try!(reader.read_u16::<BigEndian>().map_err(drop));
|
let sfnt_name_offset = try!(reader.read_u16::<BigEndian>().map_err(Error::eof));
|
||||||
let sfnt_data_offset = try!(reader.read_u32::<BigEndian>().map_err(drop)) & 0x00ffffff;
|
let sfnt_data_offset = try!(reader.read_u32::<BigEndian>().map_err(Error::eof)) &
|
||||||
let sfnt_ptr = try!(reader.read_u32::<BigEndian>().map_err(drop));
|
0x00ffffff;
|
||||||
|
let sfnt_ptr = try!(reader.read_u32::<BigEndian>().map_err(Error::eof));
|
||||||
|
|
||||||
// Load the resource.
|
// Load the resource.
|
||||||
reader = bytes;
|
reader = bytes;
|
||||||
try!(reader.jump(resource_data_offset as usize + sfnt_data_offset as usize));
|
try!(reader.jump(resource_data_offset as usize + sfnt_data_offset as usize)
|
||||||
let sfnt_size = try!(reader.read_u32::<BigEndian>().map_err(drop));
|
.map_err(Error::eof));
|
||||||
|
let sfnt_size = try!(reader.read_u32::<BigEndian>().map_err(Error::eof));
|
||||||
Font::from_otf(&reader[0..sfnt_size as usize])
|
Font::from_otf(&reader[0..sfnt_size as usize])
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn glyph_ranges_for_codepoint_ranges(&self, codepoint_ranges: &[CodepointRange])
|
pub fn glyph_ranges_for_codepoint_ranges(&self, codepoint_ranges: &[CodepointRange])
|
||||||
-> Result<GlyphRanges, ()> {
|
-> Result<GlyphRanges, Error> {
|
||||||
self.cmap.glyph_ranges_for_codepoint_ranges(codepoint_ranges)
|
self.cmap.glyph_ranges_for_codepoint_ranges(codepoint_ranges)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn for_each_point<F>(&self, glyph_id: u16, callback: F) -> Result<(), ()>
|
pub fn for_each_point<F>(&self, glyph_id: u16, callback: F) -> Result<(), Error>
|
||||||
where F: FnMut(&Point) {
|
where F: FnMut(&Point) {
|
||||||
match self.glyf {
|
match self.glyf {
|
||||||
Some(glyf) => {
|
Some(glyf) => {
|
||||||
glyf.for_each_point(&self.head,
|
let loca = match self.loca {
|
||||||
try!(self.loca.as_ref().ok_or(())),
|
Some(ref loca) => loca,
|
||||||
glyph_id,
|
None => return Err(Error::RequiredTableMissing),
|
||||||
callback)
|
};
|
||||||
|
|
||||||
|
glyf.for_each_point(&self.head, loca, glyph_id, callback)
|
||||||
}
|
}
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn glyph_bounds(&self, glyph_id: u16) -> Result<GlyphBounds, ()> {
|
pub fn glyph_bounds(&self, glyph_id: u16) -> Result<GlyphBounds, Error> {
|
||||||
match self.glyf {
|
match self.glyf {
|
||||||
Some(glyf) => {
|
Some(glyf) => {
|
||||||
glyf.glyph_bounds(&self.head, try!(self.loca.as_ref().ok_or(())), glyph_id)
|
let loca = match self.loca {
|
||||||
|
Some(ref loca) => loca,
|
||||||
|
None => return Err(Error::RequiredTableMissing),
|
||||||
|
};
|
||||||
|
|
||||||
|
glyf.glyph_bounds(&self.head, loca, glyph_id)
|
||||||
}
|
}
|
||||||
None => Err(()),
|
None => Err(Error::RequiredTableMissing),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,8 +288,46 @@ impl<'a> Font<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn metrics_for_glyph(&self, glyph_id: u16) -> Result<HorizontalMetrics, ()> {
|
pub fn metrics_for_glyph(&self, glyph_id: u16) -> Result<HorizontalMetrics, Error> {
|
||||||
self.hmtx.metrics_for_glyph(&self.hhea, glyph_id)
|
self.hmtx.metrics_for_glyph(&self.hhea, glyph_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can occur when parsing OpenType fonts.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// A miscellaneous error occurred.
|
||||||
|
Failed,
|
||||||
|
/// The file ended unexpectedly.
|
||||||
|
UnexpectedEof,
|
||||||
|
/// The file declared that it was in a version of the format we don't support.
|
||||||
|
UnsupportedVersion,
|
||||||
|
/// The file was of a format we don't support.
|
||||||
|
UnknownFormat,
|
||||||
|
/// The font had a glyph format we don't support.
|
||||||
|
UnsupportedGlyphFormat,
|
||||||
|
/// We don't support the declared version of the font's character map.
|
||||||
|
UnsupportedCmapVersion,
|
||||||
|
/// The font character map has an unsupported platform/encoding ID.
|
||||||
|
UnsupportedCmapEncoding,
|
||||||
|
/// The font character map has an unsupported format.
|
||||||
|
UnsupportedCmapFormat,
|
||||||
|
/// We don't support the declared version of the font header.
|
||||||
|
UnsupportedHeadVersion,
|
||||||
|
/// We don't support the declared version of the font's horizontal metrics.
|
||||||
|
UnsupportedHheaVersion,
|
||||||
|
/// A required table is missing.
|
||||||
|
RequiredTableMissing,
|
||||||
|
/// The glyph is a composite glyph.
|
||||||
|
///
|
||||||
|
/// TODO(pcwalton): Support these.
|
||||||
|
CompositeGlyph,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error {
|
||||||
|
#[inline]
|
||||||
|
pub fn eof<T>(_: T) -> Error {
|
||||||
|
Error::UnexpectedEof
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
use euclid::{Point2D, Rect, Size2D};
|
use euclid::{Point2D, Rect, Size2D};
|
||||||
use gl::types::{GLsizeiptr, GLuint};
|
use gl::types::{GLsizeiptr, GLuint};
|
||||||
use gl;
|
use gl;
|
||||||
use otf::Font;
|
use otf::{self, Font};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ impl OutlineBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_glyph(&mut self, font: &Font, glyph_id: u16) -> Result<(), ()> {
|
pub fn add_glyph(&mut self, font: &Font, glyph_id: u16) -> Result<(), otf::Error> {
|
||||||
let glyph_index = self.descriptors.len() as u16;
|
let glyph_index = self.descriptors.len() as u16;
|
||||||
|
|
||||||
let mut point_index = self.vertices.len() as u32;
|
let mut point_index = self.vertices.len() as u32;
|
||||||
|
|
Loading…
Reference in New Issue