1use std::{fmt, marker::PhantomData, mem};
2
3use skia_bindings::{
4 self as sb, SkFontArguments, SkFontArguments_Palette, SkFontArguments_VariationPosition,
5};
6
7use crate::prelude::*;
8
9#[repr(C)]
11pub struct FontArguments<'vp, 'p> {
12 args: SkFontArguments,
13 pd_vp: PhantomData<&'vp [variation_position::Coordinate]>,
14 pd_p: PhantomData<&'p [palette::Override]>,
15}
16
17native_transmutable!(SkFontArguments, FontArguments<'_, '_>);
18
19#[derive(Clone, Debug)]
24pub struct VariationPosition<'a> {
25 pub coordinates: &'a [variation_position::Coordinate],
26}
27
28pub mod variation_position {
29 use crate::FourByteTag;
30 use skia_bindings::SkFontArguments_VariationPosition_Coordinate;
31
32 #[derive(Copy, Clone, PartialEq, Default, Debug)]
34 #[repr(C)]
35 pub struct Coordinate {
36 pub axis: FourByteTag,
37 pub value: f32,
38 }
39
40 native_transmutable!(SkFontArguments_VariationPosition_Coordinate, Coordinate);
41}
42
43#[derive(Clone, Debug)]
51pub struct Palette<'a> {
52 pub index: i32,
53 pub overrides: &'a [palette::Override],
54}
55
56pub mod palette {
57 use crate::Color;
58 use skia_bindings::SkFontArguments_Palette_Override;
59
60 #[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
62 #[repr(C)]
63 pub struct Override {
64 pub index: u16,
65 pub color: Color,
66 }
67
68 native_transmutable!(SkFontArguments_Palette_Override, Override);
69}
70
71impl Drop for FontArguments<'_, '_> {
72 fn drop(&mut self) {
73 unsafe { sb::C_SkFontArguments_destruct(self.native_mut()) }
74 }
75}
76
77impl Default for FontArguments<'_, '_> {
78 fn default() -> Self {
79 FontArguments::new()
80 }
81}
82
83impl fmt::Debug for FontArguments<'_, '_> {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 f.debug_struct("FontArguments")
86 .field("collection_index", &self.collection_index())
87 .field(
88 "variation_design_position",
89 &self.variation_design_position(),
90 )
91 .field("palette", &self.palette())
92 .field("synthetic_bold", &self.synthetic_bold())
93 .field("synthetic_oblique", &self.synthetic_oblique())
94 .finish()
95 }
96}
97
98impl FontArguments<'_, '_> {
99 pub fn new() -> Self {
101 Self::construct(|fa| unsafe {
102 sb::C_SkFontArguments_construct(fa);
103 })
104 }
105
106 pub fn set_collection_index(&mut self, collection_index: usize) -> &mut Self {
113 self.native_mut().fCollectionIndex = collection_index.try_into().unwrap();
114 self
115 }
116
117 pub fn set_variation_design_position(mut self, position: VariationPosition) -> FontArguments {
131 let position = SkFontArguments_VariationPosition {
132 coordinates: position.coordinates.native().as_ptr(),
133 coordinateCount: position.coordinates.len().try_into().unwrap(),
134 };
135 unsafe {
136 sb::C_SkFontArguments_setVariationDesignPosition(self.native_mut(), position);
137 mem::transmute(self)
140 }
141 }
142
143 pub fn collection_index(&self) -> usize {
145 self.native().fCollectionIndex.try_into().unwrap()
146 }
147
148 pub fn variation_design_position(&self) -> VariationPosition {
150 unsafe {
151 let position = sb::C_SkFontArguments_getVariationDesignPosition(self.native());
152 VariationPosition {
153 coordinates: safer::from_raw_parts(
154 position.coordinates as *const _,
155 position.coordinateCount.try_into().unwrap(),
156 ),
157 }
158 }
159 }
160
161 pub fn set_palette(mut self, palette: Palette) -> FontArguments {
170 let palette = SkFontArguments_Palette {
171 index: palette.index,
172 overrides: palette.overrides.native().as_ptr(),
173 overrideCount: palette.overrides.len().try_into().unwrap(),
174 };
175 unsafe {
176 sb::C_SkFontArguments_setPalette(self.native_mut(), palette);
177 mem::transmute(self)
178 }
179 }
180
181 pub fn palette(&self) -> Palette {
183 unsafe {
184 let palette = sb::C_SkFontArguments_getPalette(self.native());
185 Palette {
186 index: palette.index,
187 overrides: safer::from_raw_parts(
188 palette.overrides as *const _,
189 palette.overrideCount.try_into().unwrap(),
190 ),
191 }
192 }
193 }
194
195 pub fn set_synthetic_bold(&mut self, synthetic_bold: impl Into<Option<bool>>) -> &mut Self {
200 unsafe {
201 sb::C_SkFontArguments_setSyntheticBold(
202 self.native_mut(),
203 option_bool_to_ffi(synthetic_bold.into()),
204 );
205 }
206 self
207 }
208
209 pub fn synthetic_bold(&self) -> Option<bool> {
211 ffi_to_option_bool(unsafe { sb::C_SkFontArguments_getSyntheticBold(self.native()) })
212 }
213
214 pub fn set_synthetic_oblique(
219 &mut self,
220 synthetic_oblique: impl Into<Option<bool>>,
221 ) -> &mut Self {
222 unsafe {
223 sb::C_SkFontArguments_setSyntheticOblique(
224 self.native_mut(),
225 option_bool_to_ffi(synthetic_oblique.into()),
226 );
227 }
228 self
229 }
230
231 pub fn synthetic_oblique(&self) -> Option<bool> {
233 ffi_to_option_bool(unsafe { sb::C_SkFontArguments_getSyntheticOblique(self.native()) })
234 }
235}
236
237fn option_bool_to_ffi(value: Option<bool>) -> i32 {
238 match value {
239 Some(true) => 1,
240 Some(false) => 0,
241 None => -1,
242 }
243}
244
245fn ffi_to_option_bool(value: i32) -> Option<bool> {
246 match value {
247 1 => Some(true),
248 0 => Some(false),
249 _ => None,
250 }
251}
252
253#[cfg(test)]
254mod tests {
255 use super::*;
256
257 #[test]
258 fn test_font_arguments_with_no_coordinates() {
259 let fa = FontArguments::new();
260 let coordinates = fa.variation_design_position();
261 assert_eq!(coordinates.coordinates, []);
262 }
263
264 #[test]
265 #[allow(clippy::float_cmp)]
266 fn access_coordinates() {
267 let coordinates = Box::new([variation_position::Coordinate {
268 axis: 0.into(),
269 value: 1.0,
270 }]);
271 let args = FontArguments::new();
272 let pos = VariationPosition {
273 coordinates: coordinates.as_ref(),
274 };
275 let args = args.set_variation_design_position(pos);
276 assert_eq!(args.variation_design_position().coordinates[0].value, 1.0);
277 drop(args);
278 }
279
280 #[test]
281 fn synthetic_style_flags_roundtrip() {
282 let mut args = FontArguments::new();
283
284 assert_eq!(args.synthetic_bold(), None);
285 assert_eq!(args.synthetic_oblique(), None);
286
287 args.set_synthetic_bold(Some(true));
288 assert_eq!(args.synthetic_bold(), Some(true));
289
290 args.set_synthetic_bold(Some(false));
291 assert_eq!(args.synthetic_bold(), Some(false));
292
293 args.set_synthetic_bold(None);
294 assert_eq!(args.synthetic_bold(), None);
295
296 args.set_synthetic_oblique(Some(true));
297 assert_eq!(args.synthetic_oblique(), Some(true));
298
299 args.set_synthetic_oblique(Some(false));
300 assert_eq!(args.synthetic_oblique(), Some(false));
301
302 args.set_synthetic_oblique(None);
303 assert_eq!(args.synthetic_oblique(), None);
304 }
305}