Skip to content

Commit

Permalink
RawFace fields and TableRecord struct are public now.
Browse files Browse the repository at this point in the history
Closes #103
  • Loading branch information
RazrFalcon committed Sep 18, 2022
1 parent 5f6b89e commit ca8a291
Show file tree
Hide file tree
Showing 11 changed files with 98 additions and 51 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- `post::Table::glyph_index_by_name`
- `post::Table::names`
- `Face::glyph_index_by_name`
- `RawFace` fields and `TableRecord` struct are public now.

### Changed
- `Face::from_slice` was replaced by `Face::parse`.
- `RawFace::from_slice` was replaced by `RawFace::parse`.
- `post::Table::names` is a method and not a field now.
- Use `post::Table::glyph_name` instead of `post::Table::names.get()`.

Expand Down
30 changes: 15 additions & 15 deletions benches/methods_perf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,35 @@ use ttf_parser as ttf;
fn from_data_ttf(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansPro-Regular.ttf").unwrap();
bencher.iter(|| {
bencher::black_box(ttf::Face::from_slice(&font_data, 0).unwrap());
bencher::black_box(ttf::Face::parse(&font_data, 0).unwrap());
})
}

fn from_data_otf_cff(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansPro-Regular.otf").unwrap();
bencher.iter(|| {
bencher::black_box(ttf::Face::from_slice(&font_data, 0).unwrap());
bencher::black_box(ttf::Face::parse(&font_data, 0).unwrap());
})
}

fn from_data_otf_cff2(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansVariable-Roman.otf").unwrap();
bencher.iter(|| {
bencher::black_box(ttf::Face::from_slice(&font_data, 0).unwrap());
bencher::black_box(ttf::Face::parse(&font_data, 0).unwrap());
})
}

fn outline_glyph_8_from_glyf(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansPro-Regular.ttf").unwrap();
let face = ttf::Face::from_slice(&font_data, 0).unwrap();
let face = ttf::Face::parse(&font_data, 0).unwrap();
bencher.iter(|| {
face.outline_glyph(ttf::GlyphId(8), &mut Builder(0))
})
}

