Skip to content

Commit

Permalink
Refactor name and post table
Browse files Browse the repository at this point in the history
  • Loading branch information
LaurenzV committed Mar 3, 2024
1 parent 58ba19a commit b9a8f68
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 163 deletions.
130 changes: 0 additions & 130 deletions src/name.rs

This file was deleted.

29 changes: 29 additions & 0 deletions src/name/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
mod read;
mod write;

use super::*;
use crate::name::read::Version0Table;
use crate::Error::{MalformedFont, SubsetError};

pub(crate) fn subset(ctx: &mut Context) -> Result<()> {
let name = ctx.expect_table(Tag::NAME).ok_or(MalformedFont)?;
let mut r = Reader::new(name);

let version = r.read::<u16>().ok_or(MalformedFont)?;

// From my personal experiments, version 0 is isn't used at all, so we
// don't bother subsetting it.
if version != 0 {
ctx.push(Tag::NAME, name);
return Ok(());
}

let table = Version0Table::parse(name).ok_or(MalformedFont)?;
let subsetted_table = write::subset(&table).ok_or(SubsetError)?;

let mut w = Writer::new();
w.write(subsetted_table);

ctx.push(Tag::NAME, w.finish());
Ok(())
}
72 changes: 72 additions & 0 deletions src/name/read.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use crate::stream::{Readable, Reader};
use std::borrow::Cow;

#[derive(Clone, Debug)]
pub struct Version0Table<'a> {
pub names: Vec<NameRecord>,
pub storage: Cow<'a, [u8]>,
}

impl<'a> Version0Table<'a> {
pub fn parse(data: &'a [u8]) -> Option<Self> {
let mut r = Reader::new(data);

let version = r.read::<u16>()?;

if version != 0 {
return None;
}

let count = r.read::<u16>()?;
r.read::<u16>()?; // storage offset

let mut names = Vec::with_capacity(count as usize);

for _ in 0..count {
names.push(r.read::<NameRecord>()?);
}

let storage = Cow::Borrowed(r.tail()?);

Some(Self { names, storage })
}
}

impl Readable<'_> for NameRecord {
const SIZE: usize = u16::SIZE * 6;

fn read(r: &mut Reader<'_>) -> Option<Self> {
let platform_id = r.read::<u16>()?;
let encoding_id = r.read::<u16>()?;
let language_id = r.read::<u16>()?;
let name_id = r.read::<u16>()?;
let length = r.read::<u16>()?;
let string_offset = r.read::<u16>()?;

Some(Self {
platform_id,
encoding_id,
language_id,
name_id,
length,
string_offset,
})
}
}

#[derive(Clone, Copy, Debug)]
pub struct NameRecord {
pub platform_id: u16,
pub encoding_id: u16,
pub language_id: u16,
pub name_id: u16,
pub length: u16,
pub string_offset: u16,
}

impl NameRecord {
pub fn is_unicode(&self) -> bool {
self.platform_id == 0
|| (self.platform_id == 3 && [0, 1, 10].contains(&self.encoding_id))
}
}
57 changes: 57 additions & 0 deletions src/name/write.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use crate::name::read::NameRecord;
use crate::name::read::Version0Table;
use crate::stream::{Readable, Writeable, Writer};
use std::borrow::Cow;

type SubsettedVersion0Table<'a> = Version0Table<'a>;

pub fn subset<'a>(table: &Version0Table<'a>) -> Option<SubsettedVersion0Table<'a>> {
let mut names = table
.names
.iter()
.copied()
.filter(|record| {
record.is_unicode() && [0, 1, 2, 3, 4, 5, 6].contains(&record.name_id)
})
.collect::<Vec<_>>();

let mut storage = Vec::new();
let mut cur_storage_offset = 0;

for record in &mut names {
storage.extend(
&table.storage[(record.string_offset as usize)
..((record.string_offset + record.length) as usize)],
);
record.string_offset = cur_storage_offset;
cur_storage_offset += record.length;
}

Some(SubsettedVersion0Table { names, storage: Cow::Owned(storage) })
}

impl Writeable for SubsettedVersion0Table<'_> {
fn write(&self, w: &mut Writer) {
let count = u16::try_from(self.names.len()).unwrap();

// version
w.write::<u16>(0);
// count
w.write::<u16>(count);
// storage offset
w.write::<u16>(u16::SIZE as u16 * 3 + count * NameRecord::SIZE as u16);
w.write_vector::<NameRecord>(&self.names);
w.extend(&self.storage);
}
}

impl Writeable for NameRecord {
fn write(&self, w: &mut Writer) {
w.write::<u16>(self.platform_id);
w.write::<u16>(self.encoding_id);
w.write::<u16>(self.language_id);
w.write::<u16>(self.name_id);
w.write::<u16>(self.length);
w.write::<u16>(self.string_offset);
}
}
1 change: 0 additions & 1 deletion src/post/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use super::*;
use crate::post::read::Version2Table;
use crate::Error::{MalformedFont, SubsetError};

/// Subset the glyf and loca tables by removing glyph data for unused glyphs.
pub(crate) fn subset(ctx: &mut Context) -> Result<()> {
let post = ctx.expect_table(Tag::POST).ok_or(MalformedFont)?;
let mut r = Reader::new(post);
Expand Down
7 changes: 3 additions & 4 deletions src/post/read.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::stream::Reader;
use crate::util::LazyArray16;

/// An iterator over glyph names.
///
Expand Down Expand Up @@ -42,10 +41,10 @@ impl<'a> Iterator for Names<'a> {
}
}

#[derive(Clone, Copy, Debug)]
#[derive(Clone, Debug)]
pub struct Version2Table<'a> {
pub header: &'a [u8],
pub glyph_indexes: LazyArray16<'a, u16>,
pub glyph_indexes: Vec<u16>,
pub names_data: &'a [u8],
}

Expand All @@ -62,7 +61,7 @@ impl<'a> Version2Table<'a> {
let header = r.read_bytes(32)?;

let indexes_count = r.read::<u16>()?;
let glyph_indexes = r.read_array16::<u16>(indexes_count)?;
let glyph_indexes = r.read_vector::<u16>(indexes_count as usize)?;
let names_data = r.tail()?;

Some(Version2Table { header, glyph_indexes, names_data })
Expand Down
4 changes: 2 additions & 2 deletions src/post/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub struct SubsettedVersion2Table<'a> {
}

pub fn subset<'a>(
ctx: &mut Context,
ctx: &Context,
table: &Version2Table<'a>,
) -> Option<SubsettedVersion2Table<'a>> {
let old_names = table.names().collect::<Vec<_>>();
Expand All @@ -23,7 +23,7 @@ pub fn subset<'a>(
let mut count = 0;
for i in 0..num_glyphs {
let old_gid = ctx.mapper.get_reverse(i).unwrap();
let index = table.glyph_indexes.get(old_gid)?;
let index = *table.glyph_indexes.get(old_gid as usize)?;

if index <= 257 {
glyph_indexes.push(index);
Expand Down
Loading

0 comments on commit b9a8f68

Please sign in to comment.