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