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