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_7123",
791        feature = "pdfium_6996",
792        feature = "pdfium_6721",
793        feature = "pdfium_6666"
794    ))]
795    /// Returns the name of this [PdfFont].
796    pub fn name(&self) -> String {
797        // Retrieving the font name from Pdfium is a two-step operation. First, we call
798        // FPDFFont_GetBaseFontName() with a null buffer; this will retrieve the length of
799        // the font name in bytes. If the length is zero, then there is no font name.
800
801        // If the length is non-zero, then we reserve a byte buffer of the given
802        // length and call FPDFFont_GetBaseFontName() again with a pointer to the buffer;
803        // this will write the font name into the buffer. Unlike most text handling in
804        // Pdfium, font names are returned in UTF-8 format.
805
806        let buffer_length =
807            self.bindings
808                .FPDFFont_GetBaseFontName(self.handle, std::ptr::null_mut(), 0);
809
810        if buffer_length == 0 {
811            // The font name is not present.
812
813            return String::new();
814        }
815
816        let mut buffer = create_byte_buffer(buffer_length as usize);
817
818        let result = self.bindings.FPDFFont_GetBaseFontName(
819            self.handle,
820            buffer.as_mut_ptr() as *mut c_char,
821            buffer_length,
822        );
823
824        assert_eq!(result, buffer_length);
825
826        String::from_utf8(buffer)
827            // Trim any trailing nulls. All strings returned from Pdfium are generally terminated
828            // by one null byte.
829            .map(|str| str.trim_end_matches(char::from(0)).to_owned())
830            .unwrap_or_else(|_| String::new())
831    }
832
833    /// Returns the family of this [PdfFont].
834    pub fn family(&self) -> String {
835        // Retrieving the family name from Pdfium is a two-step operation. First, we call
836        // FPDFFont_GetFamilyName() with a null buffer; this will retrieve the length of
837        // the font name in bytes. If the length is zero, then there is no font name.
838
839        // If the length is non-zero, then we reserve a byte buffer of the given
840        // length and call FPDFFont_GetFamilyName() again with a pointer to the buffer;
841        // this will write the font name into the buffer. Unlike most text handling in
842        // Pdfium, font names are returned in UTF-8 format.
843
844        #[cfg(any(
845            feature = "pdfium_future",
846            feature = "pdfium_7123",
847            feature = "pdfium_6996",
848            feature = "pdfium_6721",
849            feature = "pdfium_6666",
850            feature = "pdfium_6611"
851        ))]
852        let buffer_length =
853            self.bindings
854                .FPDFFont_GetFamilyName(self.handle, std::ptr::null_mut(), 0);
855
856        #[cfg(any(
857            feature = "pdfium_6569",
858            feature = "pdfium_6555",
859            feature = "pdfium_6490",
860            feature = "pdfium_6406",
861            feature = "pdfium_6337",
862            feature = "pdfium_6295",
863            feature = "pdfium_6259",
864            feature = "pdfium_6164",
865            feature = "pdfium_6124",
866            feature = "pdfium_6110",
867            feature = "pdfium_6084",
868            feature = "pdfium_6043",
869            feature = "pdfium_6015",
870            feature = "pdfium_5961"
871        ))]
872        let buffer_length =
873            self.bindings
874                .FPDFFont_GetFontName(self.handle, std::ptr::null_mut(), 0);
875
876        if buffer_length == 0 {
877            // The font name is not present.
878
879            return String::new();
880        }
881
882        let mut buffer = create_byte_buffer(buffer_length as usize);
883
884        #[cfg(any(
885            feature = "pdfium_future",
886            feature = "pdfium_7123",
887            feature = "pdfium_6996",
888            feature = "pdfium_6721",
889            feature = "pdfium_6666",
890            feature = "pdfium_6611"
891        ))]
892        let result = self.bindings.FPDFFont_GetFamilyName(
893            self.handle,
894            buffer.as_mut_ptr() as *mut c_char,
895            buffer_length,
896        );
897
898        #[cfg(any(
899            feature = "pdfium_6569",
900            feature = "pdfium_6555",
901            feature = "pdfium_6490",
902            feature = "pdfium_6406",
903            feature = "pdfium_6337",
904            feature = "pdfium_6295",
905            feature = "pdfium_6259",
906            feature = "pdfium_6164",
907            feature = "pdfium_6124",
908            feature = "pdfium_6110",
909            feature = "pdfium_6084",
910            feature = "pdfium_6043",
911            feature = "pdfium_6015",
912            feature = "pdfium_5961"
913        ))]
914        let result = self.bindings.FPDFFont_GetFontName(
915            self.handle,
916            buffer.as_mut_ptr() as *mut c_char,
917            buffer_length,
918        );
919
920        assert_eq!(result, buffer_length);
921
922        String::from_utf8(buffer)
923            // Trim any trailing nulls. All strings returned from Pdfium are generally terminated
924            // by one null byte.
925            .map(|str| str.trim_end_matches(char::from(0)).to_owned())
926            .unwrap_or_else(|_| String::new())
927    }
928
929    /// Returns the weight of this [PdfFont].
930    ///
931    /// Pdfium may not reliably return the correct value of this property for built-in fonts.
932    pub fn weight(&self) -> Result<PdfFontWeight, PdfiumError> {
933        PdfFontWeight::from_pdfium(self.bindings.FPDFFont_GetWeight(self.handle)).ok_or(
934            PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown),
935        )
936    }
937
938    /// Returns the italic angle of this [PdfFont]. The italic angle is the angle,
939    /// expressed in degrees counter-clockwise from the vertical, of the dominant vertical
940    /// strokes of the font. The value is zero for non-italic fonts, and negative for fonts
941    /// that slope to the right (as almost all italic fonts do).
942    ///
943    /// Pdfium may not reliably return the correct value of this property for built-in fonts.
944    pub fn italic_angle(&self) -> Result<i32, PdfiumError> {
945        let mut angle = 0;
946
947        if self.bindings.is_true(
948            self.bindings
949                .FPDFFont_GetItalicAngle(self.handle, &mut angle),
950        ) {
951            Ok(angle)
952        } else {
953            Err(PdfiumError::PdfiumLibraryInternalError(
954                PdfiumInternalError::Unknown,
955            ))
956        }
957    }
958
959    /// Returns the ascent of this [PdfFont] for the given font size. The ascent is the maximum
960    /// height above the baseline reached by glyphs in this font, excluding the height of glyphs
961    /// for accented characters.
962    pub fn ascent(&self, font_size: PdfPoints) -> Result<PdfPoints, PdfiumError> {
963        let mut ascent = 0.0;
964
965        if self.bindings.is_true(self.bindings.FPDFFont_GetAscent(
966            self.handle,
967            font_size.value,
968            &mut ascent,
969        )) {
970            Ok(PdfPoints::new(ascent))
971        } else {
972            Err(PdfiumError::PdfiumLibraryInternalError(
973                PdfiumInternalError::Unknown,
974            ))
975        }
976    }
977
978    /// Returns the descent of this [PdfFont] for the given font size. The descent is the
979    /// maximum distance below the baseline reached by glyphs in this font, expressed as a
980    /// negative points value.
981    pub fn descent(&self, font_size: PdfPoints) -> Result<PdfPoints, PdfiumError> {
982        let mut descent = 0.0;
983
984        if self.bindings.is_true(self.bindings.FPDFFont_GetDescent(
985            self.handle,
986            font_size.value,
987            &mut descent,
988        )) {
989            Ok(PdfPoints::new(descent))
990        } else {
991            Err(PdfiumError::PdfiumLibraryInternalError(
992                PdfiumInternalError::Unknown,
993            ))
994        }
995    }
996
997    /// Returns the raw font descriptor bitflags for the containing [PdfFont].
998    #[inline]
999    fn get_flags_bits(&self) -> FpdfFontDescriptorFlags {
1000        FpdfFontDescriptorFlags::from_bits_truncate(
1001            self.bindings.FPDFFont_GetFlags(self.handle) as u32
1002        )
1003    }
1004
1005    /// Returns `true` if all the glyphs in this [PdfFont] have the same width.
1006    ///
1007    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
1008    pub fn is_fixed_pitch(&self) -> bool {
1009        self.get_flags_bits()
1010            .contains(FpdfFontDescriptorFlags::FIXED_PITCH_BIT_1)
1011    }
1012
1013    /// Returns `true` if the glyphs in this [PdfFont] have variable widths.
1014    ///
1015    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
1016    #[inline]
1017    pub fn is_proportional_pitch(&self) -> bool {
1018        !self.is_fixed_pitch()
1019    }
1020
1021    /// Returns `true` if one or more glyphs in this [PdfFont] have serifs - short strokes
1022    /// drawn at an angle on the top or bottom of glyph stems to decorate the glyphs.
1023    /// For example, Times New Roman is a serif font.
1024    ///
1025    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
1026    pub fn is_serif(&self) -> bool {
1027        self.get_flags_bits()
1028            .contains(FpdfFontDescriptorFlags::SERIF_BIT_2)
1029    }
1030
1031    /// Returns `true` if no glyphs in this [PdfFont] have serifs - short strokes
1032    /// drawn at an angle on the top or bottom of glyph stems to decorate the glyphs.
1033    /// For example, Helvetica is a sans-serif font.
1034    ///
1035    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
1036    #[inline]
1037    pub fn is_sans_serif(&self) -> bool {
1038        !self.is_serif()
1039    }
1040
1041    /// Returns `true` if this [PdfFont] contains glyphs outside the Adobe standard Latin
1042    /// character set.
1043    ///
1044    /// This classification of non-symbolic and symbolic fonts is peculiar to PDF. A font may
1045    /// contain additional characters that are used in Latin writing systems but are outside the
1046    /// Adobe standard Latin character set; PDF considers such a font to be symbolic.
1047    ///
1048    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
1049    pub fn is_symbolic(&self) -> bool {
1050        // This flag bit and the non-symbolic flag bit cannot both be set or both be clear.
1051
1052        self.get_flags_bits()
1053            .contains(FpdfFontDescriptorFlags::SYMBOLIC_BIT_3)
1054    }
1055
1056    /// Returns `true` if this [PdfFont] does not contain glyphs outside the Adobe standard
1057    /// Latin character set.
1058    ///
1059    /// This classification of non-symbolic and symbolic fonts is peculiar to PDF. A font may
1060    /// contain additional characters that are used in Latin writing systems but are outside the
1061    /// Adobe standard Latin character set; PDF considers such a font to be symbolic.
1062    ///
1063    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
1064    pub fn is_non_symbolic(&self) -> bool {
1065        // This flag bit and the symbolic flag bit cannot both be set or both be clear.
1066
1067        self.get_flags_bits()
1068            .contains(FpdfFontDescriptorFlags::NON_SYMBOLIC_BIT_6)
1069    }
1070
1071    /// Returns `true` if the glyphs in this [PdfFont] are designed to resemble cursive handwriting.
1072    ///
1073    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
1074    pub fn is_cursive(&self) -> bool {
1075        self.get_flags_bits()
1076            .contains(FpdfFontDescriptorFlags::SCRIPT_BIT_4)
1077    }
1078
1079    /// Returns `true` if the glyphs in this [PdfFont] include dominant vertical strokes
1080    /// that are slanted.
1081    ///
1082    /// The designed vertical stroke angle can be retrieved using the [PdfFont::italic_angle()] function.
1083    ///
1084    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
1085    pub fn is_italic(&self) -> bool {
1086        self.get_flags_bits()
1087            .contains(FpdfFontDescriptorFlags::ITALIC_BIT_7)
1088    }
1089
1090    /// Returns `true` if this [PdfFont] contains no lowercase letters by design.
1091    ///
1092    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
1093    pub fn is_all_caps(&self) -> bool {
1094        self.get_flags_bits()
1095            .contains(FpdfFontDescriptorFlags::ALL_CAP_BIT_17)
1096    }
1097
1098    /// Returns `true` if the lowercase letters in this [PdfFont] have the same shapes as the
1099    /// corresponding uppercase letters but are sized proportionally so they have the same size
1100    /// and stroke weight as lowercase glyphs in the same typeface family.
1101    ///
1102    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
1103    pub fn is_small_caps(&self) -> bool {
1104        self.get_flags_bits()
1105            .contains(FpdfFontDescriptorFlags::SMALL_CAP_BIT_18)
1106    }
1107
1108    /// Returns `true` if bold glyphs in this [PdfFont] are painted with extra pixels
1109    /// at very small font sizes.
1110    ///
1111    /// Typically when glyphs are painted at small sizes on low-resolution devices, individual strokes
1112    /// of bold glyphs may appear only one pixel wide. Because this is the minimum width of a pixel
1113    /// based device, individual strokes of non-bold glyphs may also appear as one pixel wide
1114    /// and therefore cannot be distinguished from bold glyphs. If this flag is set, individual
1115    /// strokes of bold glyphs may be thickened at small font sizes.
1116    ///
1117    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
1118    pub fn is_bold_reenforced(&self) -> bool {
1119        self.get_flags_bits()
1120            .contains(FpdfFontDescriptorFlags::FORCE_BOLD_BIT_19)
1121    }
1122
1123    /// Returns `true` if this [PdfFont] is an instance of one of the 14 built-in fonts
1124    /// provided as part of the PDF specification.
1125    #[inline]
1126    pub fn is_built_in(&self) -> bool {
1127        self.built_in.is_some()
1128    }
1129
1130    /// Returns the [PdfFontBuiltin] type of this built-in font, or `None` if this font is
1131    /// not one of the 14 built-in fonts provided as part of the PDF specification.
1132    #[inline]
1133    pub fn built_in(&self) -> Option<PdfFontBuiltin> {
1134        self.built_in
1135    }
1136
1137    /// Returns `true` if the data for this [PdfFont] is embedded in the containing [PdfDocument].
1138    pub fn is_embedded(&self) -> Result<bool, PdfiumError> {
1139        let result = self.bindings.FPDFFont_GetIsEmbedded(self.handle);
1140
1141        match result {
1142            1 => Ok(true),
1143            0 => Ok(false),
1144            _ => Err(PdfiumError::PdfiumLibraryInternalError(
1145                PdfiumInternalError::Unknown,
1146            )),
1147        }
1148    }
1149
1150    /// Writes this [PdfFont] to a new byte buffer, returning the byte buffer.
1151    ///
1152    /// If this [PdfFont] is not embedded in the containing [PdfDocument], then the data
1153    /// returned will be for the substitution font instead.
1154    pub fn data(&self) -> Result<Vec<u8>, PdfiumError> {
1155        // Retrieving the font data from Pdfium is a two-step operation. First, we call
1156        // FPDFFont_GetFontData() with a null buffer; this will retrieve the length of
1157        // the data in bytes. If the length is zero, then there is no data associated
1158        // with this font.
1159
1160        // If the length is non-zero, then we reserve a byte buffer of the given
1161        // length and call FPDFFont_GetFontData() again with a pointer to the buffer;
1162        // this will write the font data to the buffer.
1163
1164        let mut out_buflen: usize = 0;
1165
1166        if self
1167            .bindings()
1168            .is_true(self.bindings().FPDFFont_GetFontData(
1169                self.handle,
1170                std::ptr::null_mut(),
1171                0,
1172                &mut out_buflen,
1173            ))
1174        {
1175            // out_buflen now contains the length of the font data.
1176
1177            let buffer_length = out_buflen;
1178
1179            let mut buffer = create_byte_buffer(buffer_length as usize);
1180
1181            let result = self.bindings().FPDFFont_GetFontData(
1182                self.handle,
1183                buffer.as_mut_ptr(),
1184                buffer_length,
1185                &mut out_buflen,
1186            );
1187
1188            assert!(self.bindings.is_true(result));
1189            assert_eq!(buffer_length, out_buflen);
1190
1191            Ok(buffer)
1192        } else {
1193            Err(PdfiumError::PdfiumLibraryInternalError(
1194                PdfiumInternalError::Unknown,
1195            ))
1196        }
1197    }
1198
1199    /// Returns a collection of all the [PdfFontGlyphs] defined for this [PdfFont] in the containing
1200    /// `PdfDocument`.
1201    ///
1202    /// Note that documents typically include only the specific glyphs they need from any given font,
1203    /// not the entire font glyphset. This is a PDF feature known as font subsetting. The collection
1204    /// of glyphs returned by this function may therefore not cover the entire font glyphset.
1205    #[inline]
1206    pub fn glyphs(&self) -> &PdfFontGlyphs {
1207        self.glyphs.initialize_len();
1208        &self.glyphs
1209    }
1210}
1211
1212impl<'a> Drop for PdfFont<'a> {
1213    /// Closes this [PdfFont], releasing held memory.
1214    #[inline]
1215    fn drop(&mut self) {
1216        // The documentation for FPDFText_LoadFont() and FPDFText_LoadStandardFont() both state
1217        // that the font loaded by the function can be closed by calling FPDFFont_Close().
1218        // I had taken this to mean that _any_ FPDF_Font handle returned from a Pdfium function
1219        // should be closed via FPDFFont_Close(), but testing suggests this is not the case;
1220        // rather, it is only fonts specifically loaded by calling FPDFText_LoadFont() or
1221        // FPDFText_LoadStandardFont() that need to be actively closed.
1222
1223        // In other words, retrieving a handle to a font that already exists in a document evidently
1224        // does not allocate any additional resources, so we don't need to free anything.
1225        // (Indeed, if we try to, Pdfium segfaults.)
1226
1227        if self.is_font_memory_loaded {
1228            self.bindings.FPDFFont_Close(self.handle);
1229        }
1230    }
1231}