use super::{
OutlineCurveBuilder,
RawGlyph,
Scale,
OutlineCurve,
GlyphCache,
RawGlyphCache,
ScaledGlyph,
};
use glium::{
Display,
texture::Texture2d,
};
use ttf_parser::{
Face,
GlyphId,
};
use std::{
path::Path,
fs::read,
};
struct OwnedFont{
data:Vec<u8>,
face:Option<Face<'static>>,
}
impl OwnedFont{
fn load<P:AsRef<Path>>(path:P)->Option<OwnedFont>{
let data=match read(path){
Ok(data)=>data,
Err(_)=>return None,
};
let mut font=Self{
data,
face:None,
};
let slice:&'static [u8]=unsafe{
std::slice::from_raw_parts(font.data.as_ptr(),font.data.len())
};
let face=match Face::from_slice(slice,0){
Ok(face)=>face,
Err(_)=>return None,
};
font.face=Some(face);
Some(font)
}
}
pub struct FontOwner{
font:Box<OwnedFont>,
}
impl FontOwner{
pub fn load<P:AsRef<Path>>(path:P)->Option<FontOwner>{
let font=OwnedFont::load(path)?;
Some(Self{
font:Box::new(font),
})
}
pub fn face(&self)->&Face{
self.font.as_ref().face.as_ref().unwrap()
}
pub fn face_wrapper<'a>(&'a self)->FaceWrapper<'a>{
FaceWrapper(self.font.as_ref().face.clone().unwrap())
}
}
pub struct FaceWrapper<'a>(pub Face<'a>);
impl<'a> Font for FaceWrapper<'a>{
fn scale_for_height(&self,height:f32)->Scale{
let k=height/self.0.global_bounding_box().height() as f32;
Scale::new(k,k)
}
fn build_raw_glyph(&self,character:char)->Option<RawGlyph<Vec<OutlineCurve>>>{
if let Some(glyph_id)=self.0.glyph_index(character){
let mut outline_builder=OutlineCurveBuilder::default();
if let Some(bounding_box)=self.0.outline_glyph(glyph_id,&mut outline_builder){
let glyph_size=[
bounding_box.width() as f32,
bounding_box.height() as f32,
];
let glyph_offset=[
bounding_box.x_min as f32,
bounding_box.y_min as f32,
];
let advance_width=self.0.glyph_hor_advance(glyph_id).unwrap() as f32;
let glyph=RawGlyph::<Vec<OutlineCurve>>::raw(
outline_builder.outline,
glyph_size,
glyph_offset,
advance_width,
);
Some(glyph)
}
else{
None
}
}
else{
None
}
}
fn build_raw_undefined_glyph(&self)->RawGlyph<Vec<OutlineCurve>>{
let glyph_id=GlyphId(0);
let mut outline_builder=OutlineCurveBuilder::default();
let bounding_box=self.0.outline_glyph(glyph_id,&mut outline_builder).expect("No undefined glyph");
let glyph_size=[
bounding_box.width() as f32,
bounding_box.height() as f32,
];
let glyph_offset=[
bounding_box.x_min as f32,
bounding_box.y_min as f32,
];
let advance_width=self.0.glyph_hor_advance(glyph_id).unwrap() as f32;
RawGlyph::<Vec<OutlineCurve>>::raw(
outline_builder.outline,
glyph_size,
glyph_offset,
advance_width,
)
}
fn whitespace_advance_width(&self,horizontal_scale:f32)->f32{
self.0.glyph_hor_advance(GlyphId(3)).expect("No whitespace glyph") as f32*horizontal_scale
}
}
pub struct CachedFont{
font:FontOwner,
cache:GlyphCache,
}
impl CachedFont{
pub fn raw(font:FontOwner,glyph_cache:GlyphCache)->CachedFont{
Self{
font,
cache:glyph_cache,
}
}
pub fn new_alphabet(font:FontOwner,alphabet:&str,scale:Scale,display:&Display)->CachedFont{
let face=font.face();
let cache=GlyphCache::new_alphabet(face,alphabet,scale,display);
Self{
font,
cache
}
}
pub fn scaled_undefined_glyph(&self,scale:Scale)->ScaledGlyph<Texture2d>{
self.cache.raw_undefined_glyph().scale(scale)
}
}
impl Font for CachedFont{
fn scale_for_height(&self,height:f32)->Scale{
self.font.face_wrapper().scale_for_height(height)
}
fn build_raw_glyph<'a>(&'a self,character:char)->Option<RawGlyph<Vec<OutlineCurve>>>{
self.font.face_wrapper().build_raw_glyph(character)
}
fn build_raw_undefined_glyph(&self)->RawGlyph<Vec<OutlineCurve>>{
self.font.face_wrapper().build_raw_undefined_glyph()
}
fn whitespace_advance_width(&self,horizontal_scale:f32)->f32{
self.font.face_wrapper().whitespace_advance_width(horizontal_scale)
}
}
impl RawGlyphCache for CachedFont{
fn whitespace_advance_width(&self,horizontal_scale:f32)->f32{
self.cache.whitespace_advance_width(horizontal_scale)
}
fn scale_for_height(&self, height:f32)->Scale{
let height0 = self.cache.bounding_size()[1];
let k = height/height0;
Scale::new(k, k)
}
fn raw_glyph(&self,character:char)->Option<&RawGlyph<Texture2d>>{
if let Some(glyph)=self.cache.raw_glyph(character){
Some(glyph)
}
else{
None
}
}
fn raw_undefined_glyph(&self)->&RawGlyph<Texture2d>{
self.cache.raw_undefined_glyph()
}
}
pub trait Font{
fn scale_for_height(&self,height:f32)->Scale;
fn build_raw_glyph<'a>(&'a self,character:char)->Option<RawGlyph<Vec<OutlineCurve>>>;
fn build_raw_undefined_glyph(&self)->RawGlyph<Vec<OutlineCurve>>;
fn whitespace_advance_width(&self,horizontal_scale:f32)->f32;
}