1 // https://docs.microsoft.com/en-us/typography/opentype/spec/hmtx 2 3 use crate::parser::{Stream, LazyArray}; 4 use crate::{Font, TableName, GlyphId, HorizontalMetrics, Result, Error}; 5 use crate::raw::hmtx as raw; 6 7 impl<'a> Font<'a> { 8 /// Returns glyph's horizontal metrics. glyph_hor_metrics(&self, glyph_id: GlyphId) -> Result<HorizontalMetrics>9 pub fn glyph_hor_metrics(&self, glyph_id: GlyphId) -> Result<HorizontalMetrics> { 10 self.check_glyph_id(glyph_id)?; 11 let data = self.hmtx.ok_or_else(|| Error::TableMissing(TableName::HorizontalMetrics))?; 12 let mut s = Stream::new(data); 13 14 let number_of_hmetrics = self.number_of_hmetrics(); 15 if number_of_hmetrics == 0 { 16 return Err(Error::NoHorizontalMetrics); 17 } 18 19 let glyph_id = glyph_id.0; 20 21 let array: LazyArray<raw::HorizontalMetrics> = s.read_array(number_of_hmetrics)?; 22 23 if let Some(metrics) = array.get(glyph_id) { 24 Ok(HorizontalMetrics { 25 advance: metrics.advance_width(), 26 left_side_bearing: metrics.lsb(), 27 }) 28 } else { 29 // 'If the number_of_hmetrics is less than the total number of glyphs, 30 // then that array is followed by an array for the left side bearing values 31 // of the remaining glyphs.' 32 33 // Check for overflow. 34 if self.number_of_glyphs() < number_of_hmetrics { 35 return Err(Error::NoHorizontalMetrics); 36 } 37 38 let count = self.number_of_glyphs() - number_of_hmetrics; 39 let left_side_bearings: LazyArray<i16> = s.read_array(count)?; 40 let left_side_bearing = left_side_bearings.get(glyph_id) 41 .ok_or_else(|| Error::NoHorizontalMetrics)?; 42 43 // 'As an optimization, the number of records can be less than the number of glyphs, 44 // in which case the advance width value of the last record applies 45 // to all remaining glyph IDs.' 46 let last_metric = array.last().ok_or_else(|| Error::NoHorizontalMetrics)?; 47 48 Ok(HorizontalMetrics { 49 advance: last_metric.advance_width(), 50 left_side_bearing, 51 }) 52 } 53 } 54 } 55