skia-safe 0.99.0

Safe Skia Bindings for Rust
Documentation
use std::fmt;

use skia_bindings as sb;

use crate::{GlyphId, Rect, prelude::*, scalar};

pub type StrikeRef = Handle<sb::SkStrikeRef>;
unsafe_send_sync!(StrikeRef);

impl NativeDrop for sb::SkStrikeRef {
    fn drop(&mut self) {
        unsafe { sb::C_SkStrikeRef_destruct(self) }
    }
}

impl NativeClone for sb::SkStrikeRef {
    fn clone(&self) -> Self {
        construct(|s| unsafe { sb::C_SkStrikeRef_CopyConstruct(s, self) })
    }
}

impl fmt::Debug for StrikeRef {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("StrikeRef").finish()
    }
}

impl StrikeRef {
    pub fn get_width(&self, glyph: GlyphId) -> scalar {
        unsafe { sb::C_SkStrikeRef_getWidth(self.native(), glyph) }
    }

    pub fn get_widths(&self, glyphs: &[GlyphId], widths: &mut [scalar]) {
        assert_eq!(glyphs.len(), widths.len());
        unsafe {
            sb::C_SkStrikeRef_getWidths(
                self.native(),
                glyphs.as_ptr(),
                glyphs.len(),
                widths.as_mut_ptr(),
                widths.len(),
            )
        }
    }

    pub fn get_widths_bounds(
        &self,
        glyphs: &[GlyphId],
        mut widths: Option<&mut [scalar]>,
        mut bounds: Option<&mut [Rect]>,
    ) {
        let count = glyphs.len();

        {
            if let Some(slice) = &widths {
                assert_eq!(count, slice.len())
            };
            if let Some(slice) = &bounds {
                assert_eq!(count, slice.len())
            };
        }

        let widths_ptr = widths.as_ptr_or_null_mut();
        let widths_count = widths.map_or(0, |slice| slice.len());
        let bounds_ptr = bounds.native_mut().as_ptr_or_null_mut();
        let bounds_count = bounds.map_or(0, |slice| slice.len());

        unsafe {
            sb::C_SkStrikeRef_getWidthsBounds(
                self.native(),
                glyphs.as_ptr(),
                count,
                widths_ptr,
                widths_count,
                bounds_ptr,
                bounds_count,
            )
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::{Font, FontMgr, FontStyle};

    #[test]
    fn strike_ref_widths_match_font_widths() {
        let font_mgr = FontMgr::new();
        let typeface = font_mgr
            .legacy_make_typeface(None, FontStyle::normal())
            .unwrap();
        let font = Font::new(typeface, 14.0);
        let glyphs = font.text_to_glyphs_vec("StrikeRef");
        assert!(!glyphs.is_empty());

        let strike_ref = font.make_strike_ref();

        let mut font_widths = vec![0.0; glyphs.len()];
        font.get_widths(&glyphs, &mut font_widths);

        let mut strike_widths = vec![0.0; glyphs.len()];
        strike_ref.get_widths(&glyphs, &mut strike_widths);

        assert_eq!(strike_widths, font_widths);
        assert_eq!(strike_ref.get_width(glyphs[0]), font_widths[0]);

        let mut font_bounds = vec![Default::default(); glyphs.len()];
        let mut strike_bounds = vec![Default::default(); glyphs.len()];
        font.get_widths_bounds(&glyphs, None, Some(&mut font_bounds), None);
        strike_ref.get_widths_bounds(&glyphs, None, Some(&mut strike_bounds));

        assert_eq!(strike_bounds, font_bounds);
    }
}