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: *mut SkFont| unsafe { sb::C_SkFont_CopyConstruct(uninitialized:f, self) })
25 }
26}
27
28impl NativePartialEq for SkFont {
29 fn eq(&self, rhs: &Self) -> bool {
30 unsafe { sb::C_SkFont_Equals(self, other: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&mut DebugStruct<'_, '_>.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(name:"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 // don't fail if glyphs.len() is too large to fit into an i32.
232 glyphs
233 .len()
234 .min(i32::max_value().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(
252 ptr,
253 size,
254 encoding.into_native(),
255 ptr::null_mut(),
256 i32::max_value(),
257 )
258 .try_into()
259 .unwrap()
260 }
261 }
262
263 // convenience function
264 pub fn str_to_glyphs_vec(&self, str: impl AsRef<str>) -> Vec<GlyphId> {
265 self.text_to_glyphs_vec(str.as_ref())
266 }
267
268 // convenience function
269 pub fn text_to_glyphs_vec(&self, text: impl EncodedText) -> Vec<GlyphId> {
270 let count = self.count_text(&text);
271 let mut glyphs: Vec<GlyphId> = vec![Default::default(); count];
272 let resulting_count = self.text_to_glyphs(text, glyphs.as_mut_slice());
273 assert_eq!(count, resulting_count);
274 glyphs
275 }
276
277 pub fn measure_str(&self, str: impl AsRef<str>, paint: Option<&Paint>) -> (scalar, Rect) {
278 self.measure_text(str.as_ref(), paint)
279 }
280
281 pub fn measure_text(&self, text: impl EncodedText, paint: Option<&Paint>) -> (scalar, Rect) {
282 let mut bounds = Rect::default();
283 let (ptr, size, encoding) = text.as_raw();
284 let width = unsafe {
285 self.native().measureText(
286 ptr,
287 size,
288 encoding.into_native(),
289 bounds.native_mut(),
290 paint.native_ptr_or_null(),
291 )
292 };
293
294 (width, bounds)
295 }
296
297 pub fn unichar_to_glyph(&self, uni: Unichar) -> GlyphId {
298 unsafe { self.native().unicharToGlyph(uni) }
299 }
300
301 pub fn unichar_to_glyphs(&self, uni: &[Unichar], glyphs: &mut [GlyphId]) {
302 assert_eq!(uni.len(), glyphs.len());
303 unsafe {
304 self.native().unicharsToGlyphs(
305 uni.as_ptr(),
306 uni.len().try_into().unwrap(),
307 glyphs.as_mut_ptr(),
308 )
309 }
310 }
311
312 pub fn get_widths(&self, glyphs: &[GlyphId], widths: &mut [scalar]) {
313 self.get_widths_bounds(glyphs, Some(widths), None, None)
314 }
315
316 pub fn get_widths_bounds(
317 &self,
318 glyphs: &[GlyphId],
319 mut widths: Option<&mut [scalar]>,
320 mut bounds: Option<&mut [Rect]>,
321 paint: Option<&Paint>,
322 ) {
323 let count = glyphs.len();
324
325 {
326 if let Some(slice) = &widths {
327 assert_eq!(count, slice.len())
328 };
329 if let Some(slice) = &bounds {
330 assert_eq!(count, slice.len())
331 };
332 }
333
334 let bounds_ptr = bounds.native_mut().as_ptr_or_null_mut();
335 let widths_ptr = widths.as_ptr_or_null_mut();
336 let paint_ptr = paint.native_ptr_or_null();
337
338 unsafe {
339 self.native().getWidthsBounds(
340 glyphs.as_ptr(),
341 count.try_into().unwrap(),
342 widths_ptr,
343 bounds_ptr,
344 paint_ptr,
345 )
346 }
347 }
348
349 pub fn get_bounds(&self, glyphs: &[GlyphId], bounds: &mut [Rect], paint: Option<&Paint>) {
350 self.get_widths_bounds(glyphs, None, Some(bounds), paint)
351 }
352
353 pub fn get_pos(&self, glyphs: &[GlyphId], pos: &mut [Point], origin: Option<Point>) {
354 let count = glyphs.len();
355 assert_eq!(count, pos.len());
356
357 let origin = origin.unwrap_or_default();
358
359 unsafe {
360 self.native().getPos(
361 glyphs.as_ptr(),
362 count.try_into().unwrap(),
363 pos.native_mut().as_mut_ptr(),
364 *origin.native(),
365 )
366 }
367 }
368
369 pub fn get_x_pos(&self, glyphs: &[GlyphId], x_pos: &mut [scalar], origin: Option<scalar>) {
370 let count = glyphs.len();
371 assert_eq!(count, x_pos.len());
372 let origin = origin.unwrap_or_default();
373
374 unsafe {
375 self.native().getXPos(
376 glyphs.as_ptr(),
377 count.try_into().unwrap(),
378 x_pos.as_mut_ptr(),
379 origin,
380 )
381 }
382 }
383
384 pub fn get_intercepts<'a>(
385 &self,
386 glyphs: &[GlyphId],
387 pos: &[Point],
388 (top, bottom): (scalar, scalar),
389 paint: impl Into<Option<&'a Paint>>,
390 ) -> Vec<scalar> {
391 assert_eq!(glyphs.len(), pos.len());
392 let count = glyphs.len().try_into().unwrap();
393 let mut r: Vec<scalar> = Vec::new();
394 let mut set = |scalars: &[scalar]| r = scalars.to_vec();
395 unsafe {
396 sb::C_SkFont_getIntercepts(
397 self.native(),
398 glyphs.as_ptr(),
399 count,
400 pos.native().as_ptr(),
401 top,
402 bottom,
403 paint.into().native_ptr_or_null(),
404 VecSink::new(&mut set).native_mut(),
405 );
406 }
407 r
408 }
409
410 pub fn get_path(&self, glyph_id: GlyphId) -> Option<Path> {
411 let mut path = Path::default();
412 unsafe { self.native().getPath(glyph_id, path.native_mut()) }.if_true_some(path)
413 }
414
415 // TODO: getPaths() (needs a function to be passed, but supports a context).
416
417 pub fn metrics(&self) -> (scalar, FontMetrics) {
418 let mut line_spacing = 0.0;
419 let fm =
420 FontMetrics::construct(|fm| line_spacing = unsafe { self.native().getMetrics(fm) });
421 (line_spacing, fm)
422 }
423
424 pub fn spacing(&self) -> scalar {
425 unsafe { self.native().getMetrics(ptr::null_mut()) }
426 }
427}
428
429#[cfg(test)]
430mod tests {
431 use crate::{FontMgr, FontStyle};
432
433 use super::*;
434
435 #[test]
436 fn test_flags() {
437 let font_mgr = FontMgr::new();
438 let typeface = font_mgr
439 .legacy_make_typeface(None, FontStyle::normal())
440 .unwrap();
441 let mut font = Font::new(typeface, 10.0);
442
443 font.set_force_auto_hinting(true);
444 assert!(font.is_force_auto_hinting());
445 font.set_force_auto_hinting(false);
446 assert!(!font.is_force_auto_hinting());
447
448 font.set_embolden(true);
449 assert!(font.is_embolden());
450 font.set_embolden(false);
451 assert!(!font.is_embolden());
452 }
453}
454