2022-10-24 08:56:48 -06:00
|
|
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
2022-11-15 12:26:59 -07:00
|
|
|
pub(crate) mod fallback;
|
2022-10-18 17:13:48 -06:00
|
|
|
|
2023-09-19 01:59:51 +08:00
|
|
|
use core::fmt;
|
|
|
|
|
|
2023-03-14 00:39:50 +01:00
|
|
|
use alloc::sync::Arc;
|
2023-03-02 18:16:57 -07:00
|
|
|
|
2023-09-19 01:59:51 +08:00
|
|
|
use rustybuzz::Face as RustybuzzFace;
|
|
|
|
|
use self_cell::self_cell;
|
|
|
|
|
|
2022-10-18 12:07:22 -06:00
|
|
|
pub use self::system::*;
|
|
|
|
|
mod system;
|
2022-11-15 12:26:59 -07:00
|
|
|
|
2023-09-19 01:59:51 +08:00
|
|
|
self_cell!(
|
|
|
|
|
struct OwnedFace {
|
|
|
|
|
owner: Arc<dyn AsRef<[u8]> + Send + Sync>,
|
2023-06-08 17:45:54 +02:00
|
|
|
|
2023-09-19 01:59:51 +08:00
|
|
|
#[covariant]
|
|
|
|
|
dependent: RustybuzzFace,
|
2023-06-08 17:45:54 +02:00
|
|
|
}
|
2023-09-19 01:59:51 +08:00
|
|
|
);
|
2022-11-15 12:26:59 -07:00
|
|
|
|
2023-09-19 01:59:51 +08:00
|
|
|
/// A font
|
|
|
|
|
pub struct Font {
|
|
|
|
|
#[cfg(feature = "swash")]
|
|
|
|
|
swash: (u32, swash::CacheKey),
|
|
|
|
|
rustybuzz: OwnedFace,
|
|
|
|
|
data: Arc<dyn AsRef<[u8]> + Send + Sync>,
|
|
|
|
|
id: fontdb::ID,
|
2024-01-17 12:32:33 +03:00
|
|
|
monospace_em_width: Option<f32>,
|
|
|
|
|
scripts: Vec<[u8; 4]>,
|
2023-09-19 01:59:51 +08:00
|
|
|
}
|
2023-07-07 21:44:21 -07:00
|
|
|
|
2023-09-19 01:59:51 +08:00
|
|
|
impl fmt::Debug for Font {
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
|
f.debug_struct("Font")
|
|
|
|
|
.field("id", &self.id)
|
|
|
|
|
.finish_non_exhaustive()
|
2023-06-08 17:45:54 +02:00
|
|
|
}
|
2023-09-19 01:59:51 +08:00
|
|
|
}
|
2023-06-08 17:45:54 +02:00
|
|
|
|
2023-09-19 01:59:51 +08:00
|
|
|
impl Font {
|
|
|
|
|
pub fn id(&self) -> fontdb::ID {
|
|
|
|
|
self.id
|
2023-06-08 17:45:54 +02:00
|
|
|
}
|
|
|
|
|
|
2024-01-17 12:32:33 +03:00
|
|
|
pub fn monospace_em_width(&self) -> Option<f32> {
|
|
|
|
|
self.monospace_em_width
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn scripts(&self) -> &[[u8; 4]] {
|
|
|
|
|
&self.scripts
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-19 01:59:51 +08:00
|
|
|
pub fn data(&self) -> &[u8] {
|
|
|
|
|
(*self.data).as_ref()
|
|
|
|
|
}
|
2023-06-08 17:45:54 +02:00
|
|
|
|
2023-09-19 01:59:51 +08:00
|
|
|
pub fn rustybuzz(&self) -> &RustybuzzFace<'_> {
|
|
|
|
|
self.rustybuzz.borrow_dependent()
|
|
|
|
|
}
|
2023-06-08 17:45:54 +02:00
|
|
|
|
2023-09-19 01:59:51 +08:00
|
|
|
#[cfg(feature = "swash")]
|
|
|
|
|
pub fn as_swash(&self) -> swash::FontRef<'_> {
|
|
|
|
|
let swash = &self.swash;
|
|
|
|
|
swash::FontRef {
|
|
|
|
|
data: self.data(),
|
|
|
|
|
offset: swash.0,
|
|
|
|
|
key: swash.1,
|
2023-06-08 17:45:54 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-12 10:23:54 +01:00
|
|
|
|
|
|
|
|
impl Font {
|
2024-01-17 12:32:33 +03:00
|
|
|
pub fn new(db: &fontdb::Database, id: fontdb::ID) -> Option<Self> {
|
|
|
|
|
let info = db.face(id)?;
|
|
|
|
|
|
|
|
|
|
let (monospace_em_width, scripts) = {
|
|
|
|
|
db.with_face_data(id, |font_data, face_index| {
|
|
|
|
|
let face = ttf_parser::Face::parse(font_data, face_index).ok()?;
|
|
|
|
|
let monospace_em_width = info.monospaced.then(|| {
|
|
|
|
|
let hor_advance = face.glyph_hor_advance(face.glyph_index(' ')?)? as f32;
|
|
|
|
|
let upem = face.units_per_em() as f32;
|
|
|
|
|
Some(hor_advance/upem)
|
|
|
|
|
}).flatten();
|
|
|
|
|
|
|
|
|
|
if info.monospaced && monospace_em_width.is_none() {
|
|
|
|
|
None?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let scripts = face.tables().gpos.into_iter()
|
|
|
|
|
.chain(face.tables().gsub)
|
|
|
|
|
.map(|table| table.scripts)
|
|
|
|
|
.flatten()
|
|
|
|
|
.map(|script| script.tag.to_bytes())
|
|
|
|
|
.collect();
|
|
|
|
|
Some((monospace_em_width, scripts))
|
|
|
|
|
})?
|
|
|
|
|
}?;
|
|
|
|
|
|
2022-11-15 12:26:59 -07:00
|
|
|
let data = match &info.source {
|
2023-03-14 00:39:50 +01:00
|
|
|
fontdb::Source::Binary(data) => Arc::clone(data),
|
2022-11-15 12:26:59 -07:00
|
|
|
#[cfg(feature = "std")]
|
|
|
|
|
fontdb::Source::File(path) => {
|
|
|
|
|
log::warn!("Unsupported fontdb Source::File('{}')", path.display());
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
#[cfg(feature = "std")]
|
2023-03-14 00:39:50 +01:00
|
|
|
fontdb::Source::SharedFile(_path, data) => Arc::clone(data),
|
2022-11-15 12:26:59 -07:00
|
|
|
};
|
2023-09-19 01:59:51 +08:00
|
|
|
|
|
|
|
|
Some(Self {
|
2023-06-08 17:45:54 +02:00
|
|
|
id: info.id,
|
2024-01-17 12:32:33 +03:00
|
|
|
monospace_em_width,
|
|
|
|
|
scripts,
|
2023-06-08 17:45:54 +02:00
|
|
|
#[cfg(feature = "swash")]
|
|
|
|
|
swash: {
|
|
|
|
|
let swash = swash::FontRef::from_index((*data).as_ref(), info.index as usize)?;
|
|
|
|
|
(swash.offset, swash.key)
|
|
|
|
|
},
|
2023-09-19 01:59:51 +08:00
|
|
|
rustybuzz: OwnedFace::try_new(Arc::clone(&data), |data| {
|
|
|
|
|
RustybuzzFace::from_slice((**data).as_ref(), info.index).ok_or(())
|
|
|
|
|
})
|
|
|
|
|
.ok()?,
|
2023-06-08 17:45:54 +02:00
|
|
|
data,
|
2023-09-19 01:59:51 +08:00
|
|
|
})
|
2023-03-12 10:23:54 +01:00
|
|
|
}
|
|
|
|
|
}
|