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_8125",
180 feature = "pdfium_7881",
181 feature = "pdfium_7763",
182 feature = "pdfium_7543",
183 feature = "pdfium_7350",
184 feature = "pdfium_7215",
185 feature = "pdfium_7123",
186 feature = "pdfium_6996",
187 feature = "pdfium_6721",
188 feature = "pdfium_6666"
189 ))]
190 /// Returns the name of this [PdfFont].
191 pub fn name(&self) -> String {
192 // Retrieving the font name from Pdfium is a two-step operation. First, we call
193 // FPDFFont_GetBaseFontName() with a null buffer; this will retrieve the length of
194 // the font name in bytes. If the length is zero, then there is no font name.
195
196 // If the length is non-zero, then we reserve a byte buffer of the given
197 // length and call FPDFFont_GetBaseFontName() again with a pointer to the buffer;
198 // this will write the font name into the buffer. Unlike most text handling in
199 // Pdfium, font names are returned in UTF-8 format.
200
201 let buffer_length = unsafe {
202 self.bindings()
203 .FPDFFont_GetBaseFontName(self.handle, std::ptr::null_mut(), 0)
204 };
205
206 if buffer_length == 0 {
207 // The font name is not present.
208
209 return String::new();
210 }
211
212 let mut buffer = create_byte_buffer(buffer_length as usize);
213
214 let result = unsafe {
215 self.bindings().FPDFFont_GetBaseFontName(
216 self.handle,
217 buffer.as_mut_ptr() as *mut c_char,
218 buffer_length,
219 )
220 };
221
222 assert_eq!(result, buffer_length);
223
224 String::from_utf8(buffer)
225 // Trim any trailing nulls. All strings returned from Pdfium are generally terminated
226 // by one null byte.
227 .map(|str| str.trim_end_matches(char::from(0)).to_owned())
228 .unwrap_or_else(|_| String::new())
229 }
230
231 /// Returns the family of this [PdfFont].
232 pub fn family(&self) -> String {
233 // Retrieving the family name from Pdfium is a two-step operation. First, we call
234 // FPDFFont_GetFamilyName() with a null buffer; this will retrieve the length of
235 // the font name in bytes. If the length is zero, then there is no font name.
236
237 // If the length is non-zero, then we reserve a byte buffer of the given
238 // length and call FPDFFont_GetFamilyName() again with a pointer to the buffer;
239 // this will write the font name into the buffer. Unlike most text handling in
240 // Pdfium, font names are returned in UTF-8 format.
241
242 #[cfg(any(
243 feature = "pdfium_future",
244 feature = "pdfium_8125",
245 feature = "pdfium_7881",
246 feature = "pdfium_7763",
247 feature = "pdfium_7543",
248 feature = "pdfium_7350",
249 feature = "pdfium_7215",
250 feature = "pdfium_7123",
251 feature = "pdfium_6996",
252 feature = "pdfium_6721",
253 feature = "pdfium_6666",
254 feature = "pdfium_6611"
255 ))]
256 let buffer_length = unsafe {
257 self.bindings()
258 .FPDFFont_GetFamilyName(self.handle, std::ptr::null_mut(), 0)
259 };
260
261 #[cfg(any(
262 feature = "pdfium_6569",
263 feature = "pdfium_6555",
264 feature = "pdfium_6490",
265 feature = "pdfium_6406",
266 feature = "pdfium_6337",
267 feature = "pdfium_6295",
268 feature = "pdfium_6259",
269 feature = "pdfium_6164",
270 feature = "pdfium_6124",
271 feature = "pdfium_6110",
272 feature = "pdfium_6084",
273 feature = "pdfium_6043",
274 feature = "pdfium_6015",
275 feature = "pdfium_5961"
276 ))]
277 let buffer_length = unsafe {
278 self.bindings()
279 .FPDFFont_GetFontName(self.handle, std::ptr::null_mut(), 0)
280 };
281
282 if buffer_length == 0 {
283 // The font name is not present.
284
285 return String::new();
286 }
287
288 let mut buffer = create_byte_buffer(buffer_length as usize);
289
290 #[cfg(any(
291 feature = "pdfium_future",
292 feature = "pdfium_8125",
293 feature = "pdfium_7881",
294 feature = "pdfium_7763",
295 feature = "pdfium_7543",
296 feature = "pdfium_7350",
297 feature = "pdfium_7215",
298 feature = "pdfium_7123",
299 feature = "pdfium_6996",
300 feature = "pdfium_6721",
301 feature = "pdfium_6666",
302 feature = "pdfium_6611"
303 ))]
304 let result = unsafe {
305 self.bindings().FPDFFont_GetFamilyName(
306 self.handle,
307 buffer.as_mut_ptr() as *mut c_char,
308 buffer_length,
309 )
310 };
311
312 #[cfg(any(
313 feature = "pdfium_6569",
314 feature = "pdfium_6555",
315 feature = "pdfium_6490",
316 feature = "pdfium_6406",
317 feature = "pdfium_6337",
318 feature = "pdfium_6295",
319 feature = "pdfium_6259",
320 feature = "pdfium_6164",
321 feature = "pdfium_6124",
322 feature = "pdfium_6110",
323 feature = "pdfium_6084",
324 feature = "pdfium_6043",
325 feature = "pdfium_6015",
326 feature = "pdfium_5961"
327 ))]
328 let result = unsafe {
329 self.bindings().FPDFFont_GetFontName(
330 self.handle,
331 buffer.as_mut_ptr() as *mut c_char,
332 buffer_length,
333 )
334 };
335
336 assert_eq!(result, buffer_length);
337
338 String::from_utf8(buffer)
339 // Trim any trailing nulls. All strings returned from Pdfium are generally terminated
340 // by one null byte.
341 .map(|str| str.trim_end_matches(char::from(0)).to_owned())
342 .unwrap_or_else(|_| String::new())
343 }
344
345 /// Returns the weight of this [PdfFont].
346 ///
347 /// Pdfium may not reliably return the correct value of this property for built-in fonts.
348 pub fn weight(&self) -> Result<PdfFontWeight, PdfiumError> {
349 PdfFontWeight::from_pdfium(unsafe { self.bindings().FPDFFont_GetWeight(self.handle) })
350 .ok_or(PdfiumError::PdfiumLibraryInternalError(
351 PdfiumInternalError::Unknown,
352 ))
353 }
354
355 /// Returns the italic angle of this [PdfFont]. The italic angle is the angle,
356 /// expressed in degrees counter-clockwise from the vertical, of the dominant vertical
357 /// strokes of the font. The value is zero for non-italic fonts, and negative for fonts
358 /// that slope to the right (as almost all italic fonts do).
359 ///
360 /// Pdfium may not reliably return the correct value of this property for built-in fonts.
361 pub fn italic_angle(&self) -> Result<i32, PdfiumError> {
362 let mut angle = 0;
363
364 if self.bindings().is_true(unsafe {
365 self.bindings()
366 .FPDFFont_GetItalicAngle(self.handle, &mut angle)
367 }) {
368 Ok(angle)
369 } else {
370 Err(PdfiumError::PdfiumLibraryInternalError(
371 PdfiumInternalError::Unknown,
372 ))
373 }
374 }
375
376 /// Returns the ascent of this [PdfFont] for the given font size. The ascent is the maximum
377 /// height above the baseline reached by glyphs in this font, excluding the height of glyphs
378 /// for accented characters.
379 pub fn ascent(&self, font_size: PdfPoints) -> Result<PdfPoints, PdfiumError> {
380 let mut ascent = 0.0;
381
382 if self.bindings().is_true(unsafe {
383 self.bindings()
384 .FPDFFont_GetAscent(self.handle, font_size.value, &mut ascent)
385 }) {
386 Ok(PdfPoints::new(ascent))
387 } else {
388 Err(PdfiumError::PdfiumLibraryInternalError(
389 PdfiumInternalError::Unknown,
390 ))
391 }
392 }
393
394 /// Returns the descent of this [PdfFont] for the given font size. The descent is the
395 /// maximum distance below the baseline reached by glyphs in this font, expressed as a
396 /// negative points value.
397 pub fn descent(&self, font_size: PdfPoints) -> Result<PdfPoints, PdfiumError> {
398 let mut descent = 0.0;
399
400 if self.bindings().is_true(unsafe {
401 self.bindings()
402 .FPDFFont_GetDescent(self.handle, font_size.value, &mut descent)
403 }) {
404 Ok(PdfPoints::new(descent))
405 } else {
406 Err(PdfiumError::PdfiumLibraryInternalError(
407 PdfiumInternalError::Unknown,
408 ))
409 }
410 }
411
412 /// Returns the raw font descriptor bitflags for the containing [PdfFont].
413 #[inline]
414 fn get_flags_bits(&self) -> FpdfFontDescriptorFlags {
415 FpdfFontDescriptorFlags::from_bits_truncate(unsafe {
416 self.bindings().FPDFFont_GetFlags(self.handle)
417 } as u32)
418 }
419
420 /// Returns `true` if all the glyphs in this [PdfFont] have the same width.
421 ///
422 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
423 pub fn is_fixed_pitch(&self) -> bool {
424 self.get_flags_bits()
425 .contains(FpdfFontDescriptorFlags::FIXED_PITCH_BIT_1)
426 }
427
428 /// Returns `true` if the glyphs in this [PdfFont] have variable widths.
429 ///
430 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
431 #[inline]
432 pub fn is_proportional_pitch(&self) -> bool {
433 !self.is_fixed_pitch()
434 }
435
436 /// Returns `true` if one or more glyphs in this [PdfFont] have serifs - short strokes
437 /// drawn at an angle on the top or bottom of glyph stems to decorate the glyphs.
438 /// For example, Times New Roman is a serif font.
439 ///
440 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
441 pub fn is_serif(&self) -> bool {
442 self.get_flags_bits()
443 .contains(FpdfFontDescriptorFlags::SERIF_BIT_2)
444 }
445
446 /// Returns `true` if no glyphs in this [PdfFont] have serifs - short strokes
447 /// drawn at an angle on the top or bottom of glyph stems to decorate the glyphs.
448 /// For example, Helvetica is a sans-serif font.
449 ///
450 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
451 #[inline]
452 pub fn is_sans_serif(&self) -> bool {
453 !self.is_serif()
454 }
455
456 /// Returns `true` if this [PdfFont] contains glyphs outside the Adobe standard Latin
457 /// character set.
458 ///
459 /// This classification of non-symbolic and symbolic fonts is peculiar to PDF. A font may
460 /// contain additional characters that are used in Latin writing systems but are outside the
461 /// Adobe standard Latin character set; PDF considers such a font to be symbolic.
462 ///
463 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
464 pub fn is_symbolic(&self) -> bool {
465 // This flag bit and the non-symbolic flag bit cannot both be set or both be clear.
466
467 self.get_flags_bits()
468 .contains(FpdfFontDescriptorFlags::SYMBOLIC_BIT_3)
469 }
470
471 /// Returns `true` if this [PdfFont] does not contain glyphs outside the Adobe standard
472 /// Latin character set.
473 ///
474 /// This classification of non-symbolic and symbolic fonts is peculiar to PDF. A font may
475 /// contain additional characters that are used in Latin writing systems but are outside the
476 /// Adobe standard Latin character set; PDF considers such a font to be symbolic.
477 ///
478 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
479 pub fn is_non_symbolic(&self) -> bool {
480 // This flag bit and the symbolic flag bit cannot both be set or both be clear.
481
482 self.get_flags_bits()
483 .contains(FpdfFontDescriptorFlags::NON_SYMBOLIC_BIT_6)
484 }
485
486 /// Returns `true` if the glyphs in this [PdfFont] are designed to resemble cursive handwriting.
487 ///
488 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
489 pub fn is_cursive(&self) -> bool {
490 self.get_flags_bits()
491 .contains(FpdfFontDescriptorFlags::SCRIPT_BIT_4)
492 }
493
494 /// Returns `true` if the glyphs in this [PdfFont] include dominant vertical strokes
495 /// that are slanted.
496 ///
497 /// The designed vertical stroke angle can be retrieved using the [PdfFont::italic_angle()] function.
498 ///
499 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
500 pub fn is_italic(&self) -> bool {
501 self.get_flags_bits()
502 .contains(FpdfFontDescriptorFlags::ITALIC_BIT_7)
503 }
504
505 /// Returns `true` if this [PdfFont] contains no lowercase letters by design.
506 ///
507 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
508 pub fn is_all_caps(&self) -> bool {
509 self.get_flags_bits()
510 .contains(FpdfFontDescriptorFlags::ALL_CAP_BIT_17)
511 }
512
513 /// Returns `true` if the lowercase letters in this [PdfFont] have the same shapes as the
514 /// corresponding uppercase letters but are sized proportionally so they have the same size
515 /// and stroke weight as lowercase glyphs in the same typeface family.
516 ///
517 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
518 pub fn is_small_caps(&self) -> bool {
519 self.get_flags_bits()
520 .contains(FpdfFontDescriptorFlags::SMALL_CAP_BIT_18)
521 }
522
523 /// Returns `true` if bold glyphs in this [PdfFont] are painted with extra pixels
524 /// at very small font sizes.
525 ///
526 /// Typically when glyphs are painted at small sizes on low-resolution devices, individual strokes
527 /// of bold glyphs may appear only one pixel wide. Because this is the minimum width of a pixel
528 /// based device, individual strokes of non-bold glyphs may also appear as one pixel wide
529 /// and therefore cannot be distinguished from bold glyphs. If this flag is set, individual
530 /// strokes of bold glyphs may be thickened at small font sizes.
531 ///
532 /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
533 pub fn is_bold_reenforced(&self) -> bool {
534 self.get_flags_bits()
535 .contains(FpdfFontDescriptorFlags::FORCE_BOLD_BIT_19)
536 }
537
538 /// Returns `true` if this [PdfFont] is an instance of one of the 14 built-in fonts
539 /// provided as part of the PDF specification.
540 #[inline]
541 pub fn is_built_in(&self) -> bool {
542 self.built_in.is_some()
543 }
544
545 /// Returns the [PdfFontBuiltin] type of this built-in font, or `None` if this font is
546 /// not one of the 14 built-in fonts provided as part of the PDF specification.
547 #[inline]
548 pub fn built_in(&self) -> Option<PdfFontBuiltin> {
549 self.built_in
550 }
551
552 /// Returns `true` if the data for this [PdfFont] is embedded in the containing [PdfDocument].
553 pub fn is_embedded(&self) -> Result<bool, PdfiumError> {
554 let result = unsafe { self.bindings().FPDFFont_GetIsEmbedded(self.handle) };
555
556 match result {
557 1 => Ok(true),
558 0 => Ok(false),
559 _ => Err(PdfiumError::PdfiumLibraryInternalError(
560 PdfiumInternalError::Unknown,
561 )),
562 }
563 }
564
565 /// Writes this [PdfFont] to a new byte buffer, returning the byte buffer.
566 ///
567 /// If this [PdfFont] is not embedded in the containing [PdfDocument], then the data
568 /// returned will be for the substitution font instead.
569 pub fn data(&self) -> Result<Vec<u8>, PdfiumError> {
570 // Retrieving the font data from Pdfium is a two-step operation. First, we call
571 // FPDFFont_GetFontData() with a null buffer; this will retrieve the length of
572 // the data in bytes. If the length is zero, then there is no data associated
573 // with this font.
574
575 // If the length is non-zero, then we reserve a byte buffer of the given
576 // length and call FPDFFont_GetFontData() again with a pointer to the buffer;
577 // this will write the font data to the buffer.
578
579 let mut out_buflen: usize = 0;
580
581 if self.bindings().is_true(unsafe {
582 self.bindings().FPDFFont_GetFontData(
583 self.handle,
584 std::ptr::null_mut(),
585 0,
586 &mut out_buflen,
587 )
588 }) {
589 // out_buflen now contains the length of the font data.
590
591 let buffer_length = out_buflen;
592
593 let mut buffer = create_byte_buffer(buffer_length);
594
595 let result = unsafe {
596 self.bindings().FPDFFont_GetFontData(
597 self.handle,
598 buffer.as_mut_ptr(),
599 buffer_length,
600 &mut out_buflen,
601 )
602 };
603
604 assert!(self.bindings().is_true(result));
605 assert_eq!(buffer_length, out_buflen);
606
607 Ok(buffer)
608 } else {
609 Err(PdfiumError::PdfiumLibraryInternalError(
610 PdfiumInternalError::Unknown,
611 ))
612 }
613 }
614
615 /// Returns a collection of all the [PdfFontGlyphs] defined for this [PdfFont] in the containing
616 /// `PdfDocument`.
617 ///
618 /// Note that documents typically include only the specific glyphs they need from any given font,
619 /// not the entire font glyphset. This is a PDF feature known as font subsetting. The collection
620 /// of glyphs returned by this function may therefore not cover the entire font glyphset.
621 #[inline]
622 pub fn glyphs(&self) -> &PdfFontGlyphs<'_> {
623 self.glyphs.initialize_len();
624 &self.glyphs
625 }
626}
627
628impl<'a> Drop for PdfFont<'a> {
629 /// Closes this [PdfFont], releasing held memory.
630 #[inline]
631 fn drop(&mut self) {
632 // The documentation for FPDFText_LoadFont() and FPDFText_LoadStandardFont() both state
633 // that the font loaded by the function can be closed by calling FPDFFont_Close().
634 // I had taken this to mean that _any_ FPDF_Font handle returned from a Pdfium function
635 // should be closed via FPDFFont_Close(), but testing suggests this is not the case;
636 // rather, it is only fonts specifically loaded by calling FPDFText_LoadFont() or
637 // FPDFText_LoadStandardFont() that need to be actively closed.
638
639 // In other words, retrieving a handle to a font that already exists in a document evidently
640 // does not allocate any additional resources, so we don't need to free anything.
641 // (Indeed, if we try to, Pdfium segfaults.)
642
643 if self.is_font_memory_loaded {
644 unsafe {
645 self.bindings().FPDFFont_Close(self.handle);
646 }
647 }
648 }
649}
650
651impl<'a> PdfiumLibraryBindingsAccessor<'a> for PdfFont<'a> {}
652
653#[cfg(feature = "thread_safe")]
654unsafe impl<'a> Send for PdfFont<'a> {}
655
656#[cfg(feature = "thread_safe")]
657unsafe impl<'a> Sync for PdfFont<'a> {}