#![deny(missing_debug_implementations)]
#![warn(rust_2018_idioms)]
pub mod bidi;
pub mod color;
pub mod color_glyph;
pub mod face;
pub mod face_chain;
pub mod layout;
pub mod shaper;
pub mod shaping;
pub mod style;
pub mod variations;
pub use bidi::{
bidi_class, paragraph_level, resolve_neutral_types, resolve_weak_types, split_paragraphs,
BidiClass,
};
pub use color::{Rgba, TRANSPARENT, WHITE};
pub use color_glyph::ColorGlyphBitmap;
pub use face::{Face, FaceKind};
pub use face_chain::FaceChain;
pub use layout::{run_width, wrap_lines};
pub use oxideav_ttf::{NamedInstance, VariationAxis};
pub use shaper::{PositionedGlyph, Shaper, ShaperBuilder};
pub use shaping::{
bengali_category, bengali_feature_tags, burmese_category, burmese_feature_tags,
cluster_boundaries, cluster_boundaries_with, compute_forms, devanagari_category,
devanagari_feature_tags, feature_tags_for_run, gujarati_category, gujarati_feature_tags,
gurmukhi_category, gurmukhi_feature_tags, joining_class, kannada_category,
kannada_feature_tags, khmer_category, khmer_feature_tags, lao_category, lao_feature_tags,
malayalam_category, malayalam_feature_tags, oriya_category, oriya_feature_tags,
presentation_form, reorder_cluster, reorder_cluster_with, script_indic_tags,
shape_text_with_font, shape_text_with_script_with_font, sinhala_category, sinhala_feature_tags,
tamil_category, tamil_feature_tags, telugu_category, telugu_feature_tags, thai_category,
thai_feature_tags, ClusterFlags, IndicCategory, JoiningClass, JoiningForm, ReorderRules,
RephKind, Script, BENGALI_RULES, BURMESE_RULES, DEVANAGARI_RULES, GUJARATI_RULES,
GURMUKHI_RULES, KANNADA_RULES, KHMER_RULES, LAO_RULES, MALAYALAM_RULES, ORIYA_RULES,
SINHALA_RULES, TAMIL_RULES, TELUGU_RULES, THAI_RULES,
};
pub use style::{
synthetic_italic_shear, Style, DEFAULT_SYNTHETIC_ITALIC_DEG, ITALIC_ANGLE_EPSILON_DEG,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Error {
Ttf(oxideav_ttf::Error),
Otf(oxideav_otf::Error),
InvalidSize,
WrongFaceKind {
expected: FaceKind,
actual: FaceKind,
},
}
impl From<oxideav_ttf::Error> for Error {
fn from(e: oxideav_ttf::Error) -> Self {
Self::Ttf(e)
}
}
impl From<oxideav_otf::Error> for Error {
fn from(e: oxideav_otf::Error) -> Self {
Self::Otf(e)
}
}
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Ttf(e) => write!(f, "ttf error: {e}"),
Self::Otf(e) => write!(f, "otf error: {e}"),
Self::InvalidSize => f.write_str("non-positive font size"),
Self::WrongFaceKind { expected, actual } => {
write!(f, "wrong face kind: expected {expected:?}, got {actual:?}")
}
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Ttf(e) => Some(e),
Self::Otf(e) => Some(e),
Self::InvalidSize | Self::WrongFaceKind { .. } => None,
}
}
}
#[cfg(test)]
mod error_tests {
use super::*;
use std::error::Error as _;
#[test]
fn leaf_variants_have_no_source() {
let e = Error::InvalidSize;
assert!(e.source().is_none());
let e = Error::WrongFaceKind {
expected: FaceKind::Ttf,
actual: FaceKind::Otf,
};
assert!(e.source().is_none());
}
#[test]
fn display_emits_human_readable_text() {
let e = Error::InvalidSize;
assert_eq!(format!("{e}"), "non-positive font size");
let e = Error::WrongFaceKind {
expected: FaceKind::Ttf,
actual: FaceKind::Otf,
};
let s = format!("{e}");
assert!(s.starts_with("wrong face kind"), "got {s}");
}
#[test]
fn ttf_wrap_round_trips_via_from() {
let err: Result<Face, Error> = Face::from_ttf_bytes(vec![0u8, 1, 2, 3]);
match err {
Err(Error::Ttf(inner)) => {
let _ = inner; }
Ok(_) => panic!("4-byte garbage should not parse as TTF"),
Err(other) => panic!("expected Error::Ttf, got {other:?}"),
}
}
#[test]
fn otf_wrap_round_trips_via_from() {
let err: Result<Face, Error> = Face::from_otf_bytes(vec![0u8, 1, 2, 3]);
match err {
Err(Error::Otf(inner)) => {
let _ = inner;
}
Ok(_) => panic!("4-byte garbage should not parse as OTF"),
Err(other) => panic!("expected Error::Otf, got {other:?}"),
}
}
}