1use std::{fmt, ptr};
2
3use skia_bindings::{self as sb, SkFont, SkFont_PrivFlags};
4
5use crate::{
6 interop::VecSink, prelude::*, scalar, EncodedText, FontHinting, FontMetrics, GlyphId, Paint,
7 Path, Point, Rect, Typeface, Unichar,
8};
9
10pub use skia_bindings::SkFont_Edging as Edging;
11variant_name!(Edging::Alias);
12
13pub type Font = Handle<SkFont>;
14unsafe_send_sync!(Font);
15
16impl NativeDrop for SkFont {
17 fn drop(&mut self) {
18 unsafe { sb::C_SkFont_destruct(self) }
19 }
20}
21
22impl NativeClone for SkFont {
23 fn clone(&self) -> Self {
24 construct(|f| unsafe { sb::C_SkFont_CopyConstruct(f, self) })
25 }
26}
27
28impl NativePartialEq for SkFont {
29 fn eq(&self, rhs: &Self) -> bool {
30 unsafe { sb::C_SkFont_Equals(self, rhs) }
31 }
32}
33
34impl Default for Font {
35 fn default() -> Self {
36 Self::from_native_c(unsafe { SkFont::new() })
37 }
38}
39
40impl fmt::Debug for Font {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 f.debug_struct("Font")
43 .field("is_force_auto_hinting", &self.is_force_auto_hinting())
44 .field("is_embedded_bitmaps", &self.is_embedded_bitmaps())
45 .field("is_subpixel", &self.is_subpixel())
46 .field("is_linear_metrics", &self.is_linear_metrics())
47 .field("is_embolden", &self.is_embolden())
48 .field("is_baseline_snap", &self.is_baseline_snap())
49 .field("edging", &self.edging())
50 .field("hinting", &self.hinting())
51 .field("typeface", &self.typeface())
52 .field("size", &self.size())
53 .field("scale_x", &self.scale_x())
54 .field("skew_x", &self.skew_x())
55 .field("metrics", &self.metrics())
56 .field("spacing", &self.spacing())
57 .finish()
58 }
59}
60
61impl Font {
62 pub fn new(typeface: impl Into<Typeface>, size: impl Into<Option<scalar>>) -> Self {
63 Self::from_typeface(typeface, size)
64 }
65
66 pub fn from_typeface(typeface: impl Into<Typeface>, size: impl Into<Option<scalar>>) -> Self {
67 match size.into() {
68 None => Self::construct(|font| unsafe {
69 sb::C_SkFont_ConstructFromTypeface(font, typeface.into().into_ptr())
70 }),
71 Some(size) => Self::construct(|font| unsafe {
72 sb::C_SkFont_ConstructFromTypefaceWithSize(font, typeface.into().into_ptr(), size)
73 }),
74 }
75 }
76
77 pub fn from_typeface_with_params(
78 typeface: impl Into<Typeface>,
79 size: scalar,
80 scale: scalar,
81 skew: scalar,
82 ) -> Self {
83 Self::construct(|font| unsafe {
84 sb::C_SkFont_ConstructFromTypefaceWithSizeScaleAndSkew(
85 font,
86 typeface.into().into_ptr(),
87 size,
88 scale,
89 skew,
90 )
91 })
92 }
93
94 pub fn is_force_auto_hinting(&self) -> bool {
95 self.has_flag(sb::SkFont_PrivFlags_kForceAutoHinting_PrivFlag)
96 }
97
98 pub fn is_embedded_bitmaps(&self) -> bool {
99 self.has_flag(sb::SkFont_PrivFlags_kEmbeddedBitmaps_PrivFlag)
100 }
101
102 pub fn is_subpixel(&self) -> bool {
103 self.has_flag(sb::SkFont_PrivFlags_kSubpixel_PrivFlag)
104 }
105
106 pub fn is_linear_metrics(&self) -> bool {
107 self.has_flag(sb::SkFont_PrivFlags_kLinearMetrics_PrivFlag)
108 }
109
110 pub fn is_embolden(&self) -> bool {
111 self.has_flag(sb::SkFont_PrivFlags_kEmbolden_PrivFlag)
112 }
113
114 pub fn is_baseline_snap(&self) -> bool {
115 self.has_flag(sb::SkFont_PrivFlags_kBaselineSnap_PrivFlag)
116 }
117
118 fn has_flag(&self, flag: SkFont_PrivFlags) -> bool {
119 (SkFont_PrivFlags::from(self.native().fFlags) & flag) != 0
120 }
121
122 pub fn set_force_auto_hinting(&mut self, force_auto_hinting: bool) -> &mut Self {
123 unsafe { self.native_mut().setForceAutoHinting(force_auto_hinting) }
124 self
125 }
126
127 pub fn set_embedded_bitmaps(&mut self, embedded_bitmaps: bool) -> &mut Self {
128 unsafe { self.native_mut().setEmbeddedBitmaps(embedded_bitmaps) }
129 self
130 }
131
132 pub fn set_subpixel(&mut self, subpixel: bool) -> &mut Self {
133 unsafe { self.native_mut().setSubpixel(subpixel) }
134 self
135 }
136
137 pub fn set_linear_metrics(&mut self, linear_metrics: bool) -> &mut Self {
138 unsafe { self.native_mut().setLinearMetrics(linear_metrics) }
139 self
140 }
141
142 pub fn set_embolden(&mut self, embolden: bool) -> &mut Self {
143 unsafe { self.native_mut().setEmbolden(embolden) }
144 self
145 }
146
147 pub fn set_baseline_snap(&mut self, baseline_snap: bool) -> &mut Self {
148 unsafe { self.native_mut().setBaselineSnap(baseline_snap) }
149 self
150 }
151
152 pub fn edging(&self) -> Edging {
153 unsafe { sb::C_SkFont_getEdging(self.native()) }
154 }
155
156 pub fn set_edging(&mut self, edging: Edging) -> &mut Self {
157 unsafe { self.native_mut().setEdging(edging) }
158 self
159 }
160
161 pub fn set_hinting(&mut self, hinting: FontHinting) -> &mut Self {
162 unsafe { self.native_mut().setHinting(hinting) }
163 self
164 }
165
166 pub fn hinting(&self) -> FontHinting {
167 unsafe { sb::C_SkFont_getHinting(self.native()) }
168 }
169
170 #[must_use]
171 pub fn with_size(&self, size: scalar) -> Option<Self> {
172 if size >= 0.0 && !size.is_infinite() && !size.is_nan() {
173 let mut font = unsafe { SkFont::new() };
174 unsafe { sb::C_SkFont_makeWithSize(self.native(), size, &mut font) }
175 Some(Self::from_native_c(font))
176 } else {
177 None
178 }
179 }
180
181 pub fn typeface(&self) -> Typeface {
182 Typeface::from_unshared_ptr(self.native().fTypeface.fPtr)
183 .expect("typeface is expected to be non-null")
184 }
185
186 pub fn size(&self) -> scalar {
187 self.native().fSize
188 }
189
190 pub fn scale_x(&self) -> scalar {
191 self.native().fScaleX
192 }
193
194 pub fn skew_x(&self) -> scalar {
195 self.native().fSkewX
196 }
197
198 pub fn set_typeface(&mut self, tf: impl Into<Typeface>) -> &mut Self {
199 unsafe { sb::C_SkFont_setTypeface(self.native_mut(), tf.into().into_ptr()) }
200 self
201 }
202
203 pub fn set_size(&mut self, size: scalar) -> &mut Self {
204 unsafe { self.native_mut().setSize(size) }
205 self
206 }
207
208 pub fn set_scale_x(&mut self, scale_x: scalar) -> &mut Self {
209 unsafe { self.native_mut().setScaleX(scale_x) }
210 self
211 }
212
213 pub fn set_skew_x(&mut self, skew_x: scalar) -> &mut Self {
214 unsafe { self.native_mut().setSkewX(skew_x) }
215 self
216 }
217
218 pub fn str_to_glyphs(&self, str: impl AsRef<str>, glyphs: &mut [GlyphId]) -> usize {
219 self.text_to_glyphs(str.as_ref(), glyphs)
220 }
221
222 pub fn text_to_glyphs(&self, text: impl EncodedText, glyphs: &mut [GlyphId]) -> usize {
223 let (ptr, size, encoding) = text.as_raw();
224 unsafe {
225 self.native()
226 .textToGlyphs(
227 ptr,
228 size,
229 encoding.into_native(),
230 glyphs.as_mut_ptr(),
231 glyphs
233 .len()
234 .min(i32::MAX.try_into().unwrap())
235 .try_into()
236 .unwrap(),
237 )
238 .try_into()
239 .unwrap()
240 }
241 }
242
243 pub fn count_str(&self, str: impl AsRef<str>) -> usize {
244 self.count_text(str.as_ref())
245 }
246
247 pub fn count_text(&self, text: impl EncodedText) -> usize {
248 let (ptr, size, encoding) = text.as_raw();
249 unsafe {
250 self.native()
251 .textToGlyphs(ptr, size, encoding.into_native(), ptr::null_mut(), i32::MAX)
252 .try_into()
253 .unwrap()
254 }
255 }
256
257 pub fn str_to_glyphs_vec(&self, str: impl AsRef<str>) -> Vec<GlyphId> {
259 self.text_to_glyphs_vec(str.as_ref())
260 }
261
262 pub fn text_to_glyphs_vec(&self, text: impl EncodedText) -> Vec<GlyphId> {
264 let count = self.count_text(&text);
265 let mut glyphs: Vec<GlyphId> = vec![Default::default(); count];
266 let resulting_count = self.text_to_glyphs(text, glyphs.as_mut_slice());
267 assert_eq!(count, resulting_count);
268 glyphs
269 }
270
271 pub fn measure_str(&self, str: impl AsRef<str>, paint: Option<&Paint>) -> (scalar, Rect) {
272 self.measure_text(str.as_ref(), paint)
273 }
274
275 pub fn measure_text(&self, text: impl EncodedText, paint: Option<&Paint>) -> (scalar, Rect) {
276 let mut bounds = Rect::default();
277 let (ptr, size, encoding) = text.as_raw();
278 let width = unsafe {
279 self.native().measureText(
280 ptr,
281 size,
282 encoding.into_native(),
283 bounds.native_mut(),
284 paint.native_ptr_or_null(),
285 )
286 };
287
288 (width, bounds)
289 }
290
291 pub fn unichar_to_glyph(&self, uni: Unichar) -> GlyphId {
292 unsafe { self.native().unicharToGlyph(uni) }
293 }
294
295 pub fn unichar_to_glyphs(&self, uni: &[Unichar], glyphs: &mut [GlyphId]) {
296 assert_eq!(uni.len(), glyphs.len());
297 unsafe {
298 self.native().unicharsToGlyphs(
299 uni.as_ptr(),
300 uni.len().try_into().unwrap(),
301 glyphs.as_mut_ptr(),
302 )
303 }
304 }
305
306 pub fn get_widths(&self, glyphs: &[GlyphId], widths: &mut [scalar]) {
307 self.get_widths_bounds(glyphs, Some(widths), None, None)
308 }
309
310 pub fn get_widths_bounds(
311 &self,
312 glyphs: &[GlyphId],
313 mut widths: Option<&mut [scalar]>,
314 mut bounds: Option<&mut [Rect]>,
315 paint: Option<&Paint>,
316 ) {
317 let count = glyphs.len();
318
319 {
320 if let Some(slice) = &widths {
321 assert_eq!(count, slice.len())
322 };
323 if let Some(slice) = &bounds {
324 assert_eq!(count, slice.len())
325 };
326 }
327
328 let bounds_ptr = bounds.native_mut().as_ptr_or_null_mut();
329 let widths_ptr = widths.as_ptr_or_null_mut();
330 let paint_ptr = paint.native_ptr_or_null();
331
332 unsafe {
333 self.native().getWidthsBounds(
334 glyphs.as_ptr(),
335 count.try_into().unwrap(),
336 widths_ptr,
337 bounds_ptr,
338 paint_ptr,
339 )
340 }
341 }
342
343 pub fn get_bounds(&self, glyphs: &[GlyphId], bounds: &mut [Rect], paint: Option<&Paint>) {
344 self.get_widths_bounds(glyphs, None, Some(bounds), paint)
345 }
346
347 pub fn get_pos(&self, glyphs: &[GlyphId], pos: &mut [Point], origin: Option<Point>) {
348 let count = glyphs.len();
349 assert_eq!(count, pos.len());
350
351 let origin = origin.unwrap_or_default();
352
353 unsafe {
354 self.native().getPos(
355 glyphs.as_ptr(),
356 count.try_into().unwrap(),
357 pos.native_mut().as_mut_ptr(),
358 *origin.native(),
359 )
360 }
361 }
362
363 pub fn get_x_pos(&self, glyphs: &[GlyphId], x_pos: &mut [scalar], origin: Option<scalar>) {
364 let count = glyphs.len();
365 assert_eq!(count, x_pos.len());
366 let origin = origin.unwrap_or_default();
367
368 unsafe {
369 self.native().getXPos(
370 glyphs.as_ptr(),
371 count.try_into().unwrap(),
372 x_pos.as_mut_ptr(),
373 origin,
374 )
375 }
376 }
377
378 pub fn get_intercepts<'a>(
379 &self,
380 glyphs: &[GlyphId],
381 pos: &[Point],
382 (top, bottom): (scalar, scalar),
383 paint: impl Into<Option<&'a Paint>>,
384 ) -> Vec<scalar> {
385 assert_eq!(glyphs.len(), pos.len());
386 let count = glyphs.len().try_into().unwrap();
387 let mut r: Vec<scalar> = Vec::new();
388 let mut set = |scalars: &[scalar]| r = scalars.to_vec();
389 unsafe {
390 sb::C_SkFont_getIntercepts(
391 self.native(),
392 glyphs.as_ptr(),
393 count,
394 pos.native().as_ptr(),
395 top,
396 bottom,
397 paint.into().native_ptr_or_null(),
398 VecSink::new(&mut set).native_mut(),
399 );
400 }
401 r
402 }
403
404 pub fn get_path(&self, glyph_id: GlyphId) -> Option<Path> {
405 let mut path = Path::default();
406 unsafe { self.native().getPath(glyph_id, path.native_mut()) }.if_true_some(path)
407 }
408
409 pub fn metrics(&self) -> (scalar, FontMetrics) {
412 let mut line_spacing = 0.0;
413 let fm =
414 FontMetrics::construct(|fm| line_spacing = unsafe { self.native().getMetrics(fm) });
415 (line_spacing, fm)
416 }
417
418 pub fn spacing(&self) -> scalar {
419 unsafe { self.native().getMetrics(ptr::null_mut()) }
420 }
421}
422
423#[cfg(test)]
424mod tests {
425 use crate::{FontMgr, FontStyle};
426
427 use super::*;
428
429 #[test]
430 fn test_flags() {
431 let font_mgr = FontMgr::new();
432 let typeface = font_mgr
433 .legacy_make_typeface(None, FontStyle::normal())
434 .unwrap();
435 let mut font = Font::new(typeface, 10.0);
436
437 font.set_force_auto_hinting(true);
438 assert!(font.is_force_auto_hinting());
439 font.set_force_auto_hinting(false);
440 assert!(!font.is_force_auto_hinting());
441
442 font.set_embolden(true);
443 assert!(font.is_embolden());
444 font.set_embolden(false);
445 assert!(!font.is_embolden());
446 }
447}