use super::pdf_native_conversion;
use crate::ffi::pdf_object::types::PdfObjHandle;
use crate::pdf::font::PdfFont;
use std::sync::LazyLock;
use super::{Handle, HandleStore};
pub static PDF_FONTS: LazyLock<HandleStore<PdfFont>> = LazyLock::new(HandleStore::default);
#[unsafe(no_mangle)]
pub extern "C" fn mp_pdf_font_from_dict(dict_ptr: PdfObjHandle) -> super::Handle {
if dict_ptr == 0 {
return 0;
}
let dict = match pdf_native_conversion::pdf_obj_to_dict(dict_ptr) {
Some(d) => d,
None => return 0,
};
let font = match PdfFont::from_pdf_dict(&dict) {
Ok(f) => f,
Err(_) => return 0,
};
PDF_FONTS.insert(font)
}
#[unsafe(no_mangle)]
pub extern "C" fn mp_pdf_font_glyph_width(font: super::Handle, char_code: u32) -> f64 {
if font == 0 {
return 0.0;
}
PDF_FONTS
.get(font)
.and_then(|arc| arc.lock().ok().map(|f| f.glyph_width(char_code)))
.unwrap_or(0.0)
}
#[unsafe(no_mangle)]
pub extern "C" fn mp_pdf_font_decode_text(
font: super::Handle,
bytes: *const u8,
len: usize,
out_buf: *mut u8,
out_len: usize,
) -> i32 {
if font == 0 || bytes.is_null() || out_buf.is_null() || out_len == 0 {
return -1;
}
let input = unsafe { std::slice::from_raw_parts(bytes, len) };
let encoding = match PDF_FONTS.get(font) {
Some(arc) => match arc.lock() {
Ok(f) => f.encoding().clone(),
Err(_) => return -1,
},
None => return -1,
};
let mut s = String::new();
for &b in input {
if let Some(c) = encoding.decode_char(b) {
s.push(c);
}
}
let utf8 = s.into_bytes();
let written = utf8.len().min(out_len);
if written > 0 {
unsafe { std::ptr::copy_nonoverlapping(utf8.as_ptr(), out_buf, written) };
}
written as i32
}
#[unsafe(no_mangle)]
pub extern "C" fn mp_pdf_font_free(font: super::Handle) {
if font == 0 {
return;
}
PDF_FONTS.remove(font);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ffi::pdf_object::{pdf_dict_puts, pdf_new_dict, pdf_new_name};
use std::ffi::CStr;
fn make_font_dict() -> PdfObjHandle {
let dict = pdf_new_dict(0, 0, 4);
pdf_dict_puts(0, dict, c"Type".as_ptr(), pdf_new_name(0, c"Font".as_ptr()));
pdf_dict_puts(
0,
dict,
c"Subtype".as_ptr(),
pdf_new_name(0, c"Type1".as_ptr()),
);
pdf_dict_puts(
0,
dict,
c"BaseFont".as_ptr(),
pdf_new_name(0, c"Helvetica".as_ptr()),
);
dict
}
#[test]
fn test_mp_pdf_font_from_dict_and_free() {
let dict = make_font_dict();
let font = mp_pdf_font_from_dict(dict);
assert_ne!(font, 0);
mp_pdf_font_free(font);
}
#[test]
fn test_mp_pdf_font_glyph_width() {
let dict = make_font_dict();
let font = mp_pdf_font_from_dict(dict);
assert_ne!(font, 0);
let w = mp_pdf_font_glyph_width(font, 65);
assert!(w > 0.0);
mp_pdf_font_free(font);
}
#[test]
fn test_mp_pdf_font_decode_text() {
let dict = make_font_dict();
let font = mp_pdf_font_from_dict(dict);
assert_ne!(font, 0);
let input = b"Hello";
let mut out = [0u8; 32];
let n = mp_pdf_font_decode_text(font, input.as_ptr(), 5, out.as_mut_ptr(), 32);
assert!(n > 0);
assert_eq!(&out[..n as usize], b"Hello");
mp_pdf_font_free(font);
}
#[test]
fn test_mp_pdf_font_null_checks() {
assert_eq!(mp_pdf_font_from_dict(0), 0);
assert_eq!(mp_pdf_font_glyph_width(0, 65), 0.0);
}
}