diff --git a/src/otf/cmap.rs b/src/otf/cmap.rs index fcfee069..6b593fc9 100644 --- a/src/otf/cmap.rs +++ b/src/otf/cmap.rs @@ -11,7 +11,7 @@ use byteorder::{BigEndian, ReadBytesExt}; use charmap::CodepointRange; use glyph_range::{GlyphRange, GlyphRanges, MappedGlyphRange}; -use otf::FontTable; +use otf::{Error, FontTable}; use std::cmp; use std::mem; use std::u16; @@ -40,30 +40,30 @@ impl<'a> CmapTable<'a> { } pub fn glyph_ranges_for_codepoint_ranges(&self, codepoint_ranges: &[CodepointRange]) - -> Result { + -> Result { let mut cmap_reader = self.table.bytes; // Check version. - if try!(cmap_reader.read_u16::().map_err(drop)) != 0 { - return Err(()) + if try!(cmap_reader.read_u16::().map_err(Error::eof)) != 0 { + return Err(Error::UnsupportedCmapVersion) } - let num_tables = try!(cmap_reader.read_u16::().map_err(drop)); + let num_tables = try!(cmap_reader.read_u16::().map_err(Error::eof)); // Check platform ID and encoding. // TODO(pcwalton): Handle more. let mut table_found = false; for _ in 0..num_tables { - let platform_id = try!(cmap_reader.read_u16::().map_err(drop)); - let encoding_id = try!(cmap_reader.read_u16::().map_err(drop)); - let offset = try!(cmap_reader.read_u32::().map_err(drop)); + let platform_id = try!(cmap_reader.read_u16::().map_err(Error::eof)); + let encoding_id = try!(cmap_reader.read_u16::().map_err(Error::eof)); + let offset = try!(cmap_reader.read_u32::().map_err(Error::eof)); match (platform_id, encoding_id) { (PLATFORM_ID_UNICODE, _) | (PLATFORM_ID_MICROSOFT, MICROSOFT_ENCODING_ID_UNICODE_BMP) | (PLATFORM_ID_MICROSOFT, MICROSOFT_ENCODING_ID_UNICODE_UCS4) => { // Move to the mapping table. 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; break } @@ -72,22 +72,22 @@ impl<'a> CmapTable<'a> { } if !table_found { - return Err(()) + return Err(Error::UnsupportedCmapEncoding) } // Check the mapping table format. - let format = try!(cmap_reader.read_u16::().map_err(drop)); + let format = try!(cmap_reader.read_u16::().map_err(Error::eof)); if format != FORMAT_SEGMENT_MAPPING_TO_DELTA_VALUES { - return Err(()) + return Err(Error::UnsupportedCmapFormat) } // Read the mapping table header. - let _length = try!(cmap_reader.read_u16::().map_err(drop)); - let _language = try!(cmap_reader.read_u16::().map_err(drop)); - let seg_count = try!(cmap_reader.read_u16::().map_err(drop)) / 2; - let _search_range = try!(cmap_reader.read_u16::().map_err(drop)); - let _entry_selector = try!(cmap_reader.read_u16::().map_err(drop)); - let _range_shift = try!(cmap_reader.read_u16::().map_err(drop)); + let _length = try!(cmap_reader.read_u16::().map_err(Error::eof)); + let _language = try!(cmap_reader.read_u16::().map_err(Error::eof)); + let seg_count = try!(cmap_reader.read_u16::().map_err(Error::eof)) / 2; + let _search_range = try!(cmap_reader.read_u16::().map_err(Error::eof)); + let _entry_selector = try!(cmap_reader.read_u16::().map_err(Error::eof)); + let _range_shift = try!(cmap_reader.read_u16::().map_err(Error::eof)); // 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` // are the correct names. let (end_codes, mut start_codes) = (cmap_reader, cmap_reader); - try!(start_codes.jump((seg_count as usize + 1) * mem::size_of::())); + try!(start_codes.jump((seg_count as usize + 1) * mem::size_of::()) + .map_err(Error::eof)); let mut id_deltas = start_codes; - try!(id_deltas.jump(seg_count as usize * mem::size_of::())); + try!(id_deltas.jump(seg_count as usize * mem::size_of::()).map_err(Error::eof)); let mut id_range_offsets = id_deltas; - try!(id_range_offsets.jump(seg_count as usize * mem::size_of::())); + try!(id_range_offsets.jump(seg_count as usize * mem::size_of::()) + .map_err(Error::eof)); let mut glyph_ids = id_range_offsets; - try!(glyph_ids.jump(seg_count as usize * mem::size_of::())); + try!(glyph_ids.jump(seg_count as usize * mem::size_of::()).map_err(Error::eof)); // Now perform the lookups. let mut glyph_ranges = GlyphRanges::new(); @@ -130,16 +132,16 @@ impl<'a> CmapTable<'a> { let mid = (low + high) / 2; let mut end_code = end_codes; - try!(end_code.jump(mid as usize * 2)); - let end_code = try!(end_code.read_u16::().map_err(drop)); + try!(end_code.jump(mid as usize * 2).map_err(Error::eof)); + let end_code = try!(end_code.read_u16::().map_err(Error::eof)); if start_codepoint_range > end_code { low = mid + 1; continue } let mut start_code = start_codes; - try!(start_code.jump(mid as usize * 2)); - let start_code = try!(start_code.read_u16::().map_err(drop)); + try!(start_code.jump(mid as usize * 2).map_err(Error::eof)); + let start_code = try!(start_code.read_u16::().map_err(Error::eof)); if start_codepoint_range < start_code { high = mid; continue @@ -169,14 +171,15 @@ impl<'a> CmapTable<'a> { let mut end_code = end_codes; let mut id_range_offset = id_range_offsets; let mut id_delta = id_deltas; - try!(start_code.jump(segment_index as usize * 2)); - try!(end_code.jump(segment_index as usize * 2)); - try!(id_range_offset.jump(segment_index as usize * 2)); - try!(id_delta.jump(segment_index as usize * 2)); - let start_code = try!(start_code.read_u16::().map_err(drop)); - let end_code = try!(end_code.read_u16::().map_err(drop)); - let id_range_offset = try!(id_range_offset.read_u16::().map_err(drop)); - let id_delta = try!(id_delta.read_i16::().map_err(drop)); + try!(start_code.jump(segment_index as usize * 2).map_err(Error::eof)); + try!(end_code.jump(segment_index as usize * 2).map_err(Error::eof)); + try!(id_range_offset.jump(segment_index as usize * 2).map_err(Error::eof)); + try!(id_delta.jump(segment_index as usize * 2).map_err(Error::eof)); + let start_code = try!(start_code.read_u16::().map_err(Error::eof)); + let end_code = try!(end_code.read_u16::().map_err(Error::eof)); + let id_range_offset = try!(id_range_offset.read_u16::() + .map_err(Error::eof)); + let id_delta = try!(id_delta.read_i16::().map_err(Error::eof)); end_codepoint_range = cmp::min(end_codepoint_range, end_code); codepoint_range.start = (end_codepoint_range + 1) as u32; @@ -203,8 +206,9 @@ impl<'a> CmapTable<'a> { // Otherwise, look up the glyphs individually. for code_offset in start_code_offset..(end_code_offset + 1) { let mut glyph_id = glyph_ids; - try!(glyph_id.jump((id_range_offset as usize + code_offset as usize) * 2)); - let mut glyph_id = try!(glyph_id.read_u16::().map_err(drop)); + try!(glyph_id.jump((id_range_offset as usize + code_offset as usize) * 2) + .map_err(Error::eof)); + let mut glyph_id = try!(glyph_id.read_u16::().map_err(Error::eof)); if glyph_id == 0 { glyph_ranges.ranges.push(MappedGlyphRange { codepoint_start: start_code as u32 + code_offset as u32, diff --git a/src/otf/glyf.rs b/src/otf/glyf.rs index 7a6389b7..bd31d272 100644 --- a/src/otf/glyf.rs +++ b/src/otf/glyf.rs @@ -10,9 +10,9 @@ use byteorder::{BigEndian, ReadBytesExt}; use euclid::Point2D; -use otf::FontTable; use otf::head::HeadTable; use otf::loca::LocaTable; +use otf::{Error, FontTable}; use outline::GlyphBounds; use std::mem; use util::Jump; @@ -54,7 +54,7 @@ impl<'a> GlyfTable<'a> { loca_table: &LocaTable, glyph_id: u16, mut callback: F) - -> Result<(), ()> where F: FnMut(&Point) { + -> Result<(), Error> where F: FnMut(&Point) { let mut reader = self.table.bytes; match try!(loca_table.location_of(head_table, glyph_id)) { @@ -62,24 +62,25 @@ impl<'a> GlyfTable<'a> { // No points. 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::().map_err(drop)); + let number_of_contours = try!(reader.read_i16::().map_err(Error::eof)); if number_of_contours < 0 { // TODO(pcwalton): Composite glyphs. - return Err(()) + return Err(Error::CompositeGlyph) } - try!(reader.jump(mem::size_of::() * 4)); + try!(reader.jump(mem::size_of::() * 4).map_err(Error::eof)); // Find out how many points we have. let mut endpoints_reader = reader; - try!(reader.jump(mem::size_of::() as usize * (number_of_contours as usize - 1))); - let number_of_points = try!(reader.read_u16::().map_err(drop)) + 1; + try!(reader.jump(mem::size_of::() as usize * (number_of_contours as usize - 1)) + .map_err(Error::eof)); + let number_of_points = try!(reader.read_u16::().map_err(Error::eof)) + 1; // Skip over hinting instructions. - let instruction_length = try!(reader.read_u16::().map_err(drop)); - try!(reader.jump(instruction_length as usize)); + let instruction_length = try!(reader.read_u16::().map_err(Error::eof)); + try!(reader.jump(instruction_length as usize).map_err(Error::eof)); // Find the offsets of the X and Y coordinates. let flags_reader = reader; @@ -89,14 +90,14 @@ impl<'a> GlyfTable<'a> { // Set up the streams. let mut flag_parser = try!(FlagParser::new(flags_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; // Now parse the contours. let (mut position, mut point_index) = (Point2D::new(0, 0), 0); for _ in 0..number_of_contours { - let contour_point_count = - try!(endpoints_reader.read_u16::().map_err(drop)) - point_index + 1; + let contour_point_count = try!(endpoints_reader.read_u16::() + .map_err(Error::eof)) - point_index + 1; let mut first_on_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); 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) { delta.x = -delta.x } } else if !flags.contains(THIS_X_IS_SAME) { - delta.x = try!(x_coordinate_reader.read_i16::().map_err(drop)) + delta.x = try!(x_coordinate_reader.read_i16::().map_err(Error::eof)) } 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) { delta.y = -delta.y } } else if !flags.contains(THIS_Y_IS_SAME) { - delta.y = try!(y_coordinate_reader.read_i16::().map_err(drop)) + delta.y = try!(y_coordinate_reader.read_i16::().map_err(Error::eof)) } 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) - -> Result { + -> Result { let mut reader = self.table.bytes; match try!(loca_table.location_of(head_table, glyph_id)) { @@ -202,16 +203,16 @@ impl<'a> GlyfTable<'a> { 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. - try!(reader.read_i16::().map_err(drop)); + try!(reader.read_i16::().map_err(Error::eof)); - let x_min = try!(reader.read_i16::().map_err(drop)); - let y_min = try!(reader.read_i16::().map_err(drop)); - let x_max = try!(reader.read_i16::().map_err(drop)); - let y_max = try!(reader.read_i16::().map_err(drop)); + let x_min = try!(reader.read_i16::().map_err(Error::eof)); + let y_min = try!(reader.read_i16::().map_err(Error::eof)); + let x_max = try!(reader.read_i16::().map_err(Error::eof)); + let y_max = try!(reader.read_i16::().map_err(Error::eof)); Ok(GlyphBounds { left: x_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. #[inline] fn calculate_size_of_x_coordinates<'a, 'b>(reader: &'a mut &'b [u8], number_of_points: u16) - -> Result { + -> Result { let (mut x_coordinate_length, mut points_left) = (0, number_of_points); 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) { 1 } 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) { @@ -255,7 +256,7 @@ struct FlagParser<'a> { impl<'a> FlagParser<'a> { #[inline] - fn new(buffer: &[u8]) -> Result { + fn new(buffer: &[u8]) -> Result { let mut parser = FlagParser { next: buffer, current: &buffer[0], @@ -266,18 +267,26 @@ impl<'a> FlagParser<'a> { } #[inline] - fn next(&mut self) -> Result<(), ()> { + fn next(&mut self) -> Result<(), Error> { if self.repeats_left > 0 { self.repeats_left -= 1; 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); self.next = &self.next[1..]; 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..]; } else { self.repeats_left = 0 diff --git a/src/otf/head.rs b/src/otf/head.rs index 1ca71eb2..df172173 100644 --- a/src/otf/head.rs +++ b/src/otf/head.rs @@ -9,7 +9,7 @@ // except according to those terms. use byteorder::{BigEndian, ReadBytesExt}; -use otf::FontTable; +use otf::{Error, FontTable}; use std::mem; use util::Jump; @@ -22,38 +22,38 @@ pub struct HeadTable { } impl HeadTable { - pub fn new(table: FontTable) -> Result { + pub fn new(table: FontTable) -> Result { let mut reader = table.bytes; // Check the version. - let major_version = try!(reader.read_u16::().map_err(drop)); - let minor_version = try!(reader.read_u16::().map_err(drop)); + let major_version = try!(reader.read_u16::().map_err(Error::eof)); + let minor_version = try!(reader.read_u16::().map_err(Error::eof)); if (major_version, minor_version) != (1, 0) { - return Err(()) + return Err(Error::UnsupportedHeadVersion) } // Check the magic number. - try!(reader.jump(mem::size_of::() * 2)); - let magic_number = try!(reader.read_u32::().map_err(drop)); + try!(reader.jump(mem::size_of::() * 2).map_err(Error::eof)); + let magic_number = try!(reader.read_u32::().map_err(Error::eof)); if magic_number != MAGIC_NUMBER { - return Err(()) + return Err(Error::UnknownFormat) } // Read the units per em. - try!(reader.jump(mem::size_of::())); - let units_per_em = try!(reader.read_u16::().map_err(drop)); + try!(reader.jump(mem::size_of::()).map_err(Error::eof)); + let units_per_em = try!(reader.read_u16::().map_err(Error::eof)); // Read the index-to-location format. try!(reader.jump(mem::size_of::() * 2 + mem::size_of::() * 4 + mem::size_of::() * 2 + - mem::size_of::())); - let index_to_loc_format = try!(reader.read_i16::().map_err(drop)); + mem::size_of::()).map_err(Error::eof)); + let index_to_loc_format = try!(reader.read_i16::().map_err(Error::eof)); // Check the glyph data format. - let glyph_data_format = try!(reader.read_i16::().map_err(drop)); + let glyph_data_format = try!(reader.read_i16::().map_err(Error::eof)); if glyph_data_format != 0 { - return Err(()) + return Err(Error::UnsupportedGlyphFormat) } Ok(HeadTable { diff --git a/src/otf/hhea.rs b/src/otf/hhea.rs index 052582aa..39ebc85d 100644 --- a/src/otf/hhea.rs +++ b/src/otf/hhea.rs @@ -9,7 +9,7 @@ // except according to those terms. use byteorder::{BigEndian, ReadBytesExt}; -use otf::FontTable; +use otf::{Error, FontTable}; use std::mem; use util::Jump; @@ -19,19 +19,19 @@ pub struct HheaTable { } impl HheaTable { - pub fn new(table: FontTable) -> Result { + pub fn new(table: FontTable) -> Result { let mut reader = table.bytes; // Check the version. - let major_version = try!(reader.read_u16::().map_err(drop)); - let minor_version = try!(reader.read_u16::().map_err(drop)); + let major_version = try!(reader.read_u16::().map_err(Error::eof)); + let minor_version = try!(reader.read_u16::().map_err(Error::eof)); if (major_version, minor_version) != (1, 0) { - return Err(()) + return Err(Error::UnsupportedHheaVersion) } // Read the number of `hmtx` entries. - try!(reader.jump(mem::size_of::() * 15)); - let number_of_h_metrics = try!(reader.read_u16::().map_err(drop)); + try!(reader.jump(mem::size_of::() * 15).map_err(Error::eof)); + let number_of_h_metrics = try!(reader.read_u16::().map_err(Error::eof)); Ok(HheaTable { number_of_h_metrics: number_of_h_metrics, diff --git a/src/otf/hmtx.rs b/src/otf/hmtx.rs index b51f4bc9..874ecc69 100644 --- a/src/otf/hmtx.rs +++ b/src/otf/hmtx.rs @@ -9,8 +9,8 @@ // except according to those terms. use byteorder::{BigEndian, ReadBytesExt}; -use otf::FontTable; use otf::hhea::HheaTable; +use otf::{Error, FontTable}; use std::mem; use util::Jump; @@ -27,23 +27,23 @@ impl<'a> HmtxTable<'a> { } pub fn metrics_for_glyph(&self, hhea_table: &HheaTable, glyph_id: u16) - -> Result { + -> Result { let mut reader = self.table.bytes; // Read the advance width. let advance_width; if glyph_id < hhea_table.number_of_h_metrics { - try!(reader.jump(mem::size_of::() * 2 * glyph_id as usize)); - advance_width = try!(reader.read_u16::().map_err(drop)) + try!(reader.jump(mem::size_of::() * 2 * glyph_id as usize).map_err(Error::eof)); + advance_width = try!(reader.read_u16::().map_err(Error::eof)) } else { try!(reader.jump(mem::size_of::() * 2 * - (hhea_table.number_of_h_metrics - 1) as usize)); - advance_width = try!(reader.read_u16::().map_err(drop)); - try!(reader.jump(mem::size_of::() * glyph_id as usize)); + (hhea_table.number_of_h_metrics - 1) as usize).map_err(Error::eof)); + advance_width = try!(reader.read_u16::().map_err(Error::eof)); + try!(reader.jump(mem::size_of::() * glyph_id as usize).map_err(Error::eof)); } // Read the left-side bearing. - let lsb = try!(reader.read_i16::().map_err(drop)); + let lsb = try!(reader.read_i16::().map_err(Error::eof)); Ok(HorizontalMetrics { advance_width: advance_width, diff --git a/src/otf/loca.rs b/src/otf/loca.rs index d555c23b..87f5b94d 100644 --- a/src/otf/loca.rs +++ b/src/otf/loca.rs @@ -9,8 +9,8 @@ // except according to those terms. use byteorder::{BigEndian, ReadBytesExt}; -use otf::FontTable; use otf::head::HeadTable; +use otf::{Error, FontTable}; use util::Jump; pub struct LocaTable<'a> { @@ -18,31 +18,33 @@ pub struct LocaTable<'a> { } impl<'a> LocaTable<'a> { - pub fn new(loca_table: FontTable<'a>) -> Result, ()> { + pub fn new(loca_table: FontTable<'a>) -> Result, Error> { Ok(LocaTable { table: loca_table, }) } - pub fn location_of(&self, head_table: &HeadTable, glyph_id: u16) -> Result, ()> { + pub fn location_of(&self, head_table: &HeadTable, glyph_id: u16) + -> Result, Error> { let mut reader = self.table.bytes; let (this_location, next_location) = match head_table.index_to_loc_format { 0 => { - try!(reader.jump(glyph_id as usize * 2)); - let this_location = try!(reader.read_u16::().map_err(drop)) as u32 * 2; - let next_location = match reader.read_u16::().map_err(drop) { + try!(reader.jump(glyph_id as usize * 2).map_err(Error::eof)); + let this_location = + try!(reader.read_u16::().map_err(Error::eof)) as u32 * 2; + let next_location = match reader.read_u16::() { Ok(next_location) => Ok(next_location as u32 * 2), - Err(_) => Err(()), + Err(_) => Err(Error::UnexpectedEof), }; (this_location, next_location) } 1 => { - try!(reader.jump(glyph_id as usize * 4)); - let this_location = try!(reader.read_u32::().map_err(drop)); - let next_location = reader.read_u32::().map_err(drop); + try!(reader.jump(glyph_id as usize * 4).map_err(Error::eof)); + let this_location = try!(reader.read_u32::().map_err(Error::eof)); + let next_location = reader.read_u32::().map_err(Error::eof); (this_location, next_location) } - _ => return Err(()), + _ => return Err(Error::UnknownFormat), }; if next_location == Ok(this_location) { diff --git a/src/otf/mod.rs b/src/otf/mod.rs index fe92cf84..4223e0fb 100644 --- a/src/otf/mod.rs +++ b/src/otf/mod.rs @@ -86,59 +86,59 @@ pub struct FontTable<'a> { } impl<'a> Font<'a> { - pub fn new<'b>(bytes: &'b [u8]) -> Result, ()> { + pub fn new<'b>(bytes: &'b [u8]) -> Result, Error> { // Check magic number. let mut reader = bytes; - let mut magic_number = try!(reader.read_u32::().map_err(drop)); + let mut magic_number = try!(reader.read_u32::().map_err(Error::eof)); match magic_number { TTCF => { // This is a font collection. Read the first font. // // TODO(pcwalton): Provide a mechanism to read others. - let major_version = try!(reader.read_u16::().map_err(drop)); - let minor_version = try!(reader.read_u16::().map_err(drop)); + let major_version = try!(reader.read_u16::().map_err(Error::eof)); + let minor_version = try!(reader.read_u16::().map_err(Error::eof)); if (major_version != 1 && major_version != 2) || minor_version != 0 { - return Err(()) + return Err(Error::UnsupportedVersion) } - let num_fonts = try!(reader.read_u32::().map_err(drop)); + let num_fonts = try!(reader.read_u32::().map_err(Error::eof)); if num_fonts == 0 { - return Err(()) + return Err(Error::Failed) } - let table_offset = try!(reader.read_u32::().map_err(drop)); + let table_offset = try!(reader.read_u32::().map_err(Error::eof)); Font::from_otf(&bytes[table_offset as usize..]) } magic_number if SFNT_VERSIONS.contains(&magic_number) => Font::from_otf(bytes), 0x0100 => Font::from_dfont(bytes), - _ => Err(()), + _ => Err(Error::UnknownFormat), } } - pub fn from_otf<'b>(bytes: &'b [u8]) -> Result, ()> { + pub fn from_otf<'b>(bytes: &'b [u8]) -> Result, Error> { let mut reader = bytes; - let mut magic_number = try!(reader.read_u32::().map_err(drop)); + let mut magic_number = try!(reader.read_u32::().map_err(Error::eof)); // Check version. if !SFNT_VERSIONS.contains(&magic_number) { - return Err(()) + return Err(Error::UnknownFormat) } - let num_tables = try!(reader.read_u16::().map_err(drop)); - try!(reader.jump(mem::size_of::() * 3)); + let num_tables = try!(reader.read_u16::().map_err(Error::eof)); + try!(reader.jump(mem::size_of::() * 3).map_err(Error::eof)); let (mut cmap_table, mut head_table) = (None, None); let (mut hhea_table, mut hmtx_table) = (None, None); let (mut glyf_table, mut loca_table) = (None, None); for _ in 0..num_tables { - let table_id = try!(reader.read_u32::().map_err(drop)); + let table_id = try!(reader.read_u32::().map_err(Error::eof)); // Skip over the checksum. - try!(reader.read_u32::().map_err(drop)); + try!(reader.read_u32::().map_err(Error::eof)); - let offset = try!(reader.read_u32::().map_err(drop)) as usize; - let length = try!(reader.read_u32::().map_err(drop)) as usize; + let offset = try!(reader.read_u32::().map_err(Error::eof)) as usize; + let length = try!(reader.read_u32::().map_err(Error::eof)) as usize; let mut slot = match table_id { CMAP => &mut cmap_table, @@ -152,7 +152,7 @@ impl<'a> Font<'a> { // Make sure there isn't more than one copy of the table. if slot.is_some() { - return Err(()) + return Err(Error::Failed) } *slot = Some(FontTable { @@ -168,10 +168,10 @@ impl<'a> Font<'a> { Ok(Font { bytes: bytes, - cmap: CmapTable::new(try!(cmap_table.ok_or(()))), - head: try!(HeadTable::new(try!(head_table.ok_or(())))), - hhea: try!(HheaTable::new(try!(hhea_table.ok_or(())))), - hmtx: HmtxTable::new(try!(hmtx_table.ok_or(()))), + cmap: CmapTable::new(try!(cmap_table.ok_or(Error::RequiredTableMissing))), + head: try!(HeadTable::new(try!(head_table.ok_or(Error::RequiredTableMissing)))), + hhea: try!(HheaTable::new(try!(hhea_table.ok_or(Error::RequiredTableMissing)))), + hmtx: HmtxTable::new(try!(hmtx_table.ok_or(Error::RequiredTableMissing))), glyf: glyf_table.map(GlyfTable::new), loca: loca_table, @@ -179,35 +179,36 @@ impl<'a> Font<'a> { } /// https://github.com/kreativekorp/ksfl/wiki/Macintosh-Resource-File-Format - pub fn from_dfont<'b>(bytes: &'b [u8]) -> Result, ()> { + pub fn from_dfont<'b>(bytes: &'b [u8]) -> Result, Error> { let mut reader = bytes; // Read the Mac resource file header. - let resource_data_offset = try!(reader.read_u32::().map_err(drop)); - let resource_map_offset = try!(reader.read_u32::().map_err(drop)); - let resource_data_size = try!(reader.read_u32::().map_err(drop)); - let resource_map_size = try!(reader.read_u32::().map_err(drop)); + let resource_data_offset = try!(reader.read_u32::().map_err(Error::eof)); + let resource_map_offset = try!(reader.read_u32::().map_err(Error::eof)); + let resource_data_size = try!(reader.read_u32::().map_err(Error::eof)); + let resource_map_size = try!(reader.read_u32::().map_err(Error::eof)); // Move to the fields we care about in the resource map. reader = bytes; try!(reader.jump(resource_map_offset as usize + mem::size_of::() * 5 + - mem::size_of::() * 2)); + mem::size_of::() * 2).map_err(Error::eof)); // Read the type list and name list offsets. - let type_list_offset = try!(reader.read_u16::().map_err(drop)); - let name_list_offset = try!(reader.read_u16::().map_err(drop)); + let type_list_offset = try!(reader.read_u16::().map_err(Error::eof)); + let name_list_offset = try!(reader.read_u16::().map_err(Error::eof)); // Move to the type list. 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. - let type_count = (try!(reader.read_i16::().map_err(drop)) + 1) as usize; + let type_count = (try!(reader.read_i16::().map_err(Error::eof)) + 1) as usize; let mut resource_count_and_list_offset = None; for type_index in 0..type_count { - let type_id = try!(reader.read_u32::().map_err(drop)); - let resource_count = try!(reader.read_u16::().map_err(drop)); - let resource_list_offset = try!(reader.read_u16::().map_err(drop)); + let type_id = try!(reader.read_u32::().map_err(Error::eof)); + let resource_count = try!(reader.read_u16::().map_err(Error::eof)); + let resource_list_offset = try!(reader.read_u16::().map_err(Error::eof)); if type_id == SFNT { resource_count_and_list_offset = Some((resource_count, resource_list_offset)); break @@ -217,12 +218,12 @@ impl<'a> Font<'a> { // Unpack the resource count and list offset. let resource_count; match resource_count_and_list_offset { - None => return Err(()), + None => return Err(Error::Failed), Some((count, resource_list_offset)) => { resource_count = count; reader = bytes; 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 // others. - let sfnt_id = try!(reader.read_u16::().map_err(drop)); - let sfnt_name_offset = try!(reader.read_u16::().map_err(drop)); - let sfnt_data_offset = try!(reader.read_u32::().map_err(drop)) & 0x00ffffff; - let sfnt_ptr = try!(reader.read_u32::().map_err(drop)); + let sfnt_id = try!(reader.read_u16::().map_err(Error::eof)); + let sfnt_name_offset = try!(reader.read_u16::().map_err(Error::eof)); + let sfnt_data_offset = try!(reader.read_u32::().map_err(Error::eof)) & + 0x00ffffff; + let sfnt_ptr = try!(reader.read_u32::().map_err(Error::eof)); // Load the resource. reader = bytes; - try!(reader.jump(resource_data_offset as usize + sfnt_data_offset as usize)); - let sfnt_size = try!(reader.read_u32::().map_err(drop)); + try!(reader.jump(resource_data_offset as usize + sfnt_data_offset as usize) + .map_err(Error::eof)); + let sfnt_size = try!(reader.read_u32::().map_err(Error::eof)); Font::from_otf(&reader[0..sfnt_size as usize]) } #[inline] pub fn glyph_ranges_for_codepoint_ranges(&self, codepoint_ranges: &[CodepointRange]) - -> Result { + -> Result { self.cmap.glyph_ranges_for_codepoint_ranges(codepoint_ranges) } #[inline] - pub fn for_each_point(&self, glyph_id: u16, callback: F) -> Result<(), ()> + pub fn for_each_point(&self, glyph_id: u16, callback: F) -> Result<(), Error> where F: FnMut(&Point) { match self.glyf { Some(glyf) => { - glyf.for_each_point(&self.head, - try!(self.loca.as_ref().ok_or(())), - glyph_id, - callback) + let loca = match self.loca { + Some(ref loca) => loca, + None => return Err(Error::RequiredTableMissing), + }; + + glyf.for_each_point(&self.head, loca, glyph_id, callback) } None => Ok(()), } } #[inline] - pub fn glyph_bounds(&self, glyph_id: u16) -> Result { + pub fn glyph_bounds(&self, glyph_id: u16) -> Result { match self.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] - pub fn metrics_for_glyph(&self, glyph_id: u16) -> Result { + pub fn metrics_for_glyph(&self, glyph_id: u16) -> Result { 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) -> Error { + Error::UnexpectedEof + } +} + diff --git a/src/outline.rs b/src/outline.rs index bdbde6e4..a5d13e80 100644 --- a/src/outline.rs +++ b/src/outline.rs @@ -11,7 +11,7 @@ use euclid::{Point2D, Rect, Size2D}; use gl::types::{GLsizeiptr, GLuint}; use gl; -use otf::Font; +use otf::{self, Font}; use std::mem; 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 mut point_index = self.vertices.len() as u32;