pdfium_render/pdf/document/page/text/
char.rs

1//! Defines the [PdfPageTextChar] struct, exposing functionality related to a single character
2//! in a [PdfPageTextChars] collection.
3
4use crate::bindgen::{FPDF_DOCUMENT, FPDF_PAGE, FPDF_TEXTPAGE, FS_MATRIX, FS_RECTF};
5use crate::bindings::PdfiumLibraryBindings;
6use crate::create_transform_getters;
7use crate::error::{PdfiumError, PdfiumInternalError};
8use crate::pdf::color::PdfColor;
9use crate::pdf::document::page::object::text::PdfPageTextRenderMode;
10use crate::pdf::document::page::text::chars::PdfPageTextCharIndex;
11use crate::pdf::font::{FpdfFontDescriptorFlags, PdfFontWeight};
12use crate::pdf::matrix::{PdfMatrix, PdfMatrixValue};
13use crate::pdf::points::PdfPoints;
14use crate::pdf::rect::PdfRect;
15use crate::utils::mem::create_byte_buffer;
16use std::convert::TryInto;
17use std::ffi::c_void;
18
19#[cfg(any(
20    feature = "pdfium_future",
21    feature = "pdfium_7350",
22    feature = "pdfium_7215",
23    feature = "pdfium_7123",
24    feature = "pdfium_6996",
25    feature = "pdfium_6721",
26    feature = "pdfium_6666",
27    feature = "pdfium_6611"
28))]
29use {
30    crate::pdf::document::page::object::text::PdfPageTextObject,
31    crate::pdf::document::page::PdfPageObjectOwnership,
32};
33
34#[cfg(doc)]
35use crate::pdf::document::page::text::PdfPageTextChars;
36
37/// A single character in a [PdfPageTextChars] collection.
38pub struct PdfPageTextChar<'a> {
39    document_handle: FPDF_DOCUMENT,
40    page_handle: FPDF_PAGE,
41    text_page_handle: FPDF_TEXTPAGE,
42    index: i32,
43    bindings: &'a dyn PdfiumLibraryBindings,
44}
45
46impl<'a> PdfPageTextChar<'a> {
47    #[inline]
48    pub(crate) fn from_pdfium(
49        document_handle: FPDF_DOCUMENT,
50        page_handle: FPDF_PAGE,
51        text_page_handle: FPDF_TEXTPAGE,
52        index: i32,
53        bindings: &'a dyn PdfiumLibraryBindings,
54    ) -> Self {
55        PdfPageTextChar {
56            document_handle,
57            page_handle,
58            text_page_handle,
59            index,
60            bindings,
61        }
62    }
63
64    /// Returns the internal `FPDF_DOCUMENT` handle of the [PdfDocument] containing this [PdfPageTextChar].
65    #[inline]
66    pub(crate) fn document_handle(&self) -> FPDF_DOCUMENT {
67        self.document_handle
68    }
69
70    /// Returns the internal `FPDF_PAGE` handle of the [PdfPage] containing this [PdfPageTextChar].
71    #[inline]
72    pub(crate) fn page_handle(&self) -> FPDF_PAGE {
73        self.page_handle
74    }
75
76    /// Returns the internal `FPDF_TEXTPAGE` handle for this [PdfPageTextChar].
77    #[inline]
78    pub(crate) fn text_page_handle(&self) -> FPDF_TEXTPAGE {
79        self.text_page_handle
80    }
81
82    /// Returns the [PdfiumLibraryBindings] used by this [PdfPageTextChar].
83    #[inline]
84    pub fn bindings(&self) -> &'a dyn PdfiumLibraryBindings {
85        self.bindings
86    }
87
88    #[inline]
89    pub fn index(&self) -> PdfPageTextCharIndex {
90        self.index as PdfPageTextCharIndex
91    }
92
93    /// Returns the raw Unicode literal value for this character.
94    ///
95    /// To return Rust's Unicode `char` representation of this Unicode literal, use the
96    /// [PdfPageTextChar::unicode_char] function. To return the string representation of this
97    /// Unicode literal, use the [PdfPageTextChar::unicode_string] function.
98    #[inline]
99    pub fn unicode_value(&self) -> u32 {
100        self.bindings
101            .FPDFText_GetUnicode(self.text_page_handle, self.index)
102    }
103
104    /// Returns Rust's Unicode `char` representation for this character, if available.
105    ///
106    /// To return the raw Unicode literal value for this character,
107    /// use the [PdfPageTextChar::unicode_value] function. To return the string representation of
108    /// this `char`, use the [PdfPageTextChar::unicode_string] function.
109    #[inline]
110    pub fn unicode_char(&self) -> Option<char> {
111        char::from_u32(self.unicode_value())
112    }
113
114    /// Returns a string containing Rust's Unicode `char` representation for this character,
115    /// if available.
116    ///
117    /// To return the raw Unicode literal value for this character,
118    /// use the [PdfPageTextChar::unicode_value] function. To return Rust's Unicode `char`
119    /// representation of this Unicode literal, use the [PdfPageTextChar::unicode_char] function.
120    #[inline]
121    pub fn unicode_string(&self) -> Option<String> {
122        self.unicode_char().map(|char| char.to_string())
123    }
124
125    /// Returns the effective size of this character when rendered, taking into account both the
126    /// font size applied to the character as well as any vertical scale factor applied
127    /// to the character's transformation matrix.
128    ///
129    /// To retrieve only the specified font size, ignoring any vertical scaling, use the
130    /// [PdfPageTextChar::unscaled_font_size] function.
131    #[inline]
132    pub fn scaled_font_size(&self) -> PdfPoints {
133        PdfPoints::new(self.unscaled_font_size().value * self.get_vertical_scale())
134    }
135
136    /// Returns the font size applied to this character.
137    ///
138    /// Note that the effective size of the character when rendered may differ from the font size
139    /// if a scaling factor has been applied to this character's transformation matrix.
140    /// To retrieve the effective font size, taking vertical scaling into account, use the
141    /// [PdfPageTextChar::scaled_font_size] function.
142    #[inline]
143    pub fn unscaled_font_size(&self) -> PdfPoints {
144        PdfPoints::new(
145            self.bindings
146                .FPDFText_GetFontSize(self.text_page_handle, self.index) as f32,
147        )
148    }
149
150    /// Returns the font name and raw font descriptor flags for the font applied to this character.
151    fn font(&self) -> (Option<String>, FpdfFontDescriptorFlags) {
152        // Retrieving the font name from Pdfium is a two-step operation. First, we call
153        // FPDFText_GetFontInfo() with a null buffer; this will retrieve the length of
154        // the font name in bytes. If the length is zero, then there is no font name.
155
156        // If the length is non-zero, then we reserve a byte buffer of the given
157        // length and call FPDFText_GetFontInfo() again with a pointer to the buffer;
158        // this will write the font name into the buffer. Unlike most text handling in
159        // Pdfium, font names are returned in UTF-8 format.
160
161        let mut flags = 0;
162
163        let buffer_length = self.bindings.FPDFText_GetFontInfo(
164            self.text_page_handle,
165            self.index,
166            std::ptr::null_mut(),
167            0,
168            &mut flags,
169        );
170
171        if buffer_length == 0 {
172            // The font name is not present.
173
174            return (
175                None,
176                FpdfFontDescriptorFlags::from_bits_truncate(flags as u32),
177            );
178        }
179
180        let mut buffer = create_byte_buffer(buffer_length as usize);
181
182        let result = self.bindings.FPDFText_GetFontInfo(
183            self.text_page_handle,
184            self.index,
185            buffer.as_mut_ptr() as *mut c_void,
186            buffer_length,
187            &mut flags,
188        );
189
190        assert_eq!(result, buffer_length);
191
192        (
193            String::from_utf8(buffer)
194                // Trim any trailing nulls. All strings returned from Pdfium are generally terminated
195                // by one null byte.
196                .map(|str| str.trim_end_matches(char::from(0)).to_owned())
197                .ok(),
198            FpdfFontDescriptorFlags::from_bits_truncate(flags as u32),
199        )
200    }
201
202    /// Returns the name of the font applied to this character.
203    #[inline]
204    pub fn font_name(&self) -> String {
205        self.font().0.unwrap_or_default()
206    }
207
208    /// Returns the weight of the font applied to this character.
209    ///
210    /// Pdfium may not reliably return the correct value of this property for built-in fonts.
211    #[inline]
212    pub fn font_weight(&self) -> Option<PdfFontWeight> {
213        PdfFontWeight::from_pdfium(
214            self.bindings
215                .FPDFText_GetFontWeight(self.text_page_handle, self.index),
216        )
217    }
218
219    /// Returns the raw font descriptor bitflags for the font applied to this character.
220    #[inline]
221    fn font_flags_bits(&self) -> FpdfFontDescriptorFlags {
222        self.font().1
223    }
224
225    /// Returns `true` if all the glyphs in the font applied to this character have the same width.
226    ///
227    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
228    pub fn font_is_fixed_pitch(&self) -> bool {
229        self.font_flags_bits()
230            .contains(FpdfFontDescriptorFlags::FIXED_PITCH_BIT_1)
231    }
232
233    /// Returns `true` if the glyphs in the font applied to this character have variable widths.
234    ///
235    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
236    #[inline]
237    pub fn font_is_proportional_pitch(&self) -> bool {
238        !self.font_is_fixed_pitch()
239    }
240
241    /// Returns `true` if one or more glyphs in the font applied to this character have serifs -
242    /// short strokes drawn at an angle on the top or bottom of glyph stems to decorate the glyphs.
243    /// For example, Times New Roman is a serif font.
244    ///
245    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
246    pub fn font_is_serif(&self) -> bool {
247        self.font_flags_bits()
248            .contains(FpdfFontDescriptorFlags::SERIF_BIT_2)
249    }
250
251    /// Returns `true` if no glyphs in the font applied to this character have serifs -
252    /// short strokes drawn at an angle on the top or bottom of glyph stems to decorate the glyphs.
253    /// For example, Helvetica is a sans-serif font.
254    ///
255    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
256    #[inline]
257    pub fn font_is_sans_serif(&self) -> bool {
258        !self.font_is_serif()
259    }
260
261    /// Returns `true` if the font applied to this character contains glyphs outside the
262    /// Adobe standard Latin character set.
263    ///
264    /// This classification of non-symbolic and symbolic fonts is peculiar to PDF. A font may
265    /// contain additional characters that are used in Latin writing systems but are outside the
266    /// Adobe standard Latin character set; PDF considers such a font to be symbolic.
267    ///
268    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
269    pub fn font_is_symbolic(&self) -> bool {
270        // This flag bit and the non-symbolic flag bit cannot both be set or both be clear.
271
272        self.font_flags_bits()
273            .contains(FpdfFontDescriptorFlags::SYMBOLIC_BIT_3)
274    }
275
276    /// Returns `true` if the font applied to this character does not contain glyphs outside the
277    /// Adobe standard Latin character set.
278    ///
279    /// This classification of non-symbolic and symbolic fonts is peculiar to PDF. A font may
280    /// contain additional characters that are used in Latin writing systems but are outside the
281    /// Adobe standard Latin character set; PDF considers such a font to be symbolic.
282    ///
283    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
284    pub fn font_is_non_symbolic(&self) -> bool {
285        // This flag bit and the symbolic flag bit cannot both be set or both be clear.
286
287        self.font_flags_bits()
288            .contains(FpdfFontDescriptorFlags::NON_SYMBOLIC_BIT_6)
289    }
290
291    /// Returns `true` if the glyphs in the font applied to this character are designed to resemble
292    /// cursive handwriting.
293    ///
294    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
295    pub fn font_is_cursive(&self) -> bool {
296        self.font_flags_bits()
297            .contains(FpdfFontDescriptorFlags::SCRIPT_BIT_4)
298    }
299
300    /// Returns `true` if the glyphs in the font applied to this character include dominant
301    /// vertical strokes that are slanted.
302    ///
303    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
304    pub fn font_is_italic(&self) -> bool {
305        self.font_flags_bits()
306            .contains(FpdfFontDescriptorFlags::ITALIC_BIT_7)
307    }
308
309    /// Returns `true` if the font applied to this character contains no lowercase letters by design.
310    ///
311    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
312    pub fn font_is_all_caps(&self) -> bool {
313        self.font_flags_bits()
314            .contains(FpdfFontDescriptorFlags::ALL_CAP_BIT_17)
315    }
316
317    /// Returns `true` if the lowercase letters in the font applied to this character have the
318    /// same shapes as the corresponding uppercase letters but are sized proportionally
319    /// so they have the same size and stroke weight as lowercase glyphs in the same typeface family.
320    ///
321    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
322    pub fn font_is_small_caps(&self) -> bool {
323        self.font_flags_bits()
324            .contains(FpdfFontDescriptorFlags::SMALL_CAP_BIT_18)
325    }
326
327    /// Returns `true` if bold glyphs in the font applied to this character are painted with
328    /// extra pixels at very small font sizes.
329    ///
330    /// Typically when glyphs are painted at small sizes on low-resolution devices, individual strokes
331    /// of bold glyphs may appear only one pixel wide. Because this is the minimum width of a pixel
332    /// based device, individual strokes of non-bold glyphs may also appear as one pixel wide
333    /// and therefore cannot be distinguished from bold glyphs. If this flag is set, individual
334    /// strokes of bold glyphs may be thickened at small font sizes.
335    ///
336    /// Pdfium may not reliably return the correct value of this flag for built-in fonts.
337    pub fn font_is_bold_reenforced(&self) -> bool {
338        self.font_flags_bits()
339            .contains(FpdfFontDescriptorFlags::FORCE_BOLD_BIT_19)
340    }
341
342    #[cfg(any(
343        feature = "pdfium_future",
344        feature = "pdfium_7350",
345        feature = "pdfium_7215",
346        feature = "pdfium_7123",
347        feature = "pdfium_6996",
348        feature = "pdfium_6721",
349        feature = "pdfium_6666",
350        feature = "pdfium_6611"
351    ))]
352    /// Returns the page text object that contains this character.
353    pub fn text_object(&self) -> Result<PdfPageTextObject, PdfiumError> {
354        let object_handle = self
355            .bindings()
356            .FPDFText_GetTextObject(self.text_page_handle(), self.index);
357
358        if object_handle.is_null() {
359            Err(PdfiumError::PdfiumLibraryInternalError(
360                PdfiumInternalError::Unknown,
361            ))
362        } else {
363            Ok(PdfPageTextObject::from_pdfium(
364                object_handle,
365                PdfPageObjectOwnership::owned_by_page(self.document_handle(), self.page_handle()),
366                self.bindings(),
367            ))
368        }
369    }
370
371    #[cfg(any(
372        feature = "pdfium_future",
373        feature = "pdfium_7350",
374        feature = "pdfium_7215",
375        feature = "pdfium_7123",
376        feature = "pdfium_6996",
377        feature = "pdfium_6721",
378        feature = "pdfium_6666",
379        feature = "pdfium_6611"
380    ))]
381    /// Returns the text rendering mode for this character.
382    pub fn render_mode(&self) -> Result<PdfPageTextRenderMode, PdfiumError> {
383        self.text_object()
384            .map(|text_object| text_object.render_mode())
385    }
386
387    #[cfg(any(
388        feature = "pdfium_6569",
389        feature = "pdfium_6555",
390        feature = "pdfium_6490",
391        feature = "pdfium_6406",
392        feature = "pdfium_6337",
393        feature = "pdfium_6295",
394        feature = "pdfium_6259",
395        feature = "pdfium_6164",
396        feature = "pdfium_6124",
397        feature = "pdfium_6110",
398        feature = "pdfium_6084",
399        feature = "pdfium_6043",
400        feature = "pdfium_6015",
401        feature = "pdfium_5961"
402    ))]
403    /// Returns the text rendering mode for this character.
404    pub fn render_mode(&self) -> Result<PdfPageTextRenderMode, PdfiumError> {
405        PdfPageTextRenderMode::from_pdfium(
406            self.bindings()
407                .FPDFText_GetTextRenderMode(self.text_page_handle, self.index),
408        )
409    }
410
411    /// Returns the fill color applied to this character.
412    pub fn fill_color(&self) -> Result<PdfColor, PdfiumError> {
413        let mut r = 0;
414
415        let mut g = 0;
416
417        let mut b = 0;
418
419        let mut a = 0;
420
421        if self.bindings.is_true(self.bindings.FPDFText_GetFillColor(
422            self.text_page_handle,
423            self.index,
424            &mut r,
425            &mut g,
426            &mut b,
427            &mut a,
428        )) {
429            Ok(PdfColor::new(
430                r.try_into()
431                    .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
432                g.try_into()
433                    .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
434                b.try_into()
435                    .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
436                a.try_into()
437                    .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
438            ))
439        } else {
440            Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
441        }
442    }
443
444    /// Returns the stroke color applied to this character.
445    pub fn stroke_color(&self) -> Result<PdfColor, PdfiumError> {
446        let mut r = 0;
447
448        let mut g = 0;
449
450        let mut b = 0;
451
452        let mut a = 0;
453
454        if self
455            .bindings()
456            .is_true(self.bindings.FPDFText_GetStrokeColor(
457                self.text_page_handle(),
458                self.index,
459                &mut r,
460                &mut g,
461                &mut b,
462                &mut a,
463            ))
464        {
465            Ok(PdfColor::new(
466                r.try_into()
467                    .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
468                g.try_into()
469                    .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
470                b.try_into()
471                    .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
472                a.try_into()
473                    .map_err(PdfiumError::UnableToConvertPdfiumColorValueToRustu8)?,
474            ))
475        } else {
476            Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
477        }
478    }
479
480    /// Returns the rotation angle of this character, expressed in degrees.
481    #[inline]
482    pub fn angle_degrees(&self) -> Result<f32, PdfiumError> {
483        self.angle_radians().map(|result| result.to_degrees())
484    }
485
486    /// Returns the rotation angle of this character, expressed in radians.
487    #[inline]
488    pub fn angle_radians(&self) -> Result<f32, PdfiumError> {
489        let result = self
490            .bindings
491            .FPDFText_GetCharAngle(self.text_page_handle, self.index);
492
493        if result == -1.0 {
494            Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
495        } else {
496            Ok(result)
497        }
498    }
499
500    /// Returns a precise bounding box for this character, taking the character's specific
501    /// shape into account.
502    ///
503    /// To return a loose bounding box that contains the entire glyph bounds, use the
504    /// [PdfPageTextChar::loose_bounds] function.
505    pub fn tight_bounds(&self) -> Result<PdfRect, PdfiumError> {
506        let mut left = 0.0;
507
508        let mut bottom = 0.0;
509
510        let mut right = 0.0;
511
512        let mut top = 0.0;
513
514        let result = self.bindings().FPDFText_GetCharBox(
515            self.text_page_handle(),
516            self.index,
517            &mut left,
518            &mut right,
519            &mut bottom,
520            &mut top,
521        );
522
523        PdfRect::from_pdfium_as_result(
524            result,
525            FS_RECTF {
526                left: left as f32,
527                top: top as f32,
528                right: right as f32,
529                bottom: bottom as f32,
530            },
531            self.bindings(),
532        )
533    }
534
535    /// Returns a loose bounding box for this character, containing the entire glyph bounds.
536    ///
537    /// To return a tight bounding box that takes this character's specific shape into
538    /// account, use the [PdfPageTextChar::tight_bounds] function.
539    pub fn loose_bounds(&self) -> Result<PdfRect, PdfiumError> {
540        let mut bounds = FS_RECTF {
541            left: 0.0,
542            top: 0.0,
543            right: 0.0,
544            bottom: 0.0,
545        };
546
547        let result = self.bindings.FPDFText_GetLooseCharBox(
548            self.text_page_handle(),
549            self.index,
550            &mut bounds,
551        );
552
553        PdfRect::from_pdfium_as_result(result, bounds, self.bindings())
554    }
555
556    /// Returns the current raw transformation matrix for this character.
557    fn get_matrix_impl(&self) -> Result<PdfMatrix, PdfiumError> {
558        let mut matrix = FS_MATRIX {
559            a: 0.0,
560            b: 0.0,
561            c: 0.0,
562            d: 0.0,
563            e: 0.0,
564            f: 0.0,
565        };
566
567        if self.bindings().is_true(self.bindings().FPDFText_GetMatrix(
568            self.text_page_handle(),
569            self.index,
570            &mut matrix,
571        )) {
572            Ok(PdfMatrix::from_pdfium(matrix))
573        } else {
574            Err(PdfiumError::PdfiumLibraryInternalError(
575                PdfiumInternalError::Unknown,
576            ))
577        }
578    }
579
580    create_transform_getters!(
581        "this [PdfPageTextChar]",
582        "this [PdfPageTextChar].",
583        "this [PdfPageTextChar],"
584    );
585
586    /// Returns the origin x and y positions of this character relative to its containing page.
587    pub fn origin(&self) -> Result<(PdfPoints, PdfPoints), PdfiumError> {
588        let mut x = 0.0;
589
590        let mut y = 0.0;
591
592        if self
593            .bindings()
594            .is_true(self.bindings().FPDFText_GetCharOrigin(
595                self.text_page_handle(),
596                self.index,
597                &mut x,
598                &mut y,
599            ))
600        {
601            Ok((PdfPoints::new(x as f32), PdfPoints::new(y as f32)))
602        } else {
603            Err(PdfiumError::PdfiumLibraryInternalError(
604                PdfiumInternalError::Unknown,
605            ))
606        }
607    }
608
609    /// Returns the origin x position of this character relative to its containing page.
610    #[inline]
611    pub fn origin_x(&self) -> Result<PdfPoints, PdfiumError> {
612        self.origin().map(|result| result.0)
613    }
614
615    /// Returns the origin y position of this character relative to its containing page.
616    #[inline]
617    pub fn origin_y(&self) -> Result<PdfPoints, PdfiumError> {
618        self.origin().map(|result| result.1)
619    }
620
621    /// Returns `true` if the glyph shape of this character descends below the font baseline.
622    #[inline]
623    pub fn has_descender(&self) -> bool {
624        self.tight_bounds()
625            .map(|bounds| bounds.bottom().value)
626            .unwrap_or(0.0)
627            < self
628                .loose_bounds()
629                .map(|bounds| bounds.bottom().value)
630                .unwrap_or(0.0)
631    }
632
633    /// Returns `true` if this character was generated by Pdfium. This can be the case for
634    /// certain spacing, breaking, and justification-related characters.
635    #[inline]
636    pub fn is_generated(&self) -> Result<bool, PdfiumError> {
637        match self
638            .bindings()
639            .FPDFText_IsGenerated(self.text_page_handle(), self.index)
640        {
641            1 => Ok(true),
642            0 => Ok(false),
643            _ => Err(PdfiumError::PdfiumLibraryInternalError(
644                PdfiumInternalError::Unknown,
645            )),
646        }
647    }
648
649    #[cfg(any(
650        feature = "pdfium_future",
651        feature = "pdfium_7350",
652        feature = "pdfium_7215",
653        feature = "pdfium_7123",
654        feature = "pdfium_6996",
655        feature = "pdfium_6721",
656        feature = "pdfium_6666",
657        feature = "pdfium_6611",
658        feature = "pdfium_6569",
659        feature = "pdfium_6555",
660        feature = "pdfium_6490",
661        feature = "pdfium_6406",
662        feature = "pdfium_6337",
663        feature = "pdfium_6295",
664        feature = "pdfium_6259",
665        feature = "pdfium_6164",
666        feature = "pdfium_6124",
667        feature = "pdfium_6110",
668        feature = "pdfium_6084",
669        feature = "pdfium_6043",
670        feature = "pdfium_6015",
671    ))]
672    /// Returns `true` if this character is recognized as a hyphen by Pdfium.
673    #[inline]
674    pub fn is_hyphen(&self) -> Result<bool, PdfiumError> {
675        match self
676            .bindings()
677            .FPDFText_IsHyphen(self.text_page_handle(), self.index)
678        {
679            1 => Ok(true),
680            0 => Ok(false),
681            _ => Err(PdfiumError::PdfiumLibraryInternalError(
682                PdfiumInternalError::Unknown,
683            )),
684        }
685    }
686}