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