mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Add more tests for table parsers 🔋
This commit is contained in:
parent
030d301f0c
commit
7eec0b8dd7
@ -270,10 +270,18 @@ impl PdfFont {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Subset the font using the selected characters.
|
// Subset the font using the selected characters.
|
||||||
let subsetted = font.subsetted(
|
let subset_result = font.subsetted(
|
||||||
chars.iter().cloned(),
|
chars.iter().cloned(),
|
||||||
&["head", "hhea", "hmtx", "maxp", "cmap", "cvt ", "fpgm", "prep", "loca", "glyf"][..]
|
&["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.
|
// Specify flags for the font.
|
||||||
let mut flags = FontFlags::empty();
|
let mut flags = FontFlags::empty();
|
||||||
|
@ -83,14 +83,15 @@ impl Font {
|
|||||||
|
|
||||||
// Create a conversion function between font units and sizes.
|
// Create a conversion function between font units and sizes.
|
||||||
let font_unit_ratio = 1.0 / (head.units_per_em as f32);
|
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.
|
// Find out the name of the font.
|
||||||
let font_name = name.get_decoded(NameEntry::PostScriptName)
|
let font_name = name.get_decoded(NameEntry::PostScriptName)
|
||||||
.unwrap_or_else(|| "unknown".to_owned());
|
.unwrap_or_else(|| "unknown".to_owned());
|
||||||
|
|
||||||
// Convert the widths from font units to sizes.
|
// 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.
|
// Calculate the typesetting-relevant metrics.
|
||||||
let metrics = FontMetrics {
|
let metrics = FontMetrics {
|
||||||
@ -98,14 +99,14 @@ impl Font {
|
|||||||
monospace: post.is_fixed_pitch,
|
monospace: post.is_fixed_pitch,
|
||||||
italic_angle: post.italic_angle.to_f32(),
|
italic_angle: post.italic_angle.to_f32(),
|
||||||
bounding_box: [
|
bounding_box: [
|
||||||
font_unit_to_size(head.x_min),
|
font_unit_to_size(head.x_min as f32),
|
||||||
font_unit_to_size(head.y_min),
|
font_unit_to_size(head.y_min as f32),
|
||||||
font_unit_to_size(head.x_max),
|
font_unit_to_size(head.x_max as f32),
|
||||||
font_unit_to_size(head.y_max),
|
font_unit_to_size(head.y_max as f32),
|
||||||
],
|
],
|
||||||
ascender: font_unit_to_size(os2.s_typo_ascender),
|
ascender: font_unit_to_size(os2.s_typo_ascender as f32),
|
||||||
descender: font_unit_to_size(os2.s_typo_descender),
|
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)),
|
cap_height: font_unit_to_size(os2.s_cap_height.unwrap_or(os2.s_typo_ascender) as f32),
|
||||||
weight_class: os2.us_weight_class,
|
weight_class: os2.us_weight_class,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -352,7 +353,6 @@ error_type! {
|
|||||||
OpentypeError::InvalidFont(message) => FontError::InvalidFont(message),
|
OpentypeError::InvalidFont(message) => FontError::InvalidFont(message),
|
||||||
OpentypeError::MissingTable(tag) => FontError::MissingTable(tag.to_string()),
|
OpentypeError::MissingTable(tag) => FontError::MissingTable(tag.to_string()),
|
||||||
OpentypeError::Io(err) => FontError::Io(err),
|
OpentypeError::Io(err) => FontError::Io(err),
|
||||||
_ => panic!("unexpected extensible variant"),
|
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ use std::io::{Cursor, Seek, SeekFrom};
|
|||||||
|
|
||||||
use byteorder::{BE, ReadBytesExt, WriteBytesExt};
|
use byteorder::{BE, ReadBytesExt, WriteBytesExt};
|
||||||
use opentype::{OpenTypeReader, Outlines, Table, TableRecord, Tag};
|
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 crate::size::Size;
|
||||||
use super::{Font, FontError, FontResult};
|
use super::{Font, FontError, FontResult};
|
||||||
@ -56,8 +56,7 @@ impl<'a> Subsetter<'a> {
|
|||||||
/// Do the subsetting.
|
/// Do the subsetting.
|
||||||
fn run<I, S>(mut self, tables: I) -> FontResult<Font>
|
fn run<I, S>(mut self, tables: I) -> FontResult<Font>
|
||||||
where I: IntoIterator<Item=S>, S: AsRef<str> {
|
where I: IntoIterator<Item=S>, S: AsRef<str> {
|
||||||
// Quit early if we cannot handle the font.
|
if self.outlines == Outlines::CFF {
|
||||||
if self.outlines != Outlines::TrueType {
|
|
||||||
return Err(FontError::UnsupportedFont("CFF outlines".to_string()));
|
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<()> {
|
fn subset_hhea(&mut self) -> FontResult<()> {
|
||||||
let tag = "hhea".parse().unwrap();
|
let tag = "hhea".parse().unwrap();
|
||||||
let hhea = self.read_table_data(tag)?;
|
let hhea = self.read_table_data(tag)?;
|
||||||
@ -235,7 +234,7 @@ impl<'a> Subsetter<'a> {
|
|||||||
self.write_table_body(tag, |this| {
|
self.write_table_body(tag, |this| {
|
||||||
for &glyph in &this.glyphs {
|
for &glyph in &this.glyphs {
|
||||||
let metrics = hmtx.get(glyph).take_invalid("missing glyph metrics")?;
|
let metrics = hmtx.get(glyph).take_invalid("missing glyph metrics")?;
|
||||||
this.body.write_i16::<BE>(metrics.advance_width)?;
|
this.body.write_u16::<BE>(metrics.advance_width)?;
|
||||||
this.body.write_i16::<BE>(metrics.left_side_bearing)?;
|
this.body.write_i16::<BE>(metrics.left_side_bearing)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -352,8 +351,14 @@ impl<'a> Subsetter<'a> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let args_len = if flags & 0x0001 == 1 { 4 } else { 2 };
|
// Skip additional arguments.
|
||||||
cursor.seek(SeekFrom::Current(args_len))?;
|
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.
|
/// Subset the `loca` table by changing to the new offsets.
|
||||||
fn subset_loca(&mut self) -> FontResult<()> {
|
fn subset_loca(&mut self) -> FontResult<()> {
|
||||||
|
let format = self.read_table::<Header>()?.index_to_loc_format;
|
||||||
let tag = "loca".parse().unwrap();
|
let tag = "loca".parse().unwrap();
|
||||||
let loca = self.read_table::<Locations>()?;
|
let loca = self.read_table::<Locations>()?;
|
||||||
|
|
||||||
self.write_table_body(tag, |this| {
|
self.write_table_body(tag, |this| {
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
for &glyph in &this.glyphs {
|
for &glyph in &this.glyphs {
|
||||||
this.body.write_u32::<BE>(offset)?;
|
if format == 0 {
|
||||||
|
this.body.write_u16::<BE>((offset / 2) as u16)?;
|
||||||
|
} else {
|
||||||
|
this.body.write_u32::<BE>(offset)?;
|
||||||
|
}
|
||||||
|
|
||||||
let len = loca.length(glyph).take_invalid("missing loca entry")?;
|
let len = loca.length(glyph).take_invalid("missing loca entry")?;
|
||||||
offset += len;
|
offset += len;
|
||||||
}
|
}
|
||||||
@ -458,7 +469,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn subset() {
|
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 font = Font::new(program).unwrap();
|
||||||
|
|
||||||
let subsetted = font.subsetted(
|
let subsetted = font.subsetted(
|
||||||
@ -467,6 +478,6 @@ mod tests {
|
|||||||
"cvt ", "fpgm", "prep", "loca", "glyf"][..]
|
"cvt ", "fpgm", "prep", "loca", "glyf"][..]
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
std::fs::write("../target/NotoSans-Subsetted.ttf", &subsetted.program).unwrap();
|
std::fs::write("../target/SourceSansPro-Subsetted.ttf", &subsetted.program).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user