use core::mem::size_of;
use core::ptr;
use core::slice;
use read_fonts::types::GlyphId;
use crate::hb::face::Scale;
use super::buffer::{hb_buffer_t, GlyphInfo, GlyphPosition};
use super::face::{hb_font_t, GlyphExtents};
#[derive(Clone, Copy, Debug)]
pub struct RawAdvanceWidthBatch {
pub len: usize,
pub gids: *const u32,
pub advances: *mut i32,
pub gid_stride: isize,
pub advance_stride: isize,
}
pub struct AdvanceWidthBatch<'a> {
infos: &'a [GlyphInfo],
positions: &'a mut [GlyphPosition],
}
impl<'a> AdvanceWidthBatch<'a> {
pub(crate) fn new(buffer: &'a mut hb_buffer_t) -> Self {
let len = buffer.len;
let infos = &buffer.info[..len];
let positions = &mut buffer.pos[..len];
Self { infos, positions }
}
pub fn len(&self) -> usize {
self.infos.len()
}
pub fn is_empty(&self) -> bool {
self.infos.is_empty()
}
pub fn into_raw(self) -> RawAdvanceWidthBatch {
if self.infos.is_empty() {
return RawAdvanceWidthBatch {
len: 0,
gids: ptr::null(),
advances: ptr::null_mut(),
gid_stride: size_of::<GlyphInfo>() as isize,
advance_stride: size_of::<GlyphPosition>() as isize,
};
}
RawAdvanceWidthBatch {
len: self.infos.len(),
gids: self.infos.as_ptr().cast::<u32>(),
advances: self.positions.as_mut_ptr().cast::<i32>(),
gid_stride: size_of::<GlyphInfo>() as isize,
advance_stride: size_of::<GlyphPosition>() as isize,
}
}
}
pub struct AdvanceWidthBatchIter<'a> {
infos: slice::Iter<'a, GlyphInfo>,
positions: slice::IterMut<'a, GlyphPosition>,
}
impl<'a> Iterator for AdvanceWidthBatchIter<'a> {
type Item = (GlyphId, &'a mut i32);
fn next(&mut self) -> Option<Self::Item> {
let info = self.infos.next()?;
let pos = self.positions.next()?;
Some((info.as_glyph(), &mut pos.x_advance))
}
}
impl<'a> IntoIterator for AdvanceWidthBatch<'a> {
type Item = (GlyphId, &'a mut i32);
type IntoIter = AdvanceWidthBatchIter<'a>;
fn into_iter(self) -> Self::IntoIter {
AdvanceWidthBatchIter {
infos: self.infos.iter(),
positions: self.positions.iter_mut(),
}
}
}
pub struct BuiltinFontFuncs<'a> {
face: &'a hb_font_t<'a>,
}
impl<'a> BuiltinFontFuncs<'a> {
pub(crate) fn new(face: &'a hb_font_t<'a>) -> Self {
Self { face }
}
pub fn nominal_glyph(&self, c: u32) -> Option<GlyphId> {
self.face.get_nominal_glyph(c)
}
pub fn variant_glyph(&self, c: u32, vs: u32) -> Option<GlyphId> {
self.face.get_nominal_variant_glyph(c, vs)
}
pub fn advance_width(&self, glyph: GlyphId) -> i32 {
self.face.glyph_h_advance(glyph)
}
pub fn advance_height(&self, glyph: GlyphId) -> i32 {
self.face.glyph_v_advance(glyph)
}
pub fn vertical_origin(&self, glyph: GlyphId) -> (i32, i32) {
(
self.advance_width(glyph) / 2,
self.face.glyph_v_origin(glyph),
)
}
pub fn extents(&self, glyph: GlyphId) -> Option<GlyphExtents> {
let mut extents = GlyphExtents::default();
if self.face.glyph_extents(glyph, &mut extents) {
Some(extents)
} else {
None
}
}
pub fn populate_advance_widths(&self, batch: AdvanceWidthBatch<'_>) {
for (glyph, advance) in batch {
*advance = self.face.glyph_h_advance(glyph);
}
}
}
pub trait FontFuncs {
fn nominal_glyph(&mut self, builtin: &BuiltinFontFuncs, c: u32) -> Option<GlyphId> {
builtin.nominal_glyph(c)
}
fn variant_glyph(&mut self, builtin: &BuiltinFontFuncs, c: u32, vs: u32) -> Option<GlyphId> {
builtin.variant_glyph(c, vs)
}
fn advance_width(&mut self, builtin: &BuiltinFontFuncs, glyph: GlyphId) -> i32 {
builtin.advance_width(glyph)
}
fn populate_advance_widths(
&mut self,
builtin: &BuiltinFontFuncs,
batch: AdvanceWidthBatch<'_>,
) {
for (glyph, advance) in batch {
*advance = self.advance_width(builtin, glyph);
}
}
fn advance_height(&mut self, builtin: &BuiltinFontFuncs, glyph: GlyphId) -> i32 {
builtin.advance_height(glyph)
}
fn vertical_origin(&mut self, builtin: &BuiltinFontFuncs, glyph: GlyphId) -> (i32, i32) {
builtin.vertical_origin(glyph)
}
fn extents(&mut self, builtin: &BuiltinFontFuncs, glyph: GlyphId) -> Option<GlyphExtents> {
builtin.extents(glyph)
}
}
pub(crate) struct FontFuncsDispatch<'a, 'u> {
builtin: BuiltinFontFuncs<'a>,
scale: Scale,
funcs: Option<&'u mut (dyn FontFuncs + 'u)>,
}
impl<'a, 'u> FontFuncsDispatch<'a, 'u> {
pub(crate) fn new(
face: &'a hb_font_t<'a>,
scale: Scale,
funcs: Option<&'u mut (dyn FontFuncs + 'u)>,
) -> Self {
Self {
builtin: BuiltinFontFuncs::new(face),
scale,
funcs,
}
}
#[inline(always)]
pub(crate) fn font(&self) -> &'a hb_font_t<'a> {
self.builtin.face
}
#[inline(always)]
pub(crate) fn scale(&self) -> &Scale {
&self.scale
}
#[inline(always)]
fn scale_x(&self, value: i32) -> i32 {
self.scale.scale_x(value)
}
#[inline(always)]
fn scale_y(&self, value: i32) -> i32 {
self.scale.scale_y(value)
}
#[inline(always)]
fn scale_point(&self, point: (i32, i32)) -> (i32, i32) {
(self.scale_x(point.0), self.scale_y(point.1))
}
#[inline(always)]
fn scale_extents(&self, extents: GlyphExtents) -> GlyphExtents {
self.scale.scale_extents(extents)
}
#[inline(always)]
pub(crate) fn nominal_glyph(&mut self, c: u32) -> Option<GlyphId> {
let cache = self.builtin.face.cmap_cache;
if let Some(gid) = cache.get(c) {
Some(gid.into())
} else if let Some(funcs) = &mut self.funcs {
if let Some(gid) = funcs.nominal_glyph(&self.builtin, c) {
cache.set(c, gid.to_u32());
Some(gid)
} else {
None
}
} else if let Some(gid) = self.builtin.nominal_glyph(c) {
cache.set(c, gid.to_u32());
Some(gid)
} else {
None
}
}
#[inline(always)]
pub(crate) fn has_glyph(&mut self, c: u32) -> bool {
self.nominal_glyph(c).is_some()
}
#[inline(always)]
pub(crate) fn variant_glyph(&mut self, c: u32, vs: u32) -> Option<GlyphId> {
if let Some(funcs) = &mut self.funcs {
funcs.variant_glyph(&self.builtin, c, vs)
} else {
self.builtin.variant_glyph(c, vs)
}
}
#[inline(always)]
pub(crate) fn advance_width(&mut self, glyph: GlyphId) -> i32 {
if let Some(funcs) = &mut self.funcs {
funcs.advance_width(&self.builtin, glyph)
} else {
self.scale_x(self.builtin.advance_width(glyph))
}
}
#[inline(always)]
pub(crate) fn advance_height(&mut self, glyph: GlyphId) -> i32 {
if let Some(funcs) = &mut self.funcs {
funcs.advance_height(&self.builtin, glyph)
} else {
self.scale_y(self.builtin.advance_height(glyph))
}
}
#[inline(always)]
pub(crate) fn vertical_origin(&mut self, glyph: GlyphId) -> (i32, i32) {
if let Some(funcs) = &mut self.funcs {
funcs.vertical_origin(&self.builtin, glyph)
} else {
self.scale_point(self.builtin.vertical_origin(glyph))
}
}
#[inline(always)]
pub(crate) fn extents(&mut self, glyph: GlyphId) -> Option<GlyphExtents> {
if let Some(funcs) = &mut self.funcs {
funcs.extents(&self.builtin, glyph)
} else {
Some(self.scale_extents(self.builtin.extents(glyph)?))
}
}
pub(crate) fn populate_advance_widths(&mut self, batch: AdvanceWidthBatch<'_>) {
if let Some(funcs) = &mut self.funcs {
funcs.populate_advance_widths(&self.builtin, batch);
} else {
let font = self.font();
font.glyph_metrics.populate_advance_widths(
batch.infos,
batch.positions,
font.coords(),
self.scale,
);
}
}
}