skia_safe/core/
font_arguments.rs

1use crate::prelude::*;
2use sb::SkFontArguments_Palette;
3use skia_bindings::{self as sb, SkFontArguments, SkFontArguments_VariationPosition};
4use std::{fmt, marker::PhantomData, mem};
5
6#[derive(Clone, Debug)]
7pub struct VariationPosition<'a> {
8    pub coordinates: &'a [variation_position::Coordinate],
9}
10
11pub mod variation_position {
12    use crate::FourByteTag;
13    use skia_bindings::SkFontArguments_VariationPosition_Coordinate;
14
15    #[derive(Copy, Clone, PartialEq, Default, Debug)]
16    #[repr(C)]
17    pub struct Coordinate {
18        pub axis: FourByteTag,
19        pub value: f32,
20    }
21
22    native_transmutable!(SkFontArguments_VariationPosition_Coordinate, Coordinate);
23}
24
25#[derive(Clone, Debug)]
26pub struct Palette<'a> {
27    pub index: i32,
28    pub overrides: &'a [palette::Override],
29}
30
31pub mod palette {
32    use crate::Color;
33    use skia_bindings::SkFontArguments_Palette_Override;
34
35    #[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
36    #[repr(C)]
37    pub struct Override {
38        pub index: u16,
39        pub color: Color,
40    }
41
42    native_transmutable!(SkFontArguments_Palette_Override, Override);
43}
44
45#[repr(C)]
46pub struct FontArguments<'vp, 'p> {
47    args: SkFontArguments,
48    pd_vp: PhantomData<&'vp [variation_position::Coordinate]>,
49    pd_p: PhantomData<&'p [palette::Override]>,
50}
51
52native_transmutable!(SkFontArguments, FontArguments<'_, '_>);
53
54impl Drop for FontArguments<'_, '_> {
55    fn drop(&mut self) {
56        unsafe { sb::C_SkFontArguments_destruct(self.native_mut()) }
57    }
58}
59
60impl Default for FontArguments<'_, '_> {
61    fn default() -> Self {
62        FontArguments::new()
63    }
64}
65
66impl fmt::Debug for FontArguments<'_, '_> {
67    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68        f.debug_struct("FontArguments")
69            .field("collection_index", &self.collection_index())
70            .field(
71                "variation_design_position",
72                &self.variation_design_position(),
73            )
74            .field("palette", &self.palette())
75            .finish()
76    }
77}
78
79impl FontArguments<'_, '_> {
80    pub fn new() -> Self {
81        Self::construct(|fa| unsafe {
82            sb::C_SkFontArguments_construct(fa);
83        })
84    }
85
86    pub fn set_collection_index(&mut self, collection_index: usize) -> &mut Self {
87        self.native_mut().fCollectionIndex = collection_index.try_into().unwrap();
88        self
89    }
90
91    // This function consumes self for it to be able to change its lifetime,
92    // because it borrows the coordinates referenced by [`VariationPosition`].
93    //
94    // If we would return `Self`, position's Coordinates would not be borrowed.
95    pub fn set_variation_design_position(mut self, position: VariationPosition) -> FontArguments {
96        let position = SkFontArguments_VariationPosition {
97            coordinates: position.coordinates.native().as_ptr(),
98            coordinateCount: position.coordinates.len().try_into().unwrap(),
99        };
100        unsafe {
101            sb::C_SkFontArguments_setVariationDesignPosition(self.native_mut(), position);
102            // note: we are _not_ returning Self here, but VariationPosition with a
103            // changed lifetime.
104            mem::transmute(self)
105        }
106    }
107
108    pub fn collection_index(&self) -> usize {
109        self.native().fCollectionIndex.try_into().unwrap()
110    }
111
112    pub fn variation_design_position(&self) -> VariationPosition {
113        unsafe {
114            let position = sb::C_SkFontArguments_getVariationDesignPosition(self.native());
115            VariationPosition {
116                coordinates: safer::from_raw_parts(
117                    position.coordinates as *const _,
118                    position.coordinateCount.try_into().unwrap(),
119                ),
120            }
121        }
122    }
123
124    // This function consumes `self` for it to be able to change its lifetime, because it borrows
125    // the coordinates referenced by `[Palette]`.
126    pub fn set_palette(mut self, palette: Palette) -> FontArguments {
127        let palette = SkFontArguments_Palette {
128            index: palette.index,
129            overrides: palette.overrides.native().as_ptr(),
130            overrideCount: palette.overrides.len().try_into().unwrap(),
131        };
132        unsafe {
133            sb::C_SkFontArguments_setPalette(self.native_mut(), palette);
134            mem::transmute(self)
135        }
136    }
137
138    pub fn palette(&self) -> Palette {
139        unsafe {
140            let palette = sb::C_SkFontArguments_getPalette(self.native());
141            Palette {
142                index: palette.index,
143                overrides: safer::from_raw_parts(
144                    palette.overrides as *const _,
145                    palette.overrideCount.try_into().unwrap(),
146                ),
147            }
148        }
149    }
150}
151
152#[test]
153fn test_font_arguments_with_no_coordinates() {
154    let fa = FontArguments::new();
155    let coordinates = fa.variation_design_position();
156    assert_eq!(coordinates.coordinates, []);
157}
158
159#[test]
160#[allow(clippy::float_cmp)]
161fn access_coordinates() {
162    let coordinates = Box::new([variation_position::Coordinate {
163        axis: 0.into(),
164        value: 1.0,
165    }]);
166    let args = FontArguments::new();
167    let pos = VariationPosition {
168        coordinates: coordinates.as_ref(),
169    };
170    let args = args.set_variation_design_position(pos);
171    assert_eq!(args.variation_design_position().coordinates[0].value, 1.0);
172    drop(args);
173}