pdfium_render/pdf/
font.rs

1//! Defines the [PdfFont] struct, exposing functionality related to a single font used to
2//! render text in a `PdfDocument`.
3
4pub mod glyph;
5pub mod glyphs;
6
7use crate::bindgen::{FPDF_FONT, FPDF_FONT_TRUETYPE, FPDF_FONT_TYPE1};
8use crate::bindings::PdfiumLibraryBindings;
9use crate::error::{PdfiumError, PdfiumInternalError};
10use crate::pdf::document::fonts::PdfFontBuiltin;
11use crate::pdf::document::PdfDocument;
12use crate::pdf::font::glyphs::PdfFontGlyphs;
13use crate::pdf::points::PdfPoints;
14use crate::utils::mem::create_byte_buffer;
15use bitflags::bitflags;
16use std::io::Read;
17use std::os::raw::{c_char, c_int, c_uint};
18
19#[cfg(not(target_arch = "wasm32"))]
20use std::fs::File;
21
22#[cfg(not(target_arch = "wasm32"))]
23use std::path::Path;
24
25#[cfg(target_arch = "wasm32")]
26use wasm_bindgen::JsCast;
27
28#[cfg(target_arch = "wasm32")]
29use wasm_bindgen_futures::JsFuture;
30
31#[cfg(target_arch = "wasm32")]
32use js_sys::{ArrayBuffer, Uint8Array};
33
34#[cfg(target_arch = "wasm32")]
35use web_sys::{window, Blob, Response};
36
37// The following dummy declaration is used only when running cargo doc.
38// It allows documentation of WASM-specific functionality to be included
39// in documentation generated on non-WASM targets.
40
41#[cfg(doc)]
42struct Blob;
43
44bitflags! {
45    pub(crate) struct FpdfFontDescriptorFlags: u32 {
46        const FIXED_PITCH_BIT_1 =  0b00000000000000000000000000000001;
47        const SERIF_BIT_2 =        0b00000000000000000000000000000010;
48        const SYMBOLIC_BIT_3 =     0b00000000000000000000000000000100;
49        const SCRIPT_BIT_4 =       0b00000000000000000000000000001000;
50        const NON_SYMBOLIC_BIT_6 = 0b00000000000000000000000000100000;
51        const ITALIC_BIT_7 =       0b00000000000000000000000001000000;
52        const ALL_CAP_BIT_17 =     0b00000000000000010000000000000000;
53        const SMALL_CAP_BIT_18 =   0b00000000000000100000000000000000;
54        const FORCE_BOLD_BIT_19 =  0b00000000000001000000000000000000;
55    }
56}
57
58/// The weight of a [PdfFont]. Typical values are 400 (normal) and 700 (bold).
59#[derive(Copy, Clone, Debug, PartialEq)]
60pub enum PdfFontWeight {
61    Weight100,
62    Weight200,
63    Weight300,
64    Weight400Normal,
65    Weight500,
66    Weight600,
67    Weight700Bold,
68    Weight800,
69    Weight900,
70
71    /// Any font weight value that falls outside the typical 100 - 900 value range.
72    Custom(u32),
73}
74
75impl PdfFontWeight {
76    pub(crate) fn from_pdfium(value: c_int) -> Option<PdfFontWeight> {
77        match value {
78            -1 => None,
79            100 => Some(PdfFontWeight::Weight100),
80            200 => Some(PdfFontWeight::Weight200),
81            300 => Some(PdfFontWeight::Weight300),
82            400 => Some(PdfFontWeight::Weight400Normal),
83            500 => Some(PdfFontWeight::Weight500),
84            600 => Some(PdfFontWeight::Weight600),
85            700 => Some(PdfFontWeight::Weight700Bold),
86            800 => Some(PdfFontWeight::Weight800),
87            900 => Some(PdfFontWeight::Weight900),
88            other => Some(PdfFontWeight::Custom(other as u32)),
89        }
90    }
91}
92
93/// A single font used to render text in a [PdfDocument].
94///
95/// The PDF specification defines 14 built-in fonts that can be used in any PDF file without
96/// font embedding. Additionally, custom fonts can be directly embedded into any PDF file as
97/// a data stream.
98pub struct PdfFont<'a> {
99    built_in: Option<PdfFontBuiltin>,
100    handle: FPDF_FONT,
101    bindings: &'a dyn PdfiumLibraryBindings,
102    glyphs: PdfFontGlyphs<'a>,
103    is_font_memory_loaded: bool,
104}
105
106impl<'a> PdfFont<'a> {
107    #[inline]
108    pub(crate) fn from_pdfium(
109        handle: FPDF_FONT,
110        bindings: &'a dyn PdfiumLibraryBindings,
111        built_in: Option<PdfFontBuiltin>,
112        is_font_memory_loaded: bool,
113    ) -> Self {
114        PdfFont {
115            built_in,
116            handle,
117            bindings,
118            glyphs: PdfFontGlyphs::from_pdfium(handle, bindings),
119            is_font_memory_loaded,
120        }
121    }
122
123    /// Creates a new [PdfFont] from the given given built-in font argument.
124    ///
125    /// This function is now deprecated and will be removed in release 0.9.0.
126    /// Use the `PdfFonts::new_built_in()` function instead.
127    #[deprecated(
128        since = "0.8.1",
129        note = "This function has been moved. Use the PdfFonts::new_built_in() function instead."
130    )]
131    #[doc(hidden)]
132    #[inline]
133    pub fn new_built_in(document: &'a PdfDocument<'a>, font: PdfFontBuiltin) -> PdfFont<'a> {
134        Self::from_pdfium(
135            document
136                .bindings()
137                .FPDFText_LoadStandardFont(document.handle(), font.to_pdf_font_name()),
138            document.bindings(),
139            Some(font),
140            true,
141        )
142    }
143
144    /// Creates a new [PdfFont] for the built-in "Times-Roman" font.
145    ///
146    /// This function is now deprecated and will be removed in release 0.9.0.
147    /// Use the `PdfFonts::times_roman()` function instead.
148    #[deprecated(
149        since = "0.8.1",
150        note = "This function has been moved. Use the PdfFonts::times_roman() function instead."
151    )]
152    #[doc(hidden)]
153    #[inline]
154    pub fn times_roman(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
155        #[allow(deprecated)]
156        Self::new_built_in(document, PdfFontBuiltin::TimesRoman)
157    }
158
159    /// Creates a new [PdfFont] for the built-in "Times-Bold" font.
160    ///
161    /// This function is now deprecated and will be removed in release 0.9.0.
162    /// Use the `PdfFonts::times_bold()` function instead.
163    #[deprecated(
164        since = "0.8.1",
165        note = "This function has been moved. Use the PdfFonts::times_bold() function instead."
166    )]
167    #[doc(hidden)]
168    #[inline]
169    pub fn times_bold(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
170        #[allow(deprecated)]
171        Self::new_built_in(document, PdfFontBuiltin::TimesBold)
172    }
173
174    /// Creates a new [PdfFont] for the built-in "Times-Italic" font.
175    ///
176    /// This function is now deprecated and will be removed in release 0.9.0.
177    /// Use the `PdfFonts::times_italic()` function instead.
178    #[deprecated(
179        since = "0.8.1",
180        note = "This function has been moved. Use the PdfFonts::times_italic() function instead."
181    )]
182    #[doc(hidden)]
183    #[inline]
184    pub fn times_italic(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
185        #[allow(deprecated)]
186        Self::new_built_in(document, PdfFontBuiltin::TimesItalic)
187    }
188
189    /// Creates a new [PdfFont] for the built-in "Times-BoldItalic" font.
190    ///
191    /// This function is now deprecated and will be removed in release 0.9.0.
192    /// Use the `PdfFonts::times_bold_italic()` function instead.
193    #[deprecated(
194        since = "0.8.1",
195        note = "This function has been moved. Use the PdfFonts::times_bold_italic() function instead."
196    )]
197    #[doc(hidden)]
198    #[inline]
199    pub fn times_bold_italic(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
200        #[allow(deprecated)]
201        Self::new_built_in(document, PdfFontBuiltin::TimesBoldItalic)
202    }
203
204    /// Creates a new [PdfFont] for the built-in "Helvetica" font.
205    ///
206    /// This function is now deprecated and will be removed in release 0.9.0.
207    /// Use the `PdfFonts::helvetica()` function instead.
208    #[deprecated(
209        since = "0.8.1",
210        note = "This function has been moved. Use the PdfFonts::helvetica() function instead."
211    )]
212    #[doc(hidden)]
213    #[inline]
214    pub fn helvetica(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
215        #[allow(deprecated)]
216        Self::new_built_in(document, PdfFontBuiltin::Helvetica)
217    }
218
219    /// Creates a new [PdfFont] for the built-in "Helvetica-Bold" font.
220    ///
221    /// This function is now deprecated and will be removed in release 0.9.0.
222    /// Use the `PdfFonts::helvetica_bold()` function instead.
223    #[deprecated(
224        since = "0.8.1",
225        note = "This function has been moved. Use the PdfFonts::helvetica_bold() function instead."
226    )]
227    #[doc(hidden)]
228    #[inline]
229    pub fn helvetica_bold(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
230        #[allow(deprecated)]
231        Self::new_built_in(document, PdfFontBuiltin::HelveticaBold)
232    }
233
234    /// Creates a new [PdfFont] for the built-in "Helvetica-Oblique" font.
235    ///
236    /// This function is now deprecated and will be removed in release 0.9.0.
237    /// Use the `PdfFonts::helvetica_oblique()` function instead.
238    #[deprecated(
239        since = "0.8.1",
240        note = "This function has been moved. Use the PdfFonts::helvetica_oblique() function instead."
241    )]
242    #[doc(hidden)]
243    #[inline]
244    pub fn helvetica_oblique(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
245        #[allow(deprecated)]
246        Self::new_built_in(document, PdfFontBuiltin::HelveticaOblique)
247    }
248
249    /// Creates a new [PdfFont] for the built-in "Helvetica-BoldOblique" font.
250    ///
251    /// This function is now deprecated and will be removed in release 0.9.0.
252    /// Use the `PdfFonts::helvetica_bold_oblique()` function instead.
253    #[deprecated(
254        since = "0.8.1",
255        note = "This function has been moved. Use the PdfFonts::helvetica_bold_oblique() function instead."
256    )]
257    #[doc(hidden)]
258    #[inline]
259    pub fn helvetica_bold_oblique(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
260        #[allow(deprecated)]
261        Self::new_built_in(document, PdfFontBuiltin::HelveticaBoldOblique)
262    }
263
264    /// Creates a new [PdfFont] for the built-in "Courier" font.
265    ///
266    /// This function is now deprecated and will be removed in release 0.9.0.
267    /// Use the `PdfFonts::courier()` function instead.
268    #[deprecated(
269        since = "0.8.1",
270        note = "This function has been moved. Use the PdfFonts::courier() function instead."
271    )]
272    #[doc(hidden)]
273    #[inline]
274    pub fn courier(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
275        #[allow(deprecated)]
276        Self::new_built_in(document, PdfFontBuiltin::Courier)
277    }
278
279    /// Creates a new [PdfFont] for the built-in "Courier-Bold" font.
280    ///
281    /// This function is now deprecated and will be removed in release 0.9.0.
282    /// Use the `PdfFonts::courier_bold()` function instead.
283    #[deprecated(
284        since = "0.8.1",
285        note = "This function has been moved. Use the PdfFonts::courier_bold() function instead."
286    )]
287    #[doc(hidden)]
288    #[inline]
289    pub fn courier_bold(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
290        #[allow(deprecated)]
291        Self::new_built_in(document, PdfFontBuiltin::CourierBold)
292    }
293
294    /// Creates a new [PdfFont] for the built-in "Courier-Oblique" font.
295    ///
296    /// This function is now deprecated and will be removed in release 0.9.0.
297    /// Use the `PdfFonts::courier_oblique()` function instead.
298    #[deprecated(
299        since = "0.8.1",
300        note = "This function has been moved. Use the PdfFonts::courier_oblique() function instead."
301    )]
302    #[doc(hidden)]
303    #[inline]
304    pub fn courier_oblique(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
305        #[allow(deprecated)]
306        Self::new_built_in(document, PdfFontBuiltin::CourierOblique)
307    }
308
309    /// Creates a new [PdfFont] for the built-in "Courier-BoldOblique" font.
310    ///
311    /// This function is now deprecated and will be removed in release 0.9.0.
312    /// Use the `PdfFonts::courier_bold_oblique()` function instead.
313    #[deprecated(
314        since = "0.8.1",
315        note = "This function has been moved. Use the PdfFonts::courier_bold_oblique() function instead."
316    )]
317    #[doc(hidden)]
318    #[inline]
319    pub fn courier_bold_oblique(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
320        #[allow(deprecated)]
321        Self::new_built_in(document, PdfFontBuiltin::CourierBoldOblique)
322    }
323
324    /// Creates a new [PdfFont] for the built-in "Symbol" font.
325    ///
326    /// This function is now deprecated and will be removed in release 0.9.0.
327    /// Use the `PdfFonts::symbol()` function instead.
328    #[deprecated(
329        since = "0.8.1",
330        note = "This function has been moved. Use the PdfFonts::symbol() function instead."
331    )]
332    #[doc(hidden)]
333    #[inline]
334    pub fn symbol(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
335        #[allow(deprecated)]
336        Self::new_built_in(document, PdfFontBuiltin::Symbol)
337    }
338
339    /// Creates a new [PdfFont] for the built-in "ZapfDingbats" font.
340    ///
341    /// This function is now deprecated and will be removed in release 0.9.0.
342    /// Use the `PdfFonts::zapf_dingbats()` function instead.
343    #[deprecated(
344        since = "0.8.1",
345        note = "This function has been moved. Use the PdfFonts::zapf_dingbats() function instead."
346    )]
347    #[doc(hidden)]
348    #[inline]
349    pub fn zapf_dingbats(document: &'a PdfDocument<'a>) -> PdfFont<'a> {
350        #[allow(deprecated)]
351        Self::new_built_in(document, PdfFontBuiltin::ZapfDingbats)
352    }
353
354    /// Attempts to load a Type 1 font file from the given file path.
355    ///
356    /// Set the `is_cid_font` parameter to `true` if the given font is keyed by
357    /// 16-bit character ID (CID), indicating that it supports an extended glyphset of
358    /// 65,535 glyphs. This is typically the case with fonts that support Asian character sets
359    /// or right-to-left languages.
360    ///
361    /// This function is not available when compiling to WASM. You have several options for
362    /// loading font data in WASM:
363    /// * Use the [PdfFonts::load_type1_from_fetch()] function to download font data from a
364    /// URL using the browser's built-in `fetch()` API. This function is only available when
365    /// compiling to WASM.
366    /// * Use the [PdfFonts::load_type1_from_blob()] function to load font data from a
367    /// Javascript File or Blob object (such as a File object returned from an HTML
368    /// `<input type="file">` element). This function is only available when compiling to WASM.
369    /// * Use the [PdfFonts::load_type1_from_reader()] function to load font data from any
370    /// valid Rust reader.
371    /// * Use another method to retrieve the bytes of the target font over the network,
372    /// then load those bytes into Pdfium using the [PdfFonts::new_type1_from_bytes()] function.
373    /// * Embed the bytes of the desired font directly into the compiled WASM module
374    /// using the `include_bytes!()` macro.
375    ///
376    /// This function is now deprecated and will be removed in release 0.9.0.
377    /// Use the `PdfFonts::load_type1_from_file()` function instead.
378    #[deprecated(
379        since = "0.8.1",
380        note = "This function has been moved. Use the PdfFonts::load_type1_from_file() function instead."
381    )]
382    #[doc(hidden)]
383    #[cfg(not(target_arch = "wasm32"))]
384    pub fn load_type1_from_file(
385        document: &'a PdfDocument<'a>,
386        path: &(impl AsRef<Path> + ?Sized),
387        is_cid_font: bool,
388    ) -> Result<PdfFont<'a>, PdfiumError> {
389        #[allow(deprecated)]
390        Self::load_type1_from_reader(
391            document,
392            File::open(path).map_err(PdfiumError::IoError)?,
393            is_cid_font,
394        )
395    }
396
397    /// Attempts to load a Type 1 font file from the given reader.
398    ///
399    /// Set the `is_cid_font` parameter to `true` if the given font is keyed by
400    /// 16-bit character ID (CID), indicating that it supports an extended glyphset of
401    /// 65,535 glyphs. This is typically the case with fonts that support Asian character sets
402    /// or right-to-left languages.
403    ///
404    /// This function is now deprecated and will be removed in release 0.9.0.
405    /// Use the `PdfFonts::load_type1_from_reader()` function instead.
406    #[deprecated(
407        since = "0.8.1",
408        note = "This function has been moved. Use the PdfFonts::load_type1_from_reader() function instead."
409    )]
410    #[doc(hidden)]
411    pub fn load_type1_from_reader(
412        document: &'a PdfDocument<'a>,
413        mut reader: impl Read,
414        is_cid_font: bool,
415    ) -> Result<PdfFont<'a>, PdfiumError> {
416        let mut bytes = Vec::new();
417
418        reader
419            .read_to_end(&mut bytes)
420            .map_err(PdfiumError::IoError)?;
421
422        #[allow(deprecated)]
423        Self::new_type1_from_bytes(document, bytes.as_slice(), is_cid_font)
424    }
425
426    /// Attempts to load a Type 1 font file from the given URL.
427    /// The Javascript `fetch()` API is used to download data over the network.
428    ///
429    /// Set the `is_cid_font` parameter to `true` if the given font is keyed by
430    /// 16-bit character ID (CID), indicating that it supports an extended glyphset of
431    /// 65,535 glyphs. This is typically the case with fonts that support Asian character sets
432    /// or right-to-left languages.
433    ///
434    /// This function is only available when compiling to WASM.
435    ///
436    /// This function is now deprecated and will be removed in release 0.9.0.
437    /// Use the `PdfFonts::load_type1_from_fetch()` function instead.
438    #[deprecated(
439        since = "0.8.1",
440        note = "This function has been moved. Use the PdfFonts::load_type1_from_fetch() function instead."
441    )]
442    #[doc(hidden)]
443    #[cfg(any(doc, target_arch = "wasm32"))]
444    pub async fn load_type1_from_fetch(
445        document: &'a PdfDocument<'a>,
446        url: impl ToString,
447        is_cid_font: bool,
448    ) -> Result<PdfFont<'a>, PdfiumError> {
449        if let Some(window) = window() {
450            let fetch_result = JsFuture::from(window.fetch_with_str(url.to_string().as_str()))
451                .await
452                .map_err(PdfiumError::WebSysFetchError)?;
453
454            debug_assert!(fetch_result.is_instance_of::<Response>());
455
456            let response: Response = fetch_result
457                .dyn_into()
458                .map_err(|_| PdfiumError::WebSysInvalidResponseError)?;
459
460            let blob: Blob =
461                JsFuture::from(response.blob().map_err(PdfiumError::WebSysFetchError)?)
462                    .await
463                    .map_err(PdfiumError::WebSysFetchError)?
464                    .into();
465
466            #[allow(deprecated)]
467            Self::load_type1_from_blob(document, blob, is_cid_font).await
468        } else {
469            Err(PdfiumError::WebSysWindowObjectNotAvailable)
470        }
471    }
472
473    /// Attempts to load a Type 1 font from the given Blob.
474    /// A File object returned from a FileList is a suitable Blob:
475    ///
476    /// ```text
477    /// <input id="filePicker" type="file">
478    ///
479    /// const file = document.getElementById('filePicker').files[0];
480    /// ```
481    ///
482    /// Set the `is_cid_font` parameter to `true` if the given font is keyed by
483    /// 16-bit character ID (CID), indicating that it supports an extended glyphset of
484    /// 65,535 glyphs. This is typically the case with fonts that support Asian character sets
485    /// or right-to-left languages.
486    ///
487    /// This function is only available when compiling to WASM.
488    ///
489    /// This function is now deprecated and will be removed in release 0.9.0.
490    /// Use the `PdfFonts::load_type1_from_blob()` function instead.
491    #[deprecated(
492        since = "0.8.1",
493        note = "This function has been moved. Use the PdfFonts::load_type1_from_blob() function instead."
494    )]
495    #[doc(hidden)]
496    #[cfg(any(doc, target_arch = "wasm32"))]
497    pub async fn load_type1_from_blob(
498        document: &'a PdfDocument<'a>,
499        blob: Blob,
500        is_cid_font: bool,
501    ) -> Result<PdfFont<'a>, PdfiumError> {
502        let array_buffer: ArrayBuffer = JsFuture::from(blob.array_buffer())
503            .await
504            .map_err(PdfiumError::WebSysFetchError)?
505            .into();
506
507        let u8_array: Uint8Array = Uint8Array::new(&array_buffer);
508
509        let bytes: Vec<u8> = u8_array.to_vec();
510
511        #[allow(deprecated)]
512        Self::new_type1_from_bytes(document, bytes.as_slice(), is_cid_font)
513    }
514
515    /// Attempts to load the given byte data as a Type 1 font file.
516    ///
517    /// Set the `is_cid_font` parameter to `true` if the given font is keyed by
518    /// 16-bit character ID (CID), indicating that it supports an extended glyphset of
519    /// 65,535 glyphs. This is typically the case with fonts that support Asian character sets
520    /// or right-to-left languages.
521    ///
522    /// This function is now deprecated and will be removed in release 0.9.0.
523    /// Use the `PdfFonts::load_type1_from_bytes()` function instead.
524    #[deprecated(
525        since = "0.8.1",
526        note = "This function has been moved. Use the PdfFonts::load_type1_from_bytes() function instead."
527    )]
528    #[doc(hidden)]
529    pub fn new_type1_from_bytes(
530        document: &'a PdfDocument<'a>,
531        font_data: &[u8],
532        is_cid_font: bool,
533    ) -> Result<PdfFont<'a>, PdfiumError> {
534        Self::new_font_from_bytes(document, font_data, FPDF_FONT_TYPE1, is_cid_font)
535    }
536
537    /// Attempts to load a TrueType font file from the given file path.
538    ///
539    /// Set the `is_cid_font` parameter to `true` if the given font is keyed by
540    /// 16-bit character ID (CID), indicating that it supports an extended glyphset of
541    /// 65,535 glyphs. This is typically the case with fonts that support Asian character sets
542    /// or right-to-left languages.
543    ///
544    /// This function is not available when compiling to WASM. You have several options for
545    /// loading font data in WASM:
546    /// * Use the [PdfFonts::load_true_type_from_fetch()] function to download font data from a
547    /// URL using the browser's built-in `fetch()` API. This function is only available when
548    /// compiling to WASM.
549    /// * Use the [PdfFonts::load_true_type_from_blob()] function to load font data from a
550    /// Javascript `File` or `Blob` object (such as a `File` object returned from an HTML
551    /// `<input type="file">` element). This function is only available when compiling to WASM.
552    /// * Use the [PdfFonts::load_true_type_from_reader()] function to load font data from any
553    /// valid Rust reader.
554    /// * Use another method to retrieve the bytes of the target font over the network,
555    /// then load those bytes into Pdfium using the [PdfFonts::new_true_type_from_bytes()] function.
556    /// * Embed the bytes of the desired font directly into the compiled WASM module
557    /// using the `include_bytes!()` macro.
558    ///
559    /// This function is now deprecated and will be removed in release 0.9.0.
560    /// Use the `PdfFonts::load_true_type_from_file()` function instead.
561    #[deprecated(
562        since = "0.8.1",
563        note = "This function has been moved. Use the PdfFonts::load_true_type_from_file() function instead."
564    )]
565    #[doc(hidden)]
566    #[cfg(not(target_arch = "wasm32"))]
567    pub fn load_true_type_from_file(
568        document: &'a PdfDocument<'a>,
569        path: &(impl AsRef<Path> + ?Sized),
570        is_cid_font: bool,
571    ) -> Result<PdfFont<'a>, PdfiumError> {
572        #[allow(deprecated)]
573        Self::load_true_type_from_reader(
574            document,
575            File::open(path).map_err(PdfiumError::IoError)?,
576            is_cid_font,
577        )
578    }
579
580    /// Attempts to load a TrueType font file from the given reader.
581    ///
582    /// Set the `is_cid_font` parameter to `true` if the given font is keyed by
583    /// 16-bit character ID (CID), indicating that it supports an extended glyphset of
584    /// 65,535 glyphs. This is typically the case with fonts that support Asian character sets
585    /// or right-to-left languages.
586    ///
587    /// This function is now deprecated and will be removed in release 0.9.0.
588    /// Use the `PdfFonts::load_true_type_from_reader()` function instead.
589    #[deprecated(
590        since = "0.8.1",
591        note = "This function has been moved. Use the PdfFonts::load_true_type_from_reader() function instead."
592    )]
593    #[doc(hidden)]
594    pub fn load_true_type_from_reader(
595        document: &'a PdfDocument<'a>,
596        mut reader: impl Read,
597        is_cid_font: bool,
598    ) -> Result<PdfFont<'a>, PdfiumError> {
599        let mut bytes = Vec::new();
600
601        reader
602            .read_to_end(&mut bytes)
603            .map_err(PdfiumError::IoError)?;
604
605        #[allow(deprecated)]
606        Self::new_true_type_from_bytes(document, bytes.as_slice(), is_cid_font)
607    }
608
609    /// Attempts to load a TrueType font file from the given URL.
610    /// The Javascript `fetch()` API is used to download data over the network.
611    ///
612    /// Set the `is_cid_font` parameter to `true` if the given font is keyed by
613    /// 16-bit character ID (CID), indicating that it supports an extended glyphset of
614    /// 65,535 glyphs. This is typically the case with fonts that support Asian character sets
615    /// or right-to-left languages.
616    ///
617    /// This function is only available when compiling to WASM.
618    ///
619    /// This function is now deprecated and will be removed in release 0.9.0.
620    /// Use the `PdfFonts::load_true_type_from_fetch()` function instead.
621    #[deprecated(
622        since = "0.8.1",
623        note = "This function has been moved. Use the PdfFonts::load_true_type_from_fetch() function instead."
624    )]
625    #[doc(hidden)]
626    #[cfg(any(doc, target_arch = "wasm32"))]
627    pub async fn load_true_type_from_fetch(
628        document: &'a PdfDocument<'a>,
629        url: impl ToString,
630        is_cid_font: bool,
631    ) -> Result<PdfFont<'a>, PdfiumError> {
632        if let Some(window) = window() {
633            let fetch_result = JsFuture::from(window.fetch_with_str(url.to_string().as_str()))
634                .await
635                .map_err(PdfiumError::WebSysFetchError)?;
636
637            debug_assert!(fetch_result.is_instance_of::<Response>());
638
639            let response: Response = fetch_result
640                .dyn_into()
641                .map_err(|_| PdfiumError::WebSysInvalidResponseError)?;
642
643            let blob: Blob =
644                JsFuture::from(response.blob().map_err(PdfiumError::WebSysFetchError)?)
645                    .await
646                    .map_err(PdfiumError::WebSysFetchError)?
647                    .into();
648
649            #[allow(deprecated)]
650            Self::load_true_type_from_blob(document, blob, is_cid_font).await
651        } else {
652            Err(PdfiumError::WebSysWindowObjectNotAvailable)
653        }
654    }
655
656    /// Attempts to load a TrueType font from the given `Blob`.
657    /// A `File` object returned from a `FileList` is a suitable `Blob`:
658    ///
659    /// ```text
660    /// <input id="filePicker" type="file">
661    ///
662    /// const file = document.getElementById('filePicker').files[0];
663    /// ```
664    ///
665    /// Set the `is_cid_font` parameter to `true` if the given font is keyed by
666    /// 16-bit character ID (CID), indicating that it supports an extended glyphset of
667    /// 65,535 glyphs. This is typically the case with fonts that support Asian character sets
668    /// or right-to-left languages.
669    ///
670    /// This function is only available when compiling to WASM.
671    ///
672    /// This function is now deprecated and will be removed in release 0.9.0.
673    /// Use the `PdfFonts::load_true_type_from_blob()` function instead.
674    #[deprecated(
675        since = "0.8.1",
676        note = "This function has been moved. Use the PdfFonts::load_true_type_from_blob() function instead."
677    )]
678    #[doc(hidden)]
679    #[cfg(any(doc, target_arch = "wasm32"))]
680    pub async fn load_true_type_from_blob(
681        document: &'a PdfDocument<'a>,
682        blob: Blob,
683        is_cid_font: bool,
684    ) -> Result<PdfFont<'a>, PdfiumError> {
685        let array_buffer: ArrayBuffer = JsFuture::from(blob.array_buffer())
686            .await
687            .map_err(PdfiumError::WebSysFetchError)?
688            .into();
689
690        let u8_array: Uint8Array = Uint8Array::new(&array_buffer);
691
692        let bytes: Vec<u8> = u8_array.to_vec();
693
694        #[allow(deprecated)]
695        Self::new_true_type_from_bytes(document, bytes.as_slice(), is_cid_font)
696    }
697
698    /// Attempts to load the given byte data as a TrueType font file.
699    ///
700    /// Set the `is_cid_font` parameter to `true` if the given font is keyed by
701    /// 16-bit character ID (CID), indicating that it supports an extended glyphset of
702    /// 65,535 glyphs. This is typically the case with fonts that support Asian character sets
703    /// or right-to-left languages.
704    ///
705    /// This function is now deprecated and will be removed in release 0.9.0.
706    /// Use the `PdfFonts::load_true_type_from_bytes()` function instead.
707    #[deprecated(
708        since = "0.8.1",
709        note = "This function has been moved. Use the PdfFonts::load_true_type_from_bytes() function instead."
710    )]
711    #[doc(hidden)]
712    pub fn new_true_type_from_bytes(
713        document: &'a PdfDocument<'a>,
714        font_data: &[u8],
715        is_cid_font: bool,
716    ) -> Result<PdfFont<'a>, PdfiumError> {
717        Self::new_font_from_bytes(document, font_data, FPDF_FONT_TRUETYPE, is_cid_font)
718    }
719
720    #[inline]
721    pub(crate) fn new_font_from_bytes(
722        document: &'a PdfDocument<'a>,
723        font_data: &[u8],
724        font_type: c_uint,
725        is_cid_font: bool,
726    ) -> Result<PdfFont<'a>, PdfiumError> {
727        let handle = document.bindings().FPDFText_LoadFont(
728            document.handle(),
729            font_data.as_ptr(),
730            font_data.len() as c_uint,
731            font_type as c_int,
732            document.bindings().bool_to_pdfium(is_cid_font),
733        );
734
735        if handle.is_null() {
736            Err(PdfiumError::PdfiumLibraryInternalError(
737                PdfiumInternalError::Unknown,
738            ))
739        } else {
740            Ok(PdfFont::from_pdfium(
741                handle,
742                document.bindings(),
743                None,
744                true,
745            ))
746        }
747    }
748
749    /// Returns the internal `FPDF_FONT` handle for this [PdfFont].
750    #[inline]
751    pub(crate) fn handle(&self) -> FPDF_FONT {
752        self.handle
753    }
754
755    /// Returns the [PdfiumLibraryBindings] used by this [PdfFont].
756    #[inline]
757    pub fn bindings(&self) -> &'a dyn PdfiumLibraryBindings {
758        self.bindings
759    }
760
761    #[cfg(any(
762        feature = "pdfium_6611",
763        feature = "pdfium_6569",
764        feature = "pdfium_6555",
765        feature = "pdfium_6490",
766        feature = "pdfium_6406",
767        feature = "pdfium_6337",
768        feature = "pdfium_6295",
769        feature = "pdfium_6259",
770        feature = "pdfium_6164",
771        feature = "pdfium_6124",
772        feature = "pdfium_6110",
773        feature = "pdfium_6084",
774        feature = "pdfium_6043",
775        feature = "pdfium_6015",
776        feature = "pdfium_5961"
777    ))]
778    #[inline]
779    #[deprecated(
780        since = "0.8.22",
781        note = "This function has been renamed in line with upstream Pdfium. Use the PdfFont::family() function instead."
782    )]
783    /// Returns the name of this [PdfFont].
784    pub fn name(&self) -> String {
785        self.family()
786    }
787
788    #[cfg(any(
789        feature = "pdfium_future",
790        feature = "pdfium_7350",
791        feature = "pdfium_7215",
792        feature = "pdfium_7123",
793        feature = "pdfium_6996",
794        feature = "pdfium_6721",
795        feature = "pdfium_6666"
796    ))]
797    /// Returns the name of this [PdfFont].
798    pub fn name(&self) -> String {
799        // Retrieving the font name from Pdfium is a two-step operation. First, we call
800        // FPDFFont_GetBaseFontName() with a null buffer; this will retrieve the length of
801        // the font name in bytes. If the length is zero, then there is no font name.
802
803        // If the length is non-zero, then we reserve a byte buffer of the given
804        // length and call FPDFFont_GetBaseFontName() again with a pointer to the buffer;
805        // this will write the font name into the buffer. Unlike most text handling in
806        // Pdfium, font names are returned in UTF-8 format.
807
808        let buffer_length =
809            self.bindings
810                .FPDFFont_GetBaseFontName(self.handle, std::ptr::null_mut(), 0);
811
812        if buffer_length == 0 {
813            // The font name is not present.
814
815            return String::new();
816        }
817
818        let mut buffer = create_byte_buffer(buffer_length as usize);
819
820        let result = self.bindings.FPDFFont_GetBaseFontName(
821            self.handle,
822            buffer.as_mut_ptr() as *mut c_char,
823            buffer_length,
824        );
825
826        assert_eq!(result, buffer_length);
827
828        String::from_utf8(buffer)
829            // Trim any trailing nulls. All strings returned from Pdfium are generally terminated
830            // by one null byte.
831            .map(|str| str.trim_end_matches(char::from(0)).to_owned())
832            .unwrap_or_else(|_| String::new())
833    }
834
835    /// Returns the family of this [PdfFont].
836    pub fn family(&self) -> String {
837        // Retrieving the family name from Pdfium is a two-step operation. First, we call
838        // FPDFFont_GetFamilyName() with a null buffer; this will retrieve the length of
839        // the font name in bytes. If the length is zero, then there is no font name.
840
841        // If the length is non-zero, then we reserve a byte buffer of the given
842        // length and call FPDFFont_GetFamilyName() again with a pointer to the buffer;
843        // this will write the font name into the buffer. Unlike most text handling in
844        // Pdfium, font names are returned in UTF-8 format.
845
846        #[cfg(any(
847            feature = "pdfium_future",
848            feature = "pdfium_7350",
849            feature = "pdfium_7215",
850            feature = "pdfium_7123",
851            feature = "pdfium_6996",
852            feature = "pdfium_6721",
853            feature = "pdfium_6666",
854            feature = "pdfium_6611"
855        ))]
856        let buffer_length =
857            self.bindings
858                .FPDFFont_GetFamilyName(self.handle, std::ptr::null_mut(), 0);
859
860        #[cfg(any(
861            feature = "pdfium_6569",
862            feature = "pdfium_6555",
863            feature = "pdfium_6490",
864            feature = "pdfium_6406",
865            feature = "pdfium_6337",
866            feature = "pdfium_6295",
867            feature = "pdfium_6259",
868            feature = "pdfium_6164",
869            feature = "pdfium_6124",
870            feature = "pdfium_6110",
871            feature = "pdfium_6084",
872            feature = "pdfium_6043",
873            feature = "pdfium_6015",
874            feature = "pdfium_5961"
875        ))]
876        let buffer_length =
877            self.bindings
878                .FPDFFont_GetFontName(self.handle, std::ptr::null_mut(), 0);
879
880        if buffer_length == 0 {
881            // The font name is not present.
882
883            return String::new();
884        }
885
886        let mut buffer = create_byte_buffer(buffer_length as usize);
887
888        #[cfg(any(
889            feature = "pdfium_future",
890            feature = "pdfium_7350",
891            feature = "pdfium_7215",
892            feature = "pdfium_7123",
893            feature = "pdfium_6996",
894            feature = "pdfium_6721",
895            feature = "pdfium_6666",
896            feature = "pdfium_6611"
897        ))]
898        let result = self.bindings.FPDFFont_GetFamilyName(
899            self.handle,
900            buffer.as_mut_ptr() as *mut c_char,
901            buffer_length,
902        );
903
904        #[cfg(any(
905            feature = "pdfium_6569",
906            feature = "pdfium_6555",
907            feature = "pdfium_6490",
908            feature = "pdfium_6406",
909            feature = "pdfium_6337",
910            feature = "pdfium_6295",
911            feature = "pdfium_6259",
912            feature = "pdfium_6164",
913            feature = "pdfium_6124",
914            feature = "pdfium_6110",
915            feature = "pdfium_6084",
916            feature = "pdfium_6043",
917            feature = "pdfium_6015",
918            feature = "pdfium_5961"
919        ))]
920        let result = self.bindings.FPDFFont_GetFontName(
921            self.handle,
922            buffer.as_mut_ptr() as *mut c_char,
923            buffer_length,
924        );
925
926        assert_eq!(result, buffer_length);
927
928        String::from_utf8(buffer)
929            // Trim any trailing nulls. All strings returned from Pdfium are generally terminated
930            // by one null byte.
931            .map(|str| str.trim_end_matches(char::from(0)).to_owned())
932            .unwrap_or_else(|_| String::new())
933    }
934
935    /// Returns the weight of this [PdfFont].
936    ///
937    /// Pdfium may not reliably return the correct value of this property for built-in fonts.
938    pub fn weight(&self) -> Result<PdfFontWeight, PdfiumError> {
939        PdfFontWeight::from_pdfium(self.bindings.FPDFFont_GetWeight(self.handle)).ok_or(
940            PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown),
941        )
942    }
943
944    /// Returns the italic angle of this [PdfFont]. The italic angle is the angle,
945    /// expressed in degrees counter-clockwise from the vertical, of the dominant vertical
946    /// strokes of the font. The value is zero for non-italic fonts, and negative for fonts
947    /// that slope to the right (as almost all italic fonts do).
948    ///
949    /// Pdfium may not reliably return the correct value of this property for built-in fonts.
950    pub fn italic_angle(&self) -> Result<i32, PdfiumError> {
951        let mut angle = 0;
952
953        if self.bindings.is_true(
954            self.bindings
955                .FPDFFont_GetItalicAngle(self.handle, &mut angle),
956        ) {
957            Ok(angle)
958        } else {
959            Err(PdfiumError::PdfiumLibraryInternalError(
960                PdfiumInternalError::Unknown,
961            ))
962        }
963    }
964
965    /// Returns the ascent of this [PdfFont] for the given font size. The ascent is the maximum
966    /// height above the baseline reached by glyphs in this font, excluding the height of glyphs
967    /// for accented characters.
968    pub fn ascent(&self, font_size: PdfPoints) -> Result<PdfPoints, PdfiumError> {
969        let mut ascent = 0.0;
970
971        if self.bindings.is_true(self.bindings.FPDFFont_GetAscent(
972            self.handle,
973            font_size.value,
974            &mut ascent,
975        )) {
976            Ok(PdfPoints::new(ascent))
977        } else {
978            Err(PdfiumError::PdfiumLibraryInternalError(
979                PdfiumInternalError::Unknown,
980            ))
981        }
982    }
983
984    /// Returns the descent of this [PdfFont] for the given font size. The descent is the
985    /// maximum distance below the baseline reached by glyphs in this font, expressed as a
986    /// negative points value.
987    pub fn descent(&self, font_size: PdfPoints) -> Result<PdfPoints, PdfiumError> {
988        let mut descent = 0.0;
989
990        if self.bindings.is_true(self.bindings.FPDFFont_GetDescent(
991            self.handle,
992            font_size.value,
993            &mut descent,
994        )) {
995            Ok(PdfPoints::new(descent))
996        } else {
997            Err(PdfiumError::PdfiumLibraryInternalError(
998                PdfiumInternalError::Unknown,
999            ))
1000        }
1001    }
1002
1003    /// Returns the raw font descriptor bitflags for the containing [PdfFont].
1004    #[inline]
1005    fn get_flags_bits(&self) -> FpdfFontDescriptorFlags {
1006        FpdfFontDescriptorFlags::from_bits_truncate(
1007            self.bindings.FPDFFont_GetFlags(self.handle) as u32
1008        )
1009    }
1010
1011    /// Returns `true` if all the glyphs in this [PdfFont] have the same width.
1012    ///
1013    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
1014    pub fn is_fixed_pitch(&self) -> bool {
1015        self.get_flags_bits()
1016            .contains(FpdfFontDescriptorFlags::FIXED_PITCH_BIT_1)
1017    }
1018
1019    /// Returns `true` if the glyphs in this [PdfFont] have variable widths.
1020    ///
1021    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
1022    #[inline]
1023    pub fn is_proportional_pitch(&self) -> bool {
1024        !self.is_fixed_pitch()
1025    }
1026
1027    /// Returns `true` if one or more glyphs in this [PdfFont] have serifs - short strokes
1028    /// drawn at an angle on the top or bottom of glyph stems to decorate the glyphs.
1029    /// For example, Times New Roman is a serif font.
1030    ///
1031    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
1032    pub fn is_serif(&self) -> bool {
1033        self.get_flags_bits()
1034            .contains(FpdfFontDescriptorFlags::SERIF_BIT_2)
1035    }
1036
1037    /// Returns `true` if no glyphs in this [PdfFont] have serifs - short strokes
1038    /// drawn at an angle on the top or bottom of glyph stems to decorate the glyphs.
1039    /// For example, Helvetica is a sans-serif font.
1040    ///
1041    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
1042    #[inline]
1043    pub fn is_sans_serif(&self) -> bool {
1044        !self.is_serif()
1045    }
1046
1047    /// Returns `true` if this [PdfFont] contains glyphs outside the Adobe standard Latin
1048    /// character set.
1049    ///
1050    /// This classification of non-symbolic and symbolic fonts is peculiar to PDF. A font may
1051    /// contain additional characters that are used in Latin writing systems but are outside the
1052    /// Adobe standard Latin character set; PDF considers such a font to be symbolic.
1053    ///
1054    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
1055    pub fn is_symbolic(&self) -> bool {
1056        // This flag bit and the non-symbolic flag bit cannot both be set or both be clear.
1057
1058        self.get_flags_bits()
1059            .contains(FpdfFontDescriptorFlags::SYMBOLIC_BIT_3)
1060    }
1061
1062    /// Returns `true` if this [PdfFont] does not contain glyphs outside the Adobe standard
1063    /// Latin character set.
1064    ///
1065    /// This classification of non-symbolic and symbolic fonts is peculiar to PDF. A font may
1066    /// contain additional characters that are used in Latin writing systems but are outside the
1067    /// Adobe standard Latin character set; PDF considers such a font to be symbolic.
1068    ///
1069    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
1070    pub fn is_non_symbolic(&self) -> bool {
1071        // This flag bit and the symbolic flag bit cannot both be set or both be clear.
1072
1073        self.get_flags_bits()
1074            .contains(FpdfFontDescriptorFlags::NON_SYMBOLIC_BIT_6)
1075    }
1076
1077    /// Returns `true` if the glyphs in this [PdfFont] are designed to resemble cursive handwriting.
1078    ///
1079    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
1080    pub fn is_cursive(&self) -> bool {
1081        self.get_flags_bits()
1082            .contains(FpdfFontDescriptorFlags::SCRIPT_BIT_4)
1083    }
1084
1085    /// Returns `true` if the glyphs in this [PdfFont] include dominant vertical strokes
1086    /// that are slanted.
1087    ///
1088    /// The designed vertical stroke angle can be retrieved using the [PdfFont::italic_angle()] function.
1089    ///
1090    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
1091    pub fn is_italic(&self) -> bool {
1092        self.get_flags_bits()
1093            .contains(FpdfFontDescriptorFlags::ITALIC_BIT_7)
1094    }
1095
1096    /// Returns `true` if this [PdfFont] contains no lowercase letters by design.
1097    ///
1098    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
1099    pub fn is_all_caps(&self) -> bool {
1100        self.get_flags_bits()
1101            .contains(FpdfFontDescriptorFlags::ALL_CAP_BIT_17)
1102    }
1103
1104    /// Returns `true` if the lowercase letters in this [PdfFont] have the same shapes as the
1105    /// corresponding uppercase letters but are sized proportionally so they have the same size
1106    /// and stroke weight as lowercase glyphs in the same typeface family.
1107    ///
1108    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
1109    pub fn is_small_caps(&self) -> bool {
1110        self.get_flags_bits()
1111            .contains(FpdfFontDescriptorFlags::SMALL_CAP_BIT_18)
1112    }
1113
1114    /// Returns `true` if bold glyphs in this [PdfFont] are painted with extra pixels
1115    /// at very small font sizes.
1116    ///
1117    /// Typically when glyphs are painted at small sizes on low-resolution devices, individual strokes
1118    /// of bold glyphs may appear only one pixel wide. Because this is the minimum width of a pixel
1119    /// based device, individual strokes of non-bold glyphs may also appear as one pixel wide
1120    /// and therefore cannot be distinguished from bold glyphs. If this flag is set, individual
1121    /// strokes of bold glyphs may be thickened at small font sizes.
1122    ///
1123    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
1124    pub fn is_bold_reenforced(&self) -> bool {
1125        self.get_flags_bits()
1126            .contains(FpdfFontDescriptorFlags::FORCE_BOLD_BIT_19)
1127    }
1128
1129    /// Returns `true` if this [PdfFont] is an instance of one of the 14 built-in fonts
1130    /// provided as part of the PDF specification.
1131    #[inline]
1132    pub fn is_built_in(&self) -> bool {
1133        self.built_in.is_some()
1134    }
1135
1136    /// Returns the [PdfFontBuiltin] type of this built-in font, or `None` if this font is
1137    /// not one of the 14 built-in fonts provided as part of the PDF specification.
1138    #[inline]
1139    pub fn built_in(&self) -> Option<PdfFontBuiltin> {
1140        self.built_in
1141    }
1142
1143    /// Returns `true` if the data for this [PdfFont] is embedded in the containing [PdfDocument].
1144    pub fn is_embedded(&self) -> Result<bool, PdfiumError> {
1145        let result = self.bindings.FPDFFont_GetIsEmbedded(self.handle);
1146
1147        match result {
1148            1 => Ok(true),
1149            0 => Ok(false),
1150            _ => Err(PdfiumError::PdfiumLibraryInternalError(
1151                PdfiumInternalError::Unknown,
1152            )),
1153        }
1154    }
1155
1156    /// Writes this [PdfFont] to a new byte buffer, returning the byte buffer.
1157    ///
1158    /// If this [PdfFont] is not embedded in the containing [PdfDocument], then the data
1159    /// returned will be for the substitution font instead.
1160    pub fn data(&self) -> Result<Vec<u8>, PdfiumError> {
1161        // Retrieving the font data from Pdfium is a two-step operation. First, we call
1162        // FPDFFont_GetFontData() with a null buffer; this will retrieve the length of
1163        // the data in bytes. If the length is zero, then there is no data associated
1164        // with this font.
1165
1166        // If the length is non-zero, then we reserve a byte buffer of the given
1167        // length and call FPDFFont_GetFontData() again with a pointer to the buffer;
1168        // this will write the font data to the buffer.
1169
1170        let mut out_buflen: usize = 0;
1171
1172        if self
1173            .bindings()
1174            .is_true(self.bindings().FPDFFont_GetFontData(
1175                self.handle,
1176                std::ptr::null_mut(),
1177                0,
1178                &mut out_buflen,
1179            ))
1180        {
1181            // out_buflen now contains the length of the font data.
1182
1183            let buffer_length = out_buflen;
1184
1185            let mut buffer = create_byte_buffer(buffer_length);
1186
1187            let result = self.bindings().FPDFFont_GetFontData(
1188                self.handle,
1189                buffer.as_mut_ptr(),
1190                buffer_length,
1191                &mut out_buflen,
1192            );
1193
1194            assert!(self.bindings.is_true(result));
1195            assert_eq!(buffer_length, out_buflen);
1196
1197            Ok(buffer)
1198        } else {
1199            Err(PdfiumError::PdfiumLibraryInternalError(
1200                PdfiumInternalError::Unknown,
1201            ))
1202        }
1203    }
1204
1205    /// Returns a collection of all the [PdfFontGlyphs] defined for this [PdfFont] in the containing
1206    /// `PdfDocument`.
1207    ///
1208    /// Note that documents typically include only the specific glyphs they need from any given font,
1209    /// not the entire font glyphset. This is a PDF feature known as font subsetting. The collection
1210    /// of glyphs returned by this function may therefore not cover the entire font glyphset.
1211    #[inline]
1212    pub fn glyphs(&self) -> &PdfFontGlyphs {
1213        self.glyphs.initialize_len();
1214        &self.glyphs
1215    }
1216}
1217
1218impl<'a> Drop for PdfFont<'a> {
1219    /// Closes this [PdfFont], releasing held memory.
1220    #[inline]
1221    fn drop(&mut self) {
1222        // The documentation for FPDFText_LoadFont() and FPDFText_LoadStandardFont() both state
1223        // that the font loaded by the function can be closed by calling FPDFFont_Close().
1224        // I had taken this to mean that _any_ FPDF_Font handle returned from a Pdfium function
1225        // should be closed via FPDFFont_Close(), but testing suggests this is not the case;
1226        // rather, it is only fonts specifically loaded by calling FPDFText_LoadFont() or
1227        // FPDFText_LoadStandardFont() that need to be actively closed.
1228
1229        // In other words, retrieving a handle to a font that already exists in a document evidently
1230        // does not allocate any additional resources, so we don't need to free anything.
1231        // (Indeed, if we try to, Pdfium segfaults.)
1232
1233        if self.is_font_memory_loaded {
1234            self.bindings.FPDFFont_Close(self.handle);
1235        }
1236    }
1237}