fn outline_glyph_276_from_glyf(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansPro-Regular.ttf").unwrap();
let face = ttf::Face::from_slice(&font_data, 0).unwrap();
let face = ttf::Face::parse(&font_data, 0).unwrap();
let mut b = Builder(0);
bencher.iter(|| {
face.outline_glyph(ttf::GlyphId(276), &mut b)
Expand All @@ -40,39 +40,39 @@ fn outline_glyph_276_from_glyf(bencher: &mut bencher::Bencher) {

fn outline_glyph_8_from_cff(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansPro-Regular.otf").unwrap();
let face = ttf::Face::from_slice(&font_data, 0).unwrap();
let face = ttf::Face::parse(&font_data, 0).unwrap();
bencher.iter(|| {
face.outline_glyph(ttf::GlyphId(8), &mut Builder(0))
})
}

fn outline_glyph_276_from_cff(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansPro-Regular.otf").unwrap();
let face = ttf::Face::from_slice(&font_data, 0).unwrap();
let face = ttf::Face::parse(&font_data, 0).unwrap();
bencher.iter(|| {
face.outline_glyph(ttf::GlyphId(276), &mut Builder(0))
})
}

fn outline_glyph_8_from_cff2(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansVariable-Roman.otf").unwrap();
let face = ttf::Face::from_slice(&font_data, 0).unwrap();
let face = ttf::Face::parse(&font_data, 0).unwrap();
bencher.iter(|| {
face.outline_glyph(ttf::GlyphId(8), &mut Builder(0))
})
}

fn outline_glyph_276_from_cff2(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansVariable-Roman.otf").unwrap();
let face = ttf::Face::from_slice(&font_data, 0).unwrap();
let face = ttf::Face::parse(&font_data, 0).unwrap();
bencher.iter(|| {
face.outline_glyph(ttf::GlyphId(276), &mut Builder(0))
})
}

fn family_name(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansPro-Regular.ttf").unwrap();
let face = ttf::Face::from_slice(&font_data, 0).unwrap();
let face = ttf::Face::parse(&font_data, 0).unwrap();
bencher.iter(|| {
bencher::black_box(
face.names().into_iter().find(|name| name.name_id == ttf::name_id::FULL_NAME)
Expand All @@ -83,7 +83,7 @@ fn family_name(bencher: &mut bencher::Bencher) {

fn glyph_name_post_8(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansPro-Regular.ttf").unwrap();
let face = ttf::Face::from_slice(&font_data, 0).unwrap();
let face = ttf::Face::parse(&font_data, 0).unwrap();
assert_eq!(face.glyph_name(ttf::GlyphId(8)).unwrap(), "G");
bencher.iter(|| {
bencher::black_box(face.glyph_name(ttf::GlyphId(8)).unwrap());
Expand All @@ -92,7 +92,7 @@ fn glyph_name_post_8(bencher: &mut bencher::Bencher) {

fn glyph_name_post_276(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansPro-Regular.ttf").unwrap();
let face = ttf::Face::from_slice(&font_data, 0).unwrap();
let face = ttf::Face::parse(&font_data, 0).unwrap();
assert_eq!(face.glyph_name(ttf::GlyphId(276)).unwrap(), "uni1EAB");
bencher.iter(|| {
bencher::black_box(face.glyph_name(ttf::GlyphId(276)).unwrap());
Expand All @@ -101,7 +101,7 @@ fn glyph_name_post_276(bencher: &mut bencher::Bencher) {

fn glyph_name_cff_8(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansPro-Regular.otf").unwrap();
let face = ttf::Face::from_slice(&font_data, 0).unwrap();
let face = ttf::Face::parse(&font_data, 0).unwrap();
assert_eq!(face.glyph_name(ttf::GlyphId(8)).unwrap(), "G");
bencher.iter(|| {
bencher::black_box(face.glyph_name(ttf::GlyphId(8)).unwrap());
Expand All @@ -110,7 +110,7 @@ fn glyph_name_cff_8(bencher: &mut bencher::Bencher) {

fn glyph_name_cff_276(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansPro-Regular.otf").unwrap();
let face = ttf::Face::from_slice(&font_data, 0).unwrap();
let face = ttf::Face::parse(&font_data, 0).unwrap();
assert_eq!(face.glyph_name(ttf::GlyphId(276)).unwrap(), "uni1EAB");
bencher.iter(|| {
bencher::black_box(face.glyph_name(ttf::GlyphId(276)).unwrap());
Expand All @@ -119,7 +119,7 @@ fn glyph_name_cff_276(bencher: &mut bencher::Bencher) {

fn glyph_index_u41(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansPro-Regular.ttf").unwrap();
let face = ttf::Face::from_slice(&font_data, 0).unwrap();
let face = ttf::Face::parse(&font_data, 0).unwrap();
bencher.iter(|| {
bencher::black_box(face.glyph_index('A').unwrap());
})
Expand Down
18 changes: 9 additions & 9 deletions benches/methods_perf_x1000.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use ttf_parser as ttf;

fn units_per_em(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansPro-Regular.ttf").unwrap();
let face = ttf::Face::from_slice(&font_data, 0).unwrap();
let face = ttf::Face::parse(&font_data, 0).unwrap();
bencher.iter(|| {
for _ in 0..1000 {
bencher::black_box(face.units_per_em());
Expand All @@ -12,7 +12,7 @@ fn units_per_em(bencher: &mut bencher::Bencher) {

fn width(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansPro-Regular.ttf").unwrap();
let face = ttf::Face::from_slice(&font_data, 0).unwrap();
let face = ttf::Face::parse(&font_data, 0).unwrap();
bencher.iter(|| {
for _ in 0..1000 {
bencher::black_box(face.width());
Expand All @@ -22,7 +22,7 @@ fn width(bencher: &mut bencher::Bencher) {

fn ascender(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansPro-Regular.ttf").unwrap();
let face = ttf::Face::from_slice(&font_data, 0).unwrap();
let face = ttf::Face::parse(&font_data, 0).unwrap();
bencher.iter(|| {
for _ in 0..1000 {
bencher::black_box(face.ascender());
Expand All @@ -32,7 +32,7 @@ fn ascender(bencher: &mut bencher::Bencher) {

fn underline_metrics(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansPro-Regular.ttf").unwrap();
let face = ttf::Face::from_slice(&font_data, 0).unwrap();
let face = ttf::Face::parse(&font_data, 0).unwrap();
bencher.iter(|| {
for _ in 0..1000 {
bencher::black_box(face.underline_metrics().unwrap());
Expand All @@ -42,7 +42,7 @@ fn underline_metrics(bencher: &mut bencher::Bencher) {

fn strikeout_metrics(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansPro-Regular.ttf").unwrap();
let face = ttf::Face::from_slice(&font_data, 0).unwrap();
let face = ttf::Face::parse(&font_data, 0).unwrap();
bencher.iter(|| {
for _ in 0..1000 {
bencher::black_box(face.strikeout_metrics().unwrap());
Expand All @@ -52,7 +52,7 @@ fn strikeout_metrics(bencher: &mut bencher::Bencher) {

fn subscript_metrics(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansPro-Regular.ttf").unwrap();
let face = ttf::Face::from_slice(&font_data, 0).unwrap();
let face = ttf::Face::parse(&font_data, 0).unwrap();
bencher.iter(|| {
for _ in 0..1000 {
bencher::black_box(face.subscript_metrics().unwrap());
Expand All @@ -62,7 +62,7 @@ fn subscript_metrics(bencher: &mut bencher::Bencher) {

fn x_height(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansPro-Regular.ttf").unwrap();
let face = ttf::Face::from_slice(&font_data, 0).unwrap();
let face = ttf::Face::parse(&font_data, 0).unwrap();
bencher.iter(|| {
for _ in 0..1000 {
bencher::black_box(face.x_height().unwrap());
Expand All @@ -72,7 +72,7 @@ fn x_height(bencher: &mut bencher::Bencher) {

fn glyph_hor_advance(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansPro-Regular.ttf").unwrap();
let face = ttf::Face::from_slice(&font_data, 0).unwrap();
let face = ttf::Face::parse(&font_data, 0).unwrap();
bencher.iter(|| {
for _ in 0..1000 {
bencher::black_box(face.glyph_hor_advance(ttf::GlyphId(2)).unwrap());
Expand All @@ -82,7 +82,7 @@ fn glyph_hor_advance(bencher: &mut bencher::Bencher) {

fn glyph_hor_side_bearing(bencher: &mut bencher::Bencher) {
let font_data = std::fs::read("fonts/SourceSansPro-Regular.ttf").unwrap();
let face = ttf::Face::from_slice(&font_data, 0).unwrap();
let face = ttf::Face::parse(&font_data, 0).unwrap();
bencher.iter(|| {
for _ in 0..1000 {
bencher::black_box(face.glyph_hor_side_bearing(ttf::GlyphId(2)).unwrap());
Expand Down
2 changes: 1 addition & 1 deletion examples/font-info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ fn main() {

let now = std::time::Instant::now();

let face = match ttf_parser::Face::from_slice(&font_data, 0) {
let face = match ttf_parser::Face::parse(&font_data, 0) {
Ok(f) => f,
Err(e) => {
eprint!("Error: {}.", e);
Expand Down
2 changes: 1 addition & 1 deletion examples/font2svg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ fn process(args: Args) -> Result<(), Box<dyn std::error::Error>> {
let now = std::time::Instant::now();

#[allow(unused_mut)]
let mut face = ttf::Face::from_slice(&font_data, 0)?;
let mut face = ttf::Face::parse(&font_data, 0)?;
if face.is_variable() {
#[cfg(feature = "variable-fonts")] {
for variation in args.variations {
Expand Down
74 changes: 59 additions & 15 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,13 +458,15 @@ pub struct RasterGlyphImage<'a> {
}


#[derive(Clone, Copy)]
struct TableRecord {
table_tag: Tag,
/// A raw table record.
#[derive(Clone, Copy, Debug)]
#[allow(missing_docs)]
pub struct TableRecord {
pub tag: Tag,
#[allow(dead_code)]
check_sum: u32,
offset: u32,
length: u32,
pub check_sum: u32,
pub offset: u32,
pub length: u32,
}

impl FromData for TableRecord {
Expand All @@ -474,7 +476,7 @@ impl FromData for TableRecord {
fn parse(data: &[u8]) -> Option<Self> {
let mut s = Stream::new(data);
Some(TableRecord {
table_tag: s.read::<Tag>()?,
tag: s.read::<Tag>()?,
check_sum: s.read::<u32>()?,
offset: s.read::<u32>()?,
length: s.read::<u32>()?,
Expand Down Expand Up @@ -559,8 +561,10 @@ impl std::error::Error for FaceParsingError {}
/// manually before passing it to [`Face::from_raw_tables`].
#[derive(Clone, Copy)]
pub struct RawFace<'a> {
data: &'a [u8],
table_records: LazyArray16<'a, TableRecord>,
/// The input font file data.
pub data: &'a [u8],
/// An array of table records.
pub table_records: LazyArray16<'a, TableRecord>,
}

impl<'a> RawFace<'a> {
Expand All @@ -571,7 +575,19 @@ impl<'a> RawFace<'a> {
/// Set to 0 if unsure.
///
/// While we do reuse [`FaceParsingError`], `No*Table` errors will not be throws.
#[deprecated(since="0.16.0", note="use `parse` instead")]
pub fn from_slice(data: &'a [u8], index: u32) -> Result<Self, FaceParsingError> {
Self::parse(data, index)
}

/// Creates a new [`RawFace`] from a raw data.
///
/// `index` indicates the specific font face in a font collection.
/// Use [`fonts_in_collection`] to get the total number of font faces.
/// Set to 0 if unsure.
///
/// While we do reuse [`FaceParsingError`], `No*Table` errors will not be throws.
pub fn parse(data: &'a [u8], index: u32) -> Result<Self, FaceParsingError> {
// https://docs.microsoft.com/en-us/typography/opentype/spec/otff#organization-of-an-opentype-font

let mut s = Stream::new(data);
Expand Down Expand Up @@ -613,7 +629,7 @@ impl<'a> RawFace<'a> {

/// Returns the raw data of a selected table.
pub fn table(&self, tag: Tag) -> Option<&'a [u8]> {
let (_, table) = self.table_records.binary_search_by(|record| record.table_tag.cmp(&tag))?;
let (_, table) = self.table_records.binary_search_by(|record| record.tag.cmp(&tag))?;
let offset = usize::num_from(table.offset);
let length = usize::num_from(table.length);
let end = offset.checked_add(length)?;
Expand Down Expand Up @@ -765,8 +781,25 @@ impl<'a> Face<'a> {
/// Required tables: `head`, `hhea` and `maxp`.
///
/// If an optional table has invalid data it will be skipped.
#[deprecated(since="0.16.0", note="use `parse` instead")]
pub fn from_slice(data: &'a [u8], index: u32) -> Result<Self, FaceParsingError> {
let raw_face = RawFace::from_slice(data, index)?;
Self::parse(data, index)
}

/// Creates a new [`Face`] from a raw data.
///
/// `index` indicates the specific font face in a font collection.
/// Use [`fonts_in_collection`] to get the total number of font faces.
/// Set to 0 if unsure.
///
/// This method will do some parsing and sanitization,
/// but in general can be considered free. No significant performance overhead.
///
/// Required tables: `head`, `hhea` and `maxp`.
///
/// If an optional table has invalid data it will be skipped.
pub fn parse(data: &'a [u8], index: u32) -> Result<Self, FaceParsingError> {
let raw_face = RawFace::parse(data, index)?;
let raw_tables = Self::collect_tables(raw_face);

#[allow(unused_mut)]
Expand Down Expand Up @@ -796,7 +829,7 @@ impl<'a> Face<'a> {
};

let table_data = raw_face.data.get(start..end);
match &record.table_tag.to_bytes() {
match &record.tag.to_bytes() {
b"CBDT" => tables.cbdt = table_data,
b"CBLC" => tables.cblc = table_data,
b"CFF " => tables.cff = table_data,
Expand Down Expand Up @@ -956,11 +989,22 @@ impl<'a> Face<'a> {
&self.tables
}

/// Returns the `RawFace` used to create this `Face`.
///
/// Useful if you want to parse the data manually.
///
/// Available only for faces created using [`Face::parse()`](struct.Face.html#method.parse).
#[inline]
pub fn raw_face(&self) -> &RawFace<'a> {
&self.raw_face
}

/// Returns the raw data of a selected table.
///
/// Useful if you want to parse the data manually.
///
/// Available only for faces created using [`Face::from_slice()`](struct.Face.html#method.from_slice).
/// Available only for faces created using [`Face::parse()`](struct.Face.html#method.parse).
#[deprecated(since="0.16.0", note="use `self.raw_face().table()` instead")]
#[inline]
pub fn table_data(&self, tag: Tag) -> Option<&'a [u8]> {
self.raw_face.table(tag)
Expand Down Expand Up @@ -1585,7 +1629,7 @@ impl<'a> Face<'a> {
/// }
///
/// let data = std::fs::read("tests/fonts/demo.ttf").unwrap();
/// let face = ttf_parser::Face::from_slice(&data, 0).unwrap();
/// let face = ttf_parser::Face::parse(&data, 0).unwrap();
/// let mut builder = Builder(String::new());
/// let bbox = face.outline_glyph(ttf_parser::GlyphId(1), &mut builder).unwrap();
/// assert_eq!(builder.0, "M 173 267 L 369 267 L 270 587 L 173 267 Z M 6 0 L 224 656 \
Expand Down Expand Up @@ -1804,7 +1848,7 @@ impl<'a> Iterator for DefaultTableProvider<'a> {
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.tables.next().map(|table| {
Ok((table.table_tag, {
Ok((table.tag, {
let offset = usize::num_from(table.offset);
let length = usize::num_from(table.length);
let end = offset.checked_add(length).ok_or(FaceParsingError::MalformedFont)?;
Expand Down
Loading

0 comments on commit ca8a291

Please sign in to comment.