Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[read-fonts] initial codegen for parsing sbix table #609

Merged
merged 2 commits into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
335 changes: 335 additions & 0 deletions read-fonts/generated/generated_sbix.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,335 @@
// THIS FILE IS AUTOGENERATED.
// Any changes to this file will be overwritten.
// For more information about how codegen works, see font-codegen/README.md

#[allow(unused_imports)]
use crate::codegen_prelude::*;

/// The [sbix (Standard Bitmap Graphics)](https://docs.microsoft.com/en-us/typography/opentype/spec/sbix) table
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct SbixMarker {
num_glyphs: u16,
strike_offsets_byte_len: usize,
}

impl SbixMarker {
fn version_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
fn flags_byte_range(&self) -> Range<usize> {
let start = self.version_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
fn num_strikes_byte_range(&self) -> Range<usize> {
let start = self.flags_byte_range().end;
start..start + u32::RAW_BYTE_LEN
}
fn strike_offsets_byte_range(&self) -> Range<usize> {
let start = self.num_strikes_byte_range().end;
start..start + self.strike_offsets_byte_len
}
}

impl TopLevelTable for Sbix<'_> {
/// `sbix`
const TAG: Tag = Tag::new(b"sbix");
}

impl ReadArgs for Sbix<'_> {
type Args = u16;
}

impl<'a> FontReadWithArgs<'a> for Sbix<'a> {
fn read_with_args(data: FontData<'a>, args: &u16) -> Result<Self, ReadError> {
let num_glyphs = *args;
let mut cursor = data.cursor();
cursor.advance::<u16>();
cursor.advance::<u16>();
let num_strikes: u32 = cursor.read()?;
let strike_offsets_byte_len = num_strikes as usize * Offset32::RAW_BYTE_LEN;
cursor.advance_by(strike_offsets_byte_len);
cursor.finish(SbixMarker {
num_glyphs,
strike_offsets_byte_len,
})
}
}

impl<'a> Sbix<'a> {
/// A constructor that requires additional arguments.
///
/// This type requires some external state in order to be
/// parsed.
pub fn read(data: FontData<'a>, num_glyphs: u16) -> Result<Self, ReadError> {
let args = num_glyphs;
Self::read_with_args(data, &args)
}
}

/// The [sbix (Standard Bitmap Graphics)](https://docs.microsoft.com/en-us/typography/opentype/spec/sbix) table
pub type Sbix<'a> = TableRef<'a, SbixMarker>;

impl<'a> Sbix<'a> {
/// Table version number — set to 1.
pub fn version(&self) -> u16 {
let range = self.shape.version_byte_range();
self.data.read_at(range.start).unwrap()
}

/// Bit 0: Set to 1.
/// Bit 1: Draw outlines.
/// Bits 2 to 15: reserved (set to 0).
pub fn flags(&self) -> u16 {
let range = self.shape.flags_byte_range();
self.data.read_at(range.start).unwrap()
}

/// Number of bitmap strikes.
pub fn num_strikes(&self) -> u32 {
let range = self.shape.num_strikes_byte_range();
self.data.read_at(range.start).unwrap()
}

/// Offsets from the beginning of the 'sbix' table to data for each individual bitmap strike.
pub fn strike_offsets(&self) -> &'a [BigEndian<Offset32>] {
let range = self.shape.strike_offsets_byte_range();
self.data.read_array(range).unwrap()
}

/// A dynamically resolving wrapper for [`strike_offsets`][Self::strike_offsets].
pub fn strikes(&self) -> ArrayOfOffsets<'a, Strike<'a>, Offset32> {
let data = self.data;
let offsets = self.strike_offsets();
let args = self.num_glyphs();
ArrayOfOffsets::new(offsets, data, args)
}

pub(crate) fn num_glyphs(&self) -> u16 {
self.shape.num_glyphs
}
}

#[cfg(feature = "traversal")]
impl<'a> SomeTable<'a> for Sbix<'a> {
fn type_name(&self) -> &str {
"Sbix"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("version", self.version())),
1usize => Some(Field::new("flags", self.flags())),
2usize => Some(Field::new("num_strikes", self.num_strikes())),
3usize => Some({
let data = self.data;
let args = self.num_glyphs();
Field::new(
"strike_offsets",
FieldType::array_of_offsets(
better_type_name::<Strike>(),
self.strike_offsets(),
move |off| {
let target = off.get().resolve_with_args::<Strike>(data, &args);
FieldType::offset(off.get(), target)
},
),
)
}),
_ => None,
}
}
}

