1use crate::bindgen::{
5 FPDF_BOOL, FPDF_SYSFONTINFO, FXFONT_FF_FIXEDPITCH, FXFONT_FF_ROMAN, FXFONT_FF_SCRIPT,
6};
7use crate::pdf::font::{PdfFontCharacterSet, PdfFontWeight};
8use std::collections::HashMap;
9use std::ffi::{CStr, CString};
10use std::os::raw::{c_char, c_int, c_uchar, c_uint, c_ulong, c_void};
11use std::panic;
12use std::str::FromStr;
13
14pub struct PdfiumCustomFontProviderRequest {
16 pub font_face: String,
18
19 pub character_set: PdfFontCharacterSet,
21
22 pub weight: PdfFontWeight,
24
25 pub is_italic: bool,
28
29 pub is_fixed_pitch: bool,
31
32 pub is_serif: bool,
36
37 pub is_cursive: bool,
40}
41
42#[cfg(feature = "thread_safe")]
43unsafe impl Sync for PdfiumCustomFontProviderRequest {}
44
45#[cfg(feature = "thread_safe")]
46unsafe impl Send for PdfiumCustomFontProviderRequest {}
47
48pub type PdfiumCustomFontHandle = u64;
50
51pub struct PdfiumCustomFontProviderResponse {
53 pub id: PdfiumCustomFontHandle,
56
57 pub font_face: String,
59
60 pub character_set: PdfFontCharacterSet,
62
63 pub data: Vec<u8>,
66}
67
68#[cfg(feature = "thread_safe")]
69unsafe impl Sync for PdfiumCustomFontProviderResponse {}
70
71#[cfg(feature = "thread_safe")]
72unsafe impl Send for PdfiumCustomFontProviderResponse {}
73
74pub trait PdfiumCustomFontProvider: Send + Sync {
76 fn provide(
80 &mut self,
81 request: PdfiumCustomFontProviderRequest,
82 ) -> Option<PdfiumCustomFontProviderResponse>;
83}
84
85#[repr(C)]
86#[allow(non_snake_case)]
87pub(crate) struct PdfiumCustomFontProviderExt {
88 version: c_int,
92 Release: Option<unsafe extern "C" fn(pThis: *mut FPDF_SYSFONTINFO)>,
93 EnumFonts: Option<unsafe extern "C" fn(pThis: *mut FPDF_SYSFONTINFO, pMapper: *mut c_void)>,
94 MapFont: Option<
95 unsafe extern "C" fn(
96 pThis: *mut FPDF_SYSFONTINFO,
97 weight: c_int,
98 bItalic: FPDF_BOOL,
99 charset: c_int,
100 pitch_family: c_int,
101 face: *const c_char,
102 bExact: *mut FPDF_BOOL,
103 ) -> *mut c_void,
104 >,
105 GetFont: Option<
106 unsafe extern "C" fn(pThis: *mut FPDF_SYSFONTINFO, face: *const c_char) -> *mut c_void,
107 >,
108 GetFontData: Option<
109 unsafe extern "C" fn(
110 pThis: *mut FPDF_SYSFONTINFO,
111 hFont: *mut c_void,
112 table: c_uint,
113 buffer: *mut c_uchar,
114 buf_size: c_ulong,
115 ) -> c_ulong,
116 >,
117 GetFaceName: Option<
118 unsafe extern "C" fn(
119 pThis: *mut FPDF_SYSFONTINFO,
120 hFont: *mut c_void,
121 buffer: *mut c_char,
122 buf_size: c_ulong,
123 ) -> c_ulong,
124 >,
125 GetFontCharset:
126 Option<unsafe extern "C" fn(pThis: *mut FPDF_SYSFONTINFO, hFont: *mut c_void) -> c_int>,
127 DeleteFont: Option<unsafe extern "C" fn(pThis: *mut FPDF_SYSFONTINFO, hFont: *mut c_void)>,
128 provider: Box<dyn PdfiumCustomFontProvider>,
129 cache: HashMap<PdfiumCustomFontHandle, PdfiumCustomFontProviderResponse>,
130}
131
132impl PdfiumCustomFontProviderExt {
133 pub(crate) fn new(provider: Box<dyn PdfiumCustomFontProvider>) -> Self {
134 PdfiumCustomFontProviderExt {
135 version: 2,
136 EnumFonts: None, Release: Some(fpdf_sys_font_info_release),
138 MapFont: Some(fpdf_sys_font_info_map_font),
139 GetFont: None,
140 GetFontData: Some(fpdf_sys_font_info_get_font_data),
141 GetFaceName: Some(fpdf_sys_font_info_get_face_name),
142 GetFontCharset: Some(fpdf_sys_font_info_get_font_charset),
143 DeleteFont: Some(fpdf_sys_font_info_delete_font),
144 provider,
145 cache: HashMap::new(),
146 }
147 }
148
149 #[inline]
151 pub(crate) fn as_fpdf_sys_font_info_mut_ptr(&mut self) -> &mut FPDF_SYSFONTINFO {
152 unsafe { &mut *(self as *mut PdfiumCustomFontProviderExt as *mut FPDF_SYSFONTINFO) }
153 }
154}
155
156#[allow(non_snake_case)]
158unsafe fn fpdf_sys_font_info_to_custom_font_provider<'a>(
159 pThis: *mut FPDF_SYSFONTINFO,
160) -> &'a mut PdfiumCustomFontProviderExt {
161 &mut *(pThis as *mut PdfiumCustomFontProviderExt)
162}
163
164#[allow(non_snake_case)]
166unsafe extern "C" fn fpdf_sys_font_info_release(pThis: *mut FPDF_SYSFONTINFO) {
167 fpdf_sys_font_info_to_custom_font_provider(pThis)
168 .cache
169 .clear();
170}
171
172#[allow(non_snake_case)]
174unsafe extern "C" fn fpdf_sys_font_info_map_font(
175 pThis: *mut FPDF_SYSFONTINFO,
176 weight: c_int,
177 bItalic: FPDF_BOOL,
178 charset: c_int,
179 pitch_family: c_int,
180 face: *const c_char,
181 _bExact: *mut FPDF_BOOL, ) -> *mut c_void {
183 if pThis.is_null() || face.is_null() {
184 return std::ptr::null_mut();
185 }
186
187 let provider = fpdf_sys_font_info_to_custom_font_provider(pThis);
188
189 let result = provider.provider.provide(PdfiumCustomFontProviderRequest {
190 font_face: match CStr::from_ptr(face).to_str() {
191 Ok(font_face) => font_face.to_owned(),
192 Err(_) => return std::ptr::null_mut(),
193 },
194 character_set: match PdfFontCharacterSet::from_pdfium(charset) {
195 Some(character_set) => character_set,
196 None => return std::ptr::null_mut(),
197 },
198 weight: match PdfFontWeight::from_pdfium(weight) {
199 Some(weight) => weight,
200 None => return std::ptr::null_mut(),
201 },
202 is_italic: bItalic != 0,
203 is_fixed_pitch: pitch_family & (FXFONT_FF_FIXEDPITCH as i32) == 1,
204 is_serif: pitch_family & (FXFONT_FF_ROMAN as i32) == 1,
205 is_cursive: pitch_family & (FXFONT_FF_SCRIPT as i32) == 1,
206 });
207
208 match result {
209 Some(response) => {
210 let id = response.id;
211
212 provider.cache.insert(id, response);
213
214 id as *mut c_void
215 }
216 None => std::ptr::null_mut(),
217 }
218}
219
220#[allow(non_snake_case)]
222unsafe extern "C" fn fpdf_sys_font_info_get_font_data(
223 pThis: *mut FPDF_SYSFONTINFO,
224 hFont: *mut c_void,
225 table: c_uint,
226 buffer: *mut c_uchar,
227 buf_size: c_ulong,
228) -> c_ulong {
229 if pThis.is_null() || hFont.is_null() {
230 return 0;
231 }
232
233 if table != 0 {
234 return 0;
237 }
238
239 if let Some(response) = fpdf_sys_font_info_to_custom_font_provider(pThis)
240 .cache
241 .get(&(hFont as PdfiumCustomFontHandle))
242 {
243 let font_data = &response.data;
244
245 if !buffer.is_null() && buf_size as usize >= font_data.len() {
246 buffer.copy_from_nonoverlapping(font_data.as_ptr(), font_data.len());
247 }
248
249 font_data.len() as c_ulong
250 } else {
251 0
256 }
257}
258
259#[allow(non_snake_case)]
261unsafe extern "C" fn fpdf_sys_font_info_get_face_name(
262 pThis: *mut FPDF_SYSFONTINFO,
263 hFont: *mut c_void,
264 buffer: *mut c_char,
265 buf_size: c_ulong,
266) -> c_ulong {
267 if let Some(response) = fpdf_sys_font_info_to_custom_font_provider(pThis)
268 .cache
269 .get(&(hFont as PdfiumCustomFontHandle))
270 {
271 if let Ok(face_name) = CString::from_str(&response.font_face) {
272 let chars = face_name.as_bytes_with_nul();
273
274 if !buffer.is_null() && buf_size as usize >= chars.len() {
275 buffer.copy_from_nonoverlapping(chars.as_ptr() as *const i8, chars.len());
276 }
277
278 chars.len() as c_ulong
279 } else {
280 panic!(
284 "Unable to convert face name to C string in fpdf_sys_font_info_get_face_name: {:?}",
285 &response.font_face
286 );
287 }
288 } else {
289 panic!(
294 "Unknown font handle received from Pdfium in fpdf_sys_font_info_get_face_name: {:?}",
295 hFont
296 );
297 }
298}
299
300#[allow(non_snake_case)]
302unsafe extern "C" fn fpdf_sys_font_info_get_font_charset(
303 pThis: *mut FPDF_SYSFONTINFO,
304 hFont: *mut c_void,
305) -> c_int {
306 if let Some(response) = fpdf_sys_font_info_to_custom_font_provider(pThis)
307 .cache
308 .get(&(hFont as PdfiumCustomFontHandle))
309 {
310 response.character_set.as_pdfium()
311 } else {
312 panic!(
317 "Unknown font handle received from Pdfium in fpdf_sys_font_info_get_font_charset: {:?}",
318 hFont
319 );
320 }
321}
322
323#[allow(non_snake_case)]
325unsafe extern "C" fn fpdf_sys_font_info_delete_font(
326 pThis: *mut FPDF_SYSFONTINFO,
327 hFont: *mut c_void,
328) {
329 fpdf_sys_font_info_to_custom_font_provider(pThis)
330 .cache
331 .remove(&(hFont as PdfiumCustomFontHandle));
332}