Skip to main content

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