diff --git a/src/export/pdf.rs b/src/export/pdf.rs index 811583e57..639d18b93 100644 --- a/src/export/pdf.rs +++ b/src/export/pdf.rs @@ -270,10 +270,18 @@ impl PdfFont { } // Subset the font using the selected characters. - let subsetted = font.subsetted( + let subset_result = font.subsetted( chars.iter().cloned(), &["head", "hhea", "hmtx", "maxp", "cmap", "cvt ", "fpgm", "prep", "loca", "glyf"][..] - )?; + ); + + // Check if the subsetting was successful and if it could not handle this + // font we just copy it plainly. + let subsetted = match subset_result { + Ok(font) => font, + Err(FontError::UnsupportedFont(_)) => font.clone(), + Err(err) => return Err(err.into()), + }; // Specify flags for the font. let mut flags = FontFlags::empty(); diff --git a/src/font/mod.rs b/src/font/mod.rs index 9c9289386..5d257a9a8 100644 --- a/src/font/mod.rs +++ b/src/font/mod.rs @@ -83,14 +83,15 @@ impl Font { // Create a conversion function between font units and sizes. let font_unit_ratio = 1.0 / (head.units_per_em as f32); - let font_unit_to_size = |x| Size::pt(font_unit_ratio * x as f32); + let font_unit_to_size = |x| Size::pt(font_unit_ratio * x); // Find out the name of the font. let font_name = name.get_decoded(NameEntry::PostScriptName) .unwrap_or_else(|| "unknown".to_owned()); // Convert the widths from font units to sizes. - let widths = hmtx.metrics.iter().map(|m| font_unit_to_size(m.advance_width)).collect(); + let widths = hmtx.metrics.iter() + .map(|m| font_unit_to_size(m.advance_width as f32)).collect(); // Calculate the typesetting-relevant metrics. let metrics = FontMetrics { @@ -98,14 +99,14 @@ impl Font { monospace: post.is_fixed_pitch, italic_angle: post.italic_angle.to_f32(), bounding_box: [ - font_unit_to_size(head.x_min), - font_unit_to_size(head.y_min), - font_unit_to_size(head.x_max), - font_unit_to_size(head.y_max), + font_unit_to_size(head.x_min as f32), + font_unit_to_size(head.y_min as f32), + font_unit_to_size(head.x_max as f32), + font_unit_to_size(head.y_max as f32), ], - ascender: font_unit_to_size(os2.s_typo_ascender), - descender: font_unit_to_size(os2.s_typo_descender), - cap_height: font_unit_to_size(os2.s_cap_height.unwrap_or(os2.s_typo_ascender)), + ascender: font_unit_to_size(os2.s_typo_ascender as f32), + descender: font_unit_to_size(os2.s_typo_descender as f32), + cap_height: font_unit_to_size(os2.s_cap_height.unwrap_or(os2.s_typo_ascender) as f32), weight_class: os2.us_weight_class, }; @@ -352,7 +353,6 @@ error_type! { OpentypeError::InvalidFont(message) => FontError::InvalidFont(message), OpentypeError::MissingTable(tag) => FontError::MissingTable(tag.to_string()), OpentypeError::Io(err) => FontError::Io(err), - _ => panic!("unexpected extensible variant"), }), } diff --git a/src/font/subset.rs b/src/font/subset.rs index bf3dc549b..006c00e2a 100644 --- a/src/font/subset.rs +++ b/src/font/subset.rs @@ -5,7 +5,7 @@ use std::io::{Cursor, Seek, SeekFrom}; use byteorder::{BE, ReadBytesExt, WriteBytesExt}; use opentype::{OpenTypeReader, Outlines, Table, TableRecord, Tag}; -use opentype::tables::{CharMap, Locations, HorizontalMetrics, Glyphs}; +use opentype::tables::{Header, CharMap, Locations, HorizontalMetrics, Glyphs}; use crate::size::Size; use super::{Font, FontError, FontResult}; @@ -56,8 +56,7 @@ impl<'a> Subsetter<'a> { /// Do the subsetting. fn run(mut self, tables: I) -> FontResult where I: IntoIterator, S: AsRef { - // Quit early if we cannot handle the font. - if self.outlines != Outlines::TrueType { + if self.outlines == Outlines::CFF { return Err(FontError::UnsupportedFont("CFF outlines".to_string())); } @@ -216,7 +215,7 @@ impl<'a> Subsetter<'a> { }) } - /// Subset the `hhea` table by changing the glyph count in it. + /// Subset the `hhea` table by changing the number of horizontal metrics in it. fn subset_hhea(&mut self) -> FontResult<()> { let tag = "hhea".parse().unwrap(); let hhea = self.read_table_data(tag)?; @@ -235,7 +234,7 @@ impl<'a> Subsetter<'a> { self.write_table_body(tag, |this| { for &glyph in &this.glyphs { let metrics = hmtx.get(glyph).take_invalid("missing glyph metrics")?; - this.body.write_i16::(metrics.advance_width)?; + this.body.write_u16::(metrics.advance_width)?; this.body.write_i16::(metrics.left_side_bearing)?; } Ok(()) @@ -352,8 +351,14 @@ impl<'a> Subsetter<'a> { break; } - let args_len = if flags & 0x0001 == 1 { 4 } else { 2 }; - cursor.seek(SeekFrom::Current(args_len))?; + // Skip additional arguments. + let skip = if flags & 1 != 0 { 4 } else { 2 } + + if flags & 8 != 0 { 2 } + else if flags & 64 != 0 { 4 } + else if flags & 128 != 0 { 8 } + else { 0 }; + + cursor.seek(SeekFrom::Current(skip))?; } } @@ -365,13 +370,19 @@ impl<'a> Subsetter<'a> { /// Subset the `loca` table by changing to the new offsets. fn subset_loca(&mut self) -> FontResult<()> { + let format = self.read_table::
()?.index_to_loc_format; let tag = "loca".parse().unwrap(); let loca = self.read_table::()?; self.write_table_body(tag, |this| { let mut offset = 0; for &glyph in &this.glyphs { - this.body.write_u32::(offset)?; + if format == 0 { + this.body.write_u16::((offset / 2) as u16)?; + } else { + this.body.write_u32::(offset)?; + } + let len = loca.length(glyph).take_invalid("missing loca entry")?; offset += len; } @@ -458,7 +469,7 @@ mod tests { #[test] fn subset() { - let program = std::fs::read("../fonts/NotoSans-Regular.ttf").unwrap(); + let program = std::fs::read("../fonts/SourceSansPro-Regular.ttf").unwrap(); let font = Font::new(program).unwrap(); let subsetted = font.subsetted( @@ -467,6 +478,6 @@ mod tests { "cvt ", "fpgm", "prep", "loca", "glyf"][..] ).unwrap(); - std::fs::write("../target/NotoSans-Subsetted.ttf", &subsetted.program).unwrap(); + std::fs::write("../target/SourceSansPro-Subsetted.ttf", &subsetted.program).unwrap(); } }