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;
6pub mod provider;
7
8use crate::bindgen::{
9 FPDF_FONT, FXFONT_ANSI_CHARSET, FXFONT_ARABIC_CHARSET, FXFONT_CHINESEBIG5_CHARSET,
10 FXFONT_CYRILLIC_CHARSET, FXFONT_DEFAULT_CHARSET, FXFONT_EASTERNEUROPEAN_CHARSET,
11 FXFONT_GB2312_CHARSET, FXFONT_GREEK_CHARSET, FXFONT_HANGEUL_CHARSET, FXFONT_HEBREW_CHARSET,
12 FXFONT_SHIFTJIS_CHARSET, FXFONT_SYMBOL_CHARSET, FXFONT_THAI_CHARSET, FXFONT_VIETNAMESE_CHARSET,
13};
14use crate::error::{PdfiumError, PdfiumInternalError};
15use crate::pdf::document::fonts::PdfFontBuiltin;
16use crate::pdf::font::glyphs::PdfFontGlyphs;
17use crate::pdf::points::PdfPoints;
18use crate::pdfium::PdfiumLibraryBindingsAccessor;
19use crate::utils::mem::create_byte_buffer;
20use bitflags::bitflags;
21use std::marker::PhantomData;
22use std::os::raw::{c_char, c_int};
23
24#[cfg(doc)]
25use crate::pdf::document::PdfDocument;
26
27// The following dummy declaration is used only when running cargo doc.
28// It allows documentation of WASM-specific functionality to be included
29// in documentation generated on non-WASM targets.
30
31#[cfg(doc)]
32struct Blob;
33
34bitflags! {
35 pub(crate) struct FpdfFontDescriptorFlags: u32 {
36 const FIXED_PITCH_BIT_1 = 0b00000000000000000000000000000001;
37 const SERIF_BIT_2 = 0b00000000000000000000000000000010;
38 const SYMBOLIC_BIT_3 = 0b00000000000000000000000000000100;
39 const SCRIPT_BIT_4 = 0b00000000000000000000000000001000;
40 const NON_SYMBOLIC_BIT_6 = 0b00000000000000000000000000100000;
41 const ITALIC_BIT_7 = 0b00000000000000000000000001000000;
42 const ALL_CAP_BIT_17 = 0b00000000000000010000000000000000;
43 const SMALL_CAP_BIT_18 = 0b00000000000000100000000000000000;
44 const FORCE_BOLD_BIT_19 = 0b00000000000001000000000000000000;
45 }
46}
47
48/// The weight of a [PdfFont]. Typical values are 400 (normal) and 700 (bold).
49#[derive(Copy, Clone, Debug, PartialEq)]
50pub enum PdfFontWeight {
51 Weight100,
52 Weight200,
53 Weight300,
54 Weight400Normal,
55 Weight500,
56 Weight600,
57 Weight700Bold,
58 Weight800,
59 Weight900,
60
61 /// Any font weight value that falls outside the typical 100 - 900 value range.
62 Custom(u32),
63}
64
65impl PdfFontWeight {
66 pub(crate) fn from_pdfium(value: c_int) -> Option<PdfFontWeight> {
67 match value {
68 -1 => None,
69 100 => Some(PdfFontWeight::Weight100),
70 200 => Some(PdfFontWeight::Weight200),
71 300 => Some(PdfFontWeight::Weight300),
72 400 => Some(PdfFontWeight::Weight400Normal),
73 500 => Some(PdfFontWeight::Weight500),
74 600 => Some(PdfFontWeight::Weight600),
75 700 => Some(PdfFontWeight::Weight700Bold),
76 800 => Some(PdfFontWeight::Weight800),
77 900 => Some(PdfFontWeight::Weight900),
78 other => Some(PdfFontWeight::Custom(other as u32)),
79 }
80 }
81}
82
83/// The character set of a [PdfFont].
84pub enum PdfFontCharacterSet {
85 Ansi,
86 Default,
87 Symbol,
88 JapaneseShiftJis,
89 KoreanHangul,
90 ChineseGb2312,
91 ChineseBig5,
92 Greek,
93 Vietnamese,
94 Hebrew,
95 Arabic,
96 Cyrillic,
97 Thai,
98 EasternEuropean,
99}
100
101impl PdfFontCharacterSet {
102 pub(crate) fn from_pdfium(value: c_int) -> Option<PdfFontCharacterSet> {
103 match value as u32 {
104 FXFONT_ANSI_CHARSET => Some(PdfFontCharacterSet::Ansi),
105 FXFONT_DEFAULT_CHARSET => Some(PdfFontCharacterSet::Default),
106 FXFONT_SYMBOL_CHARSET => Some(PdfFontCharacterSet::Symbol),
107 FXFONT_SHIFTJIS_CHARSET => Some(PdfFontCharacterSet::JapaneseShiftJis),
108 FXFONT_HANGEUL_CHARSET => Some(PdfFontCharacterSet::KoreanHangul),
109 FXFONT_GB2312_CHARSET => Some(PdfFontCharacterSet::ChineseGb2312),
110 FXFONT_CHINESEBIG5_CHARSET => Some(PdfFontCharacterSet::ChineseBig5),
111 FXFONT_GREEK_CHARSET => Some(PdfFontCharacterSet::Greek),
112 FXFONT_VIETNAMESE_CHARSET => Some(PdfFontCharacterSet::Vietnamese),
113 FXFONT_HEBREW_CHARSET => Some(PdfFontCharacterSet::Hebrew),
114 FXFONT_ARABIC_CHARSET => Some(PdfFontCharacterSet::Arabic),
115 FXFONT_CYRILLIC_CHARSET => Some(PdfFontCharacterSet::Cyrillic),
116 FXFONT_THAI_CHARSET => Some(PdfFontCharacterSet::Thai),
117 FXFONT_EASTERNEUROPEAN_CHARSET => Some(PdfFontCharacterSet::EasternEuropean),
118 _ => None,
119 }
120 }
121
122 pub(crate) fn as_pdfium(&self) -> c_int {
123 (match self {
124 PdfFontCharacterSet::Ansi => FXFONT_ANSI_CHARSET,
125 PdfFontCharacterSet::Default => FXFONT_DEFAULT_CHARSET,
126 PdfFontCharacterSet::Symbol => FXFONT_SYMBOL_CHARSET,
127 PdfFontCharacterSet::JapaneseShiftJis => FXFONT_SHIFTJIS_CHARSET,
128 PdfFontCharacterSet::KoreanHangul => FXFONT_HANGEUL_CHARSET,
129 PdfFontCharacterSet::ChineseGb2312 => FXFONT_GB2312_CHARSET,
130 PdfFontCharacterSet::ChineseBig5 => FXFONT_CHINESEBIG5_CHARSET,
131 PdfFontCharacterSet::Greek => FXFONT_GREEK_CHARSET,
132 PdfFontCharacterSet::Vietnamese => FXFONT_VIETNAMESE_CHARSET,
133 PdfFontCharacterSet::Hebrew => FXFONT_HEBREW_CHARSET,
134 PdfFontCharacterSet::Arabic => FXFONT_ARABIC_CHARSET,
135 PdfFontCharacterSet::Cyrillic => FXFONT_CYRILLIC_CHARSET,
136 PdfFontCharacterSet::Thai => FXFONT_THAI_CHARSET,
137 PdfFontCharacterSet::EasternEuropean => FXFONT_EASTERNEUROPEAN_CHARSET,
138 }) as c_int
139 }
140}
141
142/// A single font used to render text in a [PdfDocument].
143///
144/// The PDF specification defines 14 built-in fonts that can be used in any PDF file without
145/// font embedding. Additionally, custom fonts can be directly embedded into any PDF file as
146/// a data stream.
147pub struct PdfFont<'a> {
148 built_in: Option<PdfFontBuiltin>,
149 handle: FPDF_FONT,
150 glyphs: PdfFontGlyphs<'a>,
151 is_font_memory_loaded: bool,
152 lifetime: PhantomData<&'a FPDF_FONT>,
153}
154
155impl<'a> PdfFont<'a> {
156 #[inline]
157 pub(crate) fn from_pdfium(
158 handle: FPDF_FONT,
159 built_in: Option<PdfFontBuiltin>,
160 is_font_memory_loaded: bool,
161 ) -> Self {
162 PdfFont {
163 built_in,
164 handle,
165 glyphs: PdfFontGlyphs::from_pdfium(handle),
166 is_font_memory_loaded,
167 lifetime: PhantomData,
168 }
169 }
170
171 /// Returns the internal `FPDF_FONT` handle for this [PdfFont].
172 #[inline]
173 pub(crate) fn handle(&self) -> FPDF_FONT {
174 self.handle
175 }
176
177 #[cfg(any(
178 feature = "pdfium_future",
179 feature = "pdfium_7763",
180 feature = "pdfium_7543",
181 feature = "pdfium_7350",
182 feature = "pdfium_7215",
183 feature = "pdfium_7123",
184 feature = "pdfium_6996",
185 feature = "pdfium_6721",
186 feature = "pdfium_6666"
187 ))]
188 /// Returns the name of this [PdfFont].
189 pub fn name(&self) -> String {
190 // Retrieving the font name from Pdfium is a two-step operation. First, we call
191 // FPDFFont_GetBaseFontName() with a null buffer; this will retrieve the length of
192 // the font name in bytes. If the length is zero, then there is no font name.
193
194 // If the length is non-zero, then we reserve a byte buffer of the given
195 // length and call FPDFFont_GetBaseFontName() again with a pointer to the buffer;
196 // this will write the font name into the buffer. Unlike most text handling in
197 // Pdfium, font names are returned in UTF-8 format.
198
199 let buffer_length = unsafe {
200 self.bindings()
201 .FPDFFont_GetBaseFontName(self.handle, std::ptr::null_mut(), 0)
202 };
203
204 if buffer_length == 0 {
205 // The font name is not present.
206
207 return String::new();
208 }
209
210 let mut buffer = create_byte_buffer(buffer_length as usize);
211
212 let result = unsafe {
213 self.bindings().FPDFFont_GetBaseFontName(
214 self.handle,
215 buffer.as_mut_ptr() as *mut c_char,
216 buffer_length,
217 )
218 };
219
220 assert_eq!(result, buffer_length);
221
222 String::from_utf8(buffer)
223 // Trim any trailing nulls. All strings returned from Pdfium are generally terminated
224 // by one null byte.
225 .map(|str| str.trim_end_matches(char::from(0)).to_owned())
226 .unwrap_or_else(|_| String::new())
227 }
228
229 /// Returns the family of this [PdfFont].
230 pub fn family(&self) -> String {
231 // Retrieving the family name from Pdfium is a two-step operation. First, we call
232 // FPDFFont_GetFamilyName() with a null buffer; this will retrieve the length of
233 // the font name in bytes. If the length is zero, then there is no font name.
234
235 // If the length is non-zero, then we reserve a byte buffer of the given
236 // length and call FPDFFont_GetFamilyName() again with a pointer to the buffer;
237 // this will write the font name into the buffer. Unlike most text handling in
238 // Pdfium, font names are returned in UTF-8 format.
239
240 #[cfg(any(
241 feature = "pdfium_future",
242 feature = "pdfium_7763",
243 feature = "pdfium_7543",
244 feature = "pdfium_7350",
245 feature = "pdfium_7215",
246 feature = "pdfium_7123",
247 feature = "pdfium_6996",
248 feature = "pdfium_6721",
249 feature = "pdfium_6666",
250 feature = "pdfium_6611"
251 ))]
252 let buffer_length = unsafe {
253 self.bindings()
254 .FPDFFont_GetFamilyName(self.handle, std::ptr::null_mut(), 0)
255 };
256
257 #[cfg(any(
258 feature = "pdfium_6569",
259 feature = "pdfium_6555",
260 feature = "pdfium_6490",
261 feature = "pdfium_6406",
262 feature = "pdfium_6337",
263 feature = "pdfium_6295",
264 feature = "pdfium_6259",
265 feature = "pdfium_6164",
266 feature = "pdfium_6124",
267 feature = "pdfium_6110",
268 feature = "pdfium_6084",
269 feature = "pdfium_6043",
270 feature = "pdfium_6015",
271 feature = "pdfium_5961"
272 ))]
273 let buffer_length = unsafe {
274 self.bindings()
275 .FPDFFont_GetFontName(self.handle, std::ptr::null_mut(), 0)
276 };
277
278 if buffer_length == 0 {
279 // The font name is not present.
280
281 return String::new();
282 }
283
284 let mut buffer = create_byte_buffer(buffer_length as usize);
285
286 #[cfg(any(
287 feature = "pdfium_future",
288 feature = "pdfium_7763",
289 feature = "pdfium_7543",
290 feature = "pdfium_7350",
291 feature = "pdfium_7215",
292 feature = "pdfium_7123",
293 feature = "pdfium_6996",
294 feature = "pdfium_6721",
295 feature = "pdfium_6666",
296 feature = "pdfium_6611"
297 ))]
298 let result = unsafe {
299 self.bindings().FPDFFont_GetFamilyName(
300 self.handle,
301 buffer.as_mut_ptr() as *mut c_char,
302 buffer_length,
303 )
304 };
305
306 #[cfg(any(
307 feature = "pdfium_6569",
308 feature = "pdfium_6555",
309 feature = "pdfium_6490",
310 feature = "pdfium_6406",
311 feature = "pdfium_6337",
312 feature = "pdfium_6295",
313 feature = "pdfium_6259",
314 feature = "pdfium_6164",
315 feature = "pdfium_6124",
316 feature = "pdfium_6110",
317 feature = "pdfium_6084",
318 feature = "pdfium_6043",
319 feature = "pdfium_6015",
320 feature = "pdfium_5961"
321 ))]
322 let result = unsafe {
323 self.bindings().FPDFFont_GetFontName(
324 self.handle,
325 buffer.as_mut_ptr() as *mut c_char,
326 buffer_length,
327 )
328 };
329
330 assert_eq!(result, buffer_length);
331
332 String::from_utf8(buffer)
333 // Trim any trailing nulls. All strings returned from Pdfium are generally terminated
334 // by one null byte.
335 .map(|str| str.trim_end_matches(char::from(0)).to_owned())
336 .unwrap_or_else(|_| String::new())
337 }
338
339 /// Returns the weight of this [PdfFont].
340 ///
341 /// Pdfium may not reliably return the correct value of this property for built-in fonts.
342 pub fn weight(&self) -> Result<PdfFontWeight, PdfiumError> {
343 PdfFontWeight::from_pdfium(unsafe { self.bindings().FPDFFont_GetWeight(self.handle) })
344 .ok_or(PdfiumError::PdfiumLibraryInternalError(
345 PdfiumInternalError::Unknown,
346 ))
347 }
348
349 /// Returns the italic angle of this [PdfFont]. The italic angle is the angle,
350 /// expressed in degrees counter-clockwise from the vertical, of the dominant vertical
351 /// strokes of the font. The value is zero for non-italic fonts, and negative for fonts
352 /// that slope to the right (as almost all italic fonts do).
353 ///
354 /// Pdfium may not reliably return the correct value of this property for built-in fonts.
355 pub fn italic_angle(&self) -> Result<i32, PdfiumError> {
356 let mut angle = 0;
357
358 if self.bindings().is_true(unsafe {
359 self.bindings()
360 .FPDFFont_GetItalicAngle(self.handle, &mut angle)
361 }) {
362 Ok(angle)
363 } else {
364 Err(PdfiumError::PdfiumLibraryInternalError(
365 PdfiumInternalError::Unknown,
366 ))
367 }
368 }
369
370 /// Returns the ascent of this [PdfFont] for the given font size. The ascent is the maximum
371 /// height above the baseline reached by glyphs in this font, excluding the height of glyphs
372 /// for accented characters.
373 pub fn ascent(&self, font_size: PdfPoints) -> Result<PdfPoints, PdfiumError> {
374 let mut ascent = 0.0;
375
376 if self.bindings().is_true(unsafe {
377 self.bindings()
378 .FPDFFont_GetAscent(self.handle, font_size.value, &mut ascent)
379 }) {
380 Ok(PdfPoints::new(ascent))
381 } else {
382 Err(PdfiumError::PdfiumLibraryInternalError(
383 PdfiumInternalError::Unknown,
384 ))
385 }
386 }
387
388 /// Returns the descent of this [PdfFont] for the given font size. The descent is the
389 /// maximum distance below the baseline reached by glyphs in this font, expressed as a
390 /// negative points value.
391 pub fn descent(&self, font_size: PdfPoints) -> Result<PdfPoints, PdfiumError> {
392 let mut descent = 0.0;
393
394 if self.bindings().is_true(unsafe {
395 self.bindings()
396 .FPDFFont_GetDescent(self.handle, font_size.value, &mut descent)
397 }) {
398 Ok(PdfPoints::new(descent))
399 } else {
400 Err(PdfiumError::PdfiumLibraryInternalError(
401 PdfiumInternalError::Unknown,
402 ))
403 }
404 }
405
406 /// Returns the raw font descriptor bitflags for the containing [PdfFont].
407 #[inline]
408 fn get_flags_bits(&self) -> FpdfFontDescriptorFlags {
409 FpdfFontDescriptorFlags::from_bits_truncate(unsafe {
410 self.bindings().FPDFFont_GetFlags(self.handle)
411 } as u32)
412 }
413
414 /// Returns `true` if all the glyphs in this [PdfFont] have the same width.
415 ///
416 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
417 pub fn is_fixed_pitch(&self) -> bool {
418 self.get_flags_bits()
419 .contains(FpdfFontDescriptorFlags::FIXED_PITCH_BIT_1)
420 }
421
422 /// Returns `true` if the glyphs in this [PdfFont] have variable widths.
423 ///
424 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
425 #[inline]
426 pub fn is_proportional_pitch(&self) -> bool {
427 !self.is_fixed_pitch()
428 }
429
430 /// Returns `true` if one or more glyphs in this [PdfFont] have serifs - short strokes
431 /// drawn at an angle on the top or bottom of glyph stems to decorate the glyphs.
432 /// For example, Times New Roman is a serif font.
433 ///
434 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
435 pub fn is_serif(&self) -> bool {
436 self.get_flags_bits()
437 .contains(FpdfFontDescriptorFlags::SERIF_BIT_2)
438 }
439
440 /// Returns `true` if no glyphs in this [PdfFont] have serifs - short strokes
441 /// drawn at an angle on the top or bottom of glyph stems to decorate the glyphs.
442 /// For example, Helvetica is a sans-serif font.
443 ///
444 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
445 #[inline]
446 pub fn is_sans_serif(&self) -> bool {
447 !self.is_serif()
448 }
449
450 /// Returns `true` if this [PdfFont] contains glyphs outside the Adobe standard Latin
451 /// character set.
452 ///
453 /// This classification of non-symbolic and symbolic fonts is peculiar to PDF. A font may
454 /// contain additional characters that are used in Latin writing systems but are outside the
455 /// Adobe standard Latin character set; PDF considers such a font to be symbolic.
456 ///
457 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
458 pub fn is_symbolic(&self) -> bool {
459 // This flag bit and the non-symbolic flag bit cannot both be set or both be clear.
460
461 self.get_flags_bits()
462 .contains(FpdfFontDescriptorFlags::SYMBOLIC_BIT_3)
463 }
464
465 /// Returns `true` if this [PdfFont] does not contain glyphs outside the Adobe standard
466 /// Latin character set.
467 ///
468 /// This classification of non-symbolic and symbolic fonts is peculiar to PDF. A font may
469 /// contain additional characters that are used in Latin writing systems but are outside the
470 /// Adobe standard Latin character set; PDF considers such a font to be symbolic.
471 ///
472 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
473 pub fn is_non_symbolic(&self) -> bool {
474 // This flag bit and the symbolic flag bit cannot both be set or both be clear.
475
476 self.get_flags_bits()
477 .contains(FpdfFontDescriptorFlags::NON_SYMBOLIC_BIT_6)
478 }
479
480 /// Returns `true` if the glyphs in this [PdfFont] are designed to resemble cursive handwriting.
481 ///
482 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
483 pub fn is_cursive(&self) -> bool {
484 self.get_flags_bits()
485 .contains(FpdfFontDescriptorFlags::SCRIPT_BIT_4)
486 }
487
488 /// Returns `true` if the glyphs in this [PdfFont] include dominant vertical strokes
489 /// that are slanted.
490 ///
491 /// The designed vertical stroke angle can be retrieved using the [PdfFont::italic_angle()] function.
492 ///
493 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
494 pub fn is_italic(&self) -> bool {
495 self.get_flags_bits()
496 .contains(FpdfFontDescriptorFlags::ITALIC_BIT_7)
497 }
498
499 /// Returns `true` if this [PdfFont] contains no lowercase letters by design.
500 ///
501 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
502 pub fn is_all_caps(&self) -> bool {
503 self.get_flags_bits()
504 .contains(FpdfFontDescriptorFlags::ALL_CAP_BIT_17)
505 }
506
507 /// Returns `true` if the lowercase letters in this [PdfFont] have the same shapes as the
508 /// corresponding uppercase letters but are sized proportionally so they have the same size
509 /// and stroke weight as lowercase glyphs in the same typeface family.
510 ///
511 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
512 pub fn is_small_caps(&self) -> bool {
513 self.get_flags_bits()
514 .contains(FpdfFontDescriptorFlags::SMALL_CAP_BIT_18)
515 }
516
517 /// Returns `true` if bold glyphs in this [PdfFont] are painted with extra pixels
518 /// at very small font sizes.
519 ///
520 /// Typically when glyphs are painted at small sizes on low-resolution devices, individual strokes
521 /// of bold glyphs may appear only one pixel wide. Because this is the minimum width of a pixel
522 /// based device, individual strokes of non-bold glyphs may also appear as one pixel wide
523 /// and therefore cannot be distinguished from bold glyphs. If this flag is set, individual
524 /// strokes of bold glyphs may be thickened at small font sizes.
525 ///
526 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
527 pub fn is_bold_reenforced(&self) -> bool {
528 self.get_flags_bits()
529 .contains(FpdfFontDescriptorFlags::FORCE_BOLD_BIT_19)
530 }
531
532 /// Returns `true` if this [PdfFont] is an instance of one of the 14 built-in fonts
533 /// provided as part of the PDF specification.
534 #[inline]
535 pub fn is_built_in(&self) -> bool {
536 self.built_in.is_some()
537 }
538
539 /// Returns the [PdfFontBuiltin] type of this built-in font, or `None` if this font is
540 /// not one of the 14 built-in fonts provided as part of the PDF specification.
541 #[inline]
542 pub fn built_in(&self) -> Option<PdfFontBuiltin> {
543 self.built_in
544 }
545
546 /// Returns `true` if the data for this [PdfFont] is embedded in the containing [PdfDocument].
547 pub fn is_embedded(&self) -> Result<bool, PdfiumError> {
548 let result = unsafe { self.bindings().FPDFFont_GetIsEmbedded(self.handle) };
549
550 match result {
551 1 => Ok(true),
552 0 => Ok(false),
553 _ => Err(PdfiumError::PdfiumLibraryInternalError(
554 PdfiumInternalError::Unknown,
555 )),
556 }
557 }
558
559 /// Writes this [PdfFont] to a new byte buffer, returning the byte buffer.
560 ///
561 /// If this [PdfFont] is not embedded in the containing [PdfDocument], then the data
562 /// returned will be for the substitution font instead.
563 pub fn data(&self) -> Result<Vec<u8>, PdfiumError> {
564 // Retrieving the font data from Pdfium is a two-step operation. First, we call
565 // FPDFFont_GetFontData() with a null buffer; this will retrieve the length of
566 // the data in bytes. If the length is zero, then there is no data associated
567 // with this font.
568
569 // If the length is non-zero, then we reserve a byte buffer of the given
570 // length and call FPDFFont_GetFontData() again with a pointer to the buffer;
571 // this will write the font data to the buffer.
572
573 let mut out_buflen: usize = 0;
574
575 if self.bindings().is_true(unsafe {
576 self.bindings().FPDFFont_GetFontData(
577 self.handle,
578 std::ptr::null_mut(),
579 0,
580 &mut out_buflen,
581 )
582 }) {
583 // out_buflen now contains the length of the font data.
584
585 let buffer_length = out_buflen;
586
587 let mut buffer = create_byte_buffer(buffer_length);
588
589 let result = unsafe {
590 self.bindings().FPDFFont_GetFontData(
591 self.handle,
592 buffer.as_mut_ptr(),
593 buffer_length,
594 &mut out_buflen,
595 )
596 };
597
598 assert!(self.bindings().is_true(result));
599 assert_eq!(buffer_length, out_buflen);
600
601 Ok(buffer)
602 } else {
603 Err(PdfiumError::PdfiumLibraryInternalError(
604 PdfiumInternalError::Unknown,
605 ))
606 }
607 }
608
609 /// Returns a collection of all the [PdfFontGlyphs] defined for this [PdfFont] in the containing
610 /// `PdfDocument`.
611 ///
612 /// Note that documents typically include only the specific glyphs they need from any given font,
613 /// not the entire font glyphset. This is a PDF feature known as font subsetting. The collection
614 /// of glyphs returned by this function may therefore not cover the entire font glyphset.
615 #[inline]
616 pub fn glyphs(&self) -> &PdfFontGlyphs<'_> {
617 self.glyphs.initialize_len();
618 &self.glyphs
619 }
620}
621
622impl<'a> Drop for PdfFont<'a> {
623 /// Closes this [PdfFont], releasing held memory.
624 #[inline]
625 fn drop(&mut self) {
626 // The documentation for FPDFText_LoadFont() and FPDFText_LoadStandardFont() both state
627 // that the font loaded by the function can be closed by calling FPDFFont_Close().
628 // I had taken this to mean that _any_ FPDF_Font handle returned from a Pdfium function
629 // should be closed via FPDFFont_Close(), but testing suggests this is not the case;
630 // rather, it is only fonts specifically loaded by calling FPDFText_LoadFont() or
631 // FPDFText_LoadStandardFont() that need to be actively closed.
632
633 // In other words, retrieving a handle to a font that already exists in a document evidently
634 // does not allocate any additional resources, so we don't need to free anything.
635 // (Indeed, if we try to, Pdfium segfaults.)
636
637 if self.is_font_memory_loaded {
638 unsafe {
639 self.bindings().FPDFFont_Close(self.handle);
640 }
641 }
642 }
643}
644
645impl<'a> PdfiumLibraryBindingsAccessor<'a> for PdfFont<'a> {}
646
647#[cfg(feature = "thread_safe")]
648unsafe impl<'a> Send for PdfFont<'a> {}
649
650#[cfg(feature = "thread_safe")]
651unsafe impl<'a> Sync for PdfFont<'a> {}