Skip to main content

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