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