#[cfg(feature = "traversal")]
impl<'a> std::fmt::Debug for Sbix<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}

/// [Strike](https://learn.microsoft.com/en-us/typography/opentype/spec/sbix#strikes) header table
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct StrikeMarker {
glyph_data_offsets_byte_len: usize,
}

impl StrikeMarker {
fn ppem_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + u16::RAW_BYTE_LEN
}
fn ppi_byte_range(&self) -> Range<usize> {
let start = self.ppem_byte_range().end;
start..start + u16::RAW_BYTE_LEN
}
fn glyph_data_offsets_byte_range(&self) -> Range<usize> {
let start = self.ppi_byte_range().end;
start..start + self.glyph_data_offsets_byte_len
}
}

impl ReadArgs for Strike<'_> {
type Args = u16;
}

impl<'a> FontReadWithArgs<'a> for Strike<'a> {
fn read_with_args(data: FontData<'a>, args: &u16) -> Result<Self, ReadError> {
let num_glyphs = *args;
let mut cursor = data.cursor();
cursor.advance::<u16>();
cursor.advance::<u16>();
let glyph_data_offsets_byte_len = transforms::add(num_glyphs, 1_usize) * u32::RAW_BYTE_LEN;
cursor.advance_by(glyph_data_offsets_byte_len);
cursor.finish(StrikeMarker {
glyph_data_offsets_byte_len,
})
}
}

impl<'a> Strike<'a> {
/// A constructor that requires additional arguments.
///
/// This type requires some external state in order to be
/// parsed.
pub fn read(data: FontData<'a>, num_glyphs: u16) -> Result<Self, ReadError> {
let args = num_glyphs;
Self::read_with_args(data, &args)
}
}

/// [Strike](https://learn.microsoft.com/en-us/typography/opentype/spec/sbix#strikes) header table
pub type Strike<'a> = TableRef<'a, StrikeMarker>;

impl<'a> Strike<'a> {
/// The PPEM size for which this strike was designed.
pub fn ppem(&self) -> u16 {
let range = self.shape.ppem_byte_range();
self.data.read_at(range.start).unwrap()
}

/// The device pixel density (in PPI) for which this strike was designed. (E.g., 96 PPI, 192 PPI.)
pub fn ppi(&self) -> u16 {
let range = self.shape.ppi_byte_range();
self.data.read_at(range.start).unwrap()
}

/// Offset from the beginning of the strike data header to bitmap data for an individual glyph ID.
pub fn glyph_data_offsets(&self) -> &'a [BigEndian<u32>] {
let range = self.shape.glyph_data_offsets_byte_range();
self.data.read_array(range).unwrap()
}
}

#[cfg(feature = "traversal")]
impl<'a> SomeTable<'a> for Strike<'a> {
fn type_name(&self) -> &str {
"Strike"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("ppem", self.ppem())),
1usize => Some(Field::new("ppi", self.ppi())),
2usize => Some(Field::new("glyph_data_offsets", self.glyph_data_offsets())),
_ => None,
}
}
}

#[cfg(feature = "traversal")]
impl<'a> std::fmt::Debug for Strike<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}

/// [Glyph data](https://learn.microsoft.com/en-us/typography/opentype/spec/sbix#glyph-data) table
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct GlyphDataMarker {
data_byte_len: usize,
}

impl GlyphDataMarker {
fn origin_offset_x_byte_range(&self) -> Range<usize> {
let start = 0;
start..start + i16::RAW_BYTE_LEN
}
fn origin_offset_y_byte_range(&self) -> Range<usize> {
let start = self.origin_offset_x_byte_range().end;
start..start + i16::RAW_BYTE_LEN
}
fn graphic_type_byte_range(&self) -> Range<usize> {
let start = self.origin_offset_y_byte_range().end;
start..start + Tag::RAW_BYTE_LEN
}
fn data_byte_range(&self) -> Range<usize> {
let start = self.graphic_type_byte_range().end;
start..start + self.data_byte_len
}
}

