Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ ttf-parser = { version = "0.25", default-features = false, features = [
] }
hashbrown = { version = "0.15", optional = true }
rayon = { version = "1.10", optional = true }
thiserror = { version = "2.0.17", default-features = false }
30 changes: 7 additions & 23 deletions src/font.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ use crate::layout::GlyphRasterConfig;
use crate::math::{Geometry, Line};
use crate::platform::{as_i32, ceil, floor, fract, is_negative};
use crate::raster::Raster;
use crate::table::{load_gsub, TableKern};
use crate::table::{TableKern, load_gsub};
use crate::unicode;
use crate::FontResult;
use crate::{FontError, FontResult};
use crate::{HashMap, HashSet};
use alloc::string::String;
use alloc::vec;
Expand All @@ -13,7 +13,7 @@ use core::hash::{Hash, Hasher};
use core::mem;
use core::num::NonZeroU16;
use core::ops::Deref;
use ttf_parser::{Face, FaceParsingError, GlyphId, Tag};
use ttf_parser::{Face, GlyphId, Tag};

#[cfg(feature = "parallel")]
use rayon::prelude::*;
Expand Down Expand Up @@ -215,19 +215,6 @@ impl core::fmt::Debug for Font {
}
}

/// Converts a ttf-parser FaceParsingError into a string.
fn convert_error(error: FaceParsingError) -> &'static str {
use FaceParsingError::*;
match error {
MalformedFont => "An attempt to read out of bounds detected.",
UnknownMagic => "Face data must start with 0x00010000, 0x74727565, 0x4F54544F or 0x74746366.",
FaceIndexOutOfBounds => "The face index is larger than the number of faces in the font.",
NoHeadTable => "The head table is missing or malformed.",
NoHheaTable => "The hhea table is missing or malformed.",
NoMaxpTable => "The maxp table is missing or malformed.",
}
}

fn convert_name(face: &Face) -> Option<String> {
for name in face.names() {
if name.name_id == 4 && name.is_unicode() {
Expand All @@ -242,10 +229,7 @@ impl Font {
pub fn from_bytes<Data: Deref<Target = [u8]>>(data: Data, settings: FontSettings) -> FontResult<Font> {
let hash = crate::hash::hash(&data);

let face = match Face::parse(&data, settings.collection_index) {
Ok(f) => f,
Err(e) => return Err(convert_error(e)),
};
let face = Face::parse(&data, settings.collection_index)?;
let name = convert_name(&face);

// Optionally get kerning values for the font. This should be a try block in the future.
Expand Down Expand Up @@ -283,9 +267,9 @@ impl Font {
// Parse and store all unique codepoints.
let mut glyphs: Vec<Glyph> = vec::from_elem(Glyph::default(), glyph_count as usize);

let generate_glyph = |index: u16| -> Result<Glyph, &'static str> {
let generate_glyph = |index: u16| -> Result<Glyph, FontError> {
if index >= glyph_count {
return Err("Attempted to map a codepoint out of bounds.");
return Err(FontError::CodepointOutOfBounds);
}

let mut glyph = Glyph::default();
Expand All @@ -312,7 +296,7 @@ impl Font {
{
let generated: Vec<(u16, Glyph)> = indices_to_load
.into_par_iter()
.map(|index| Ok((index, generate_glyph(index)?)))
.map(|index| Ok::<_, FontError>((index, generate_glyph(index)?)))
.collect::<Result<_, _>>()?;
for (index, glyph) in generated {
glyphs[index as usize] = glyph;
Expand Down
37 changes: 35 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,44 @@ mod table;
mod unicode;

pub use crate::font::*;
use thiserror::Error;
use ttf_parser::FaceParsingError;

#[cfg(feature = "hashbrown")]
pub(crate) use hashbrown::{HashMap, HashSet};
#[cfg(not(feature = "hashbrown"))]
pub(crate) use std::collections::{HashMap, HashSet};

/// Alias for Result<T, &'static str>.
pub type FontResult<T> = Result<T, &'static str>;
/// Alias for Result<T, FontError>.
pub type FontResult<T> = Result<T, FontError>;

#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
pub enum FontError {
#[error("An attempt to read out of bounds detected.")]
MalformedFont,
#[error("Face data must start with 0x00010000, 0x74727565, 0x4F54544F or 0x74746366.")]
UnknownMagic,
#[error("The face index is larger than the number of faces in the font.")]
FaceIndexOutOfBounds,
#[error("The head table is missing or malformed.")]
NoHeadTable,
#[error("The hhea table is missing or malformed.")]
NoHheaTable,
#[error("The maxp table is missing or malformed.")]
NoMaxpTable,
#[error("Attempted to map a codepoint out of bounds.")]
CodepointOutOfBounds,
}

impl From<FaceParsingError> for FontError {
fn from(error: FaceParsingError) -> FontError {
match error {
FaceParsingError::MalformedFont => FontError::MalformedFont,
FaceParsingError::UnknownMagic => FontError::UnknownMagic,
FaceParsingError::FaceIndexOutOfBounds => FontError::FaceIndexOutOfBounds,
FaceParsingError::NoHeadTable => FontError::NoHeadTable,
FaceParsingError::NoHheaTable => FontError::NoHeadTable,
FaceParsingError::NoMaxpTable => FontError::NoMaxpTable,
}
}
}