Skip to main content

skia_safe/core/
strike_ref.rs

1use std::fmt;
2
3use skia_bindings as sb;
4
5use crate::{GlyphId, Rect, prelude::*, scalar};
6
7pub type StrikeRef = Handle<sb::SkStrikeRef>;
8unsafe_send_sync!(StrikeRef);
9
10impl NativeDrop for sb::SkStrikeRef {
11    fn drop(&mut self) {
12        unsafe { sb::C_SkStrikeRef_destruct(self) }
13    }
14}
15
16impl NativeClone for sb::SkStrikeRef {
17    fn clone(&self) -> Self {
18        construct(|s| unsafe { sb::C_SkStrikeRef_CopyConstruct(s, self) })
19    }
20}
21
22impl fmt::Debug for StrikeRef {
23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24        f.debug_struct("StrikeRef").finish()
25    }
26}
27
28impl StrikeRef {
29    pub fn get_width(&self, glyph: GlyphId) -> scalar {
30        unsafe { sb::C_SkStrikeRef_getWidth(self.native(), glyph) }
31    }
32
33    pub fn get_widths(&self, glyphs: &[GlyphId], widths: &mut [scalar]) {
34        assert_eq!(glyphs.len(), widths.len());
35        unsafe {
36            sb::C_SkStrikeRef_getWidths(
37                self.native(),
38                glyphs.as_ptr(),
39                glyphs.len(),
40                widths.as_mut_ptr(),
41                widths.len(),
42            )
43        }
44    }
45
46    pub fn get_widths_bounds(
47        &self,
48        glyphs: &[GlyphId],
49        mut widths: Option<&mut [scalar]>,
50        mut bounds: Option<&mut [Rect]>,
51    ) {
52        let count = glyphs.len();
53
54        {
55            if let Some(slice) = &widths {
56                assert_eq!(count, slice.len())
57            };
58            if let Some(slice) = &bounds {
59                assert_eq!(count, slice.len())
60            };
61        }
62
63        let widths_ptr = widths.as_ptr_or_null_mut();
64        let widths_count = widths.map_or(0, |slice| slice.len());
65        let bounds_ptr = bounds.native_mut().as_ptr_or_null_mut();
66        let bounds_count = bounds.map_or(0, |slice| slice.len());
67
68        unsafe {
69            sb::C_SkStrikeRef_getWidthsBounds(
70                self.native(),
71                glyphs.as_ptr(),
72                count,
73                widths_ptr,
74                widths_count,
75                bounds_ptr,
76                bounds_count,
77            )
78        }
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use crate::{Font, FontMgr, FontStyle};
85
86    #[test]
87    fn strike_ref_widths_match_font_widths() {
88        let font_mgr = FontMgr::new();
89        let typeface = font_mgr
90            .legacy_make_typeface(None, FontStyle::normal())
91            .unwrap();
92        let font = Font::new(typeface, 14.0);
93        let glyphs = font.text_to_glyphs_vec("StrikeRef");
94        assert!(!glyphs.is_empty());
95
96        let strike_ref = font.make_strike_ref();
97
98        let mut font_widths = vec![0.0; glyphs.len()];
99        font.get_widths(&glyphs, &mut font_widths);
100
101        let mut strike_widths = vec![0.0; glyphs.len()];
102        strike_ref.get_widths(&glyphs, &mut strike_widths);
103
104        assert_eq!(strike_widths, font_widths);
105        assert_eq!(strike_ref.get_width(glyphs[0]), font_widths[0]);
106
107        let mut font_bounds = vec![Default::default(); glyphs.len()];
108        let mut strike_bounds = vec![Default::default(); glyphs.len()];
109        font.get_widths_bounds(&glyphs, None, Some(&mut font_bounds), None);
110        strike_ref.get_widths_bounds(&glyphs, None, Some(&mut strike_bounds));
111
112        assert_eq!(strike_bounds, font_bounds);
113    }
114}