impl<'a> FontRead<'a> for GlyphData<'a> {
fn read(data: FontData<'a>) -> Result<Self, ReadError> {
let mut cursor = data.cursor();
cursor.advance::<i16>();
cursor.advance::<i16>();
cursor.advance::<Tag>();
let data_byte_len = cursor.remaining_bytes();
cursor.advance_by(data_byte_len);
cursor.finish(GlyphDataMarker { data_byte_len })
}
}

/// [Glyph data](https://learn.microsoft.com/en-us/typography/opentype/spec/sbix#glyph-data) table
pub type GlyphData<'a> = TableRef<'a, GlyphDataMarker>;

impl<'a> GlyphData<'a> {
/// The horizontal (x-axis) position of the left edge of the bitmap graphic in relation to the glyph design space origin.
pub fn origin_offset_x(&self) -> i16 {
let range = self.shape.origin_offset_x_byte_range();
self.data.read_at(range.start).unwrap()
}

/// The vertical (y-axis) position of the bottom edge of the bitmap graphic in relation to the glyph design space origin.
pub fn origin_offset_y(&self) -> i16 {
let range = self.shape.origin_offset_y_byte_range();
self.data.read_at(range.start).unwrap()
}

/// Indicates the format of the embedded graphic data: one of 'jpg ', 'png ' or 'tiff', or the special format 'dupe'.
pub fn graphic_type(&self) -> Tag {
let range = self.shape.graphic_type_byte_range();
self.data.read_at(range.start).unwrap()
}

/// The actual embedded graphic data. The total length is inferred from sequential entries in the glyphDataOffsets array and the fixed size (8 bytes) of the preceding fields.
pub fn data(&self) -> &'a [u8] {
let range = self.shape.data_byte_range();
self.data.read_array(range).unwrap()
}
}

#[cfg(feature = "traversal")]
impl<'a> SomeTable<'a> for GlyphData<'a> {
fn type_name(&self) -> &str {
"GlyphData"
}
fn get_field(&self, idx: usize) -> Option<Field<'a>> {
match idx {
0usize => Some(Field::new("origin_offset_x", self.origin_offset_x())),
1usize => Some(Field::new("origin_offset_y", self.origin_offset_y())),
2usize => Some(Field::new("graphic_type", self.graphic_type())),
3usize => Some(Field::new("data", self.data())),
_ => None,
}
}
}

#[cfg(feature = "traversal")]
impl<'a> std::fmt::Debug for GlyphData<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self as &dyn SomeTable<'a>).fmt(f)
}
}
7 changes: 7 additions & 0 deletions read-fonts/src/table_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,13 @@ pub trait TableProvider<'a> {
self.expect_table()
}

fn sbix(&self) -> Result<tables::sbix::Sbix<'a>, ReadError> {
// should we make the user pass this in?
let num_glyphs = self.maxp().map(|maxp| maxp.num_glyphs())?;
let data = self.expect_data_for_tag(tables::sbix::Sbix::TAG)?;
tables::sbix::Sbix::read(data, num_glyphs)
}

fn stat(&self) -> Result<tables::stat::Stat<'a>, ReadError> {
self.expect_table()
}
Expand Down
1 change: 1 addition & 0 deletions read-fonts/src/tables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub mod name;
pub mod os2;
pub mod post;
pub mod postscript;
pub mod sbix;
pub mod stat;
pub mod variations;
pub mod vhea;
Expand Down
24 changes: 24 additions & 0 deletions read-fonts/src/tables/sbix.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//! the [sbix (Standard Bitmap Graphics)](https://docs.microsoft.com/en-us/typography/opentype/spec/sbix) table

include!("../../generated/generated_sbix.rs");

impl<'a> Strike<'a> {
pub fn glyph_data(&self, glyph_id: GlyphId) -> Result<Option<GlyphData<'a>>, ReadError> {
let offsets = self.glyph_data_offsets();
let start_ix = glyph_id.to_u16() as usize;
let start = offsets.get(start_ix).ok_or(ReadError::OutOfBounds)?.get() as usize;
let end = offsets
.get(start_ix + 1)
.ok_or(ReadError::OutOfBounds)?
.get() as usize;
if start == end {
// Empty glyphs are okay
return Ok(None);
}
let data = self
.offset_data()
.slice(start..end)
.ok_or(ReadError::OutOfBounds)?;
Ok(Some(GlyphData::read(data)?))
}
}
Loading