1 | use std::{fmt, ptr}; |
2 | |
3 | use skia_bindings::{self as sb, SkFont, SkFont_PrivFlags}; |
4 | |
5 | use crate::{ |
6 | interop::VecSink, prelude::*, scalar, EncodedText, FontHinting, FontMetrics, GlyphId, Paint, |
7 | Path, Point, Rect, Typeface, Unichar, |
8 | }; |
9 | |
10 | pub use skia_bindings::SkFont_Edging as Edging; |
11 | variant_name!(Edging::Alias); |
12 | |
13 | pub type Font = Handle<SkFont>; |
14 | unsafe_send_sync!(Font); |
15 | |
16 | impl NativeDrop for SkFont { |
17 | fn drop(&mut self) { |
18 | unsafe { sb::C_SkFont_destruct(self) } |
19 | } |
20 | } |
21 | |
22 | impl NativeClone for SkFont { |
23 | fn clone(&self) -> Self { |
24 | construct(|f: *mut SkFont| unsafe { sb::C_SkFont_CopyConstruct(uninitialized:f, self) }) |
25 | } |
26 | } |
27 | |
28 | impl NativePartialEq for SkFont { |
29 | fn eq(&self, rhs: &Self) -> bool { |
30 | unsafe { sb::C_SkFont_Equals(self, other:rhs) } |
31 | } |
32 | } |
33 | |
34 | impl Default for Font { |
35 | fn default() -> Self { |
36 | Self::from_native_c(unsafe { SkFont::new() }) |
37 | } |
38 | } |
39 | |
40 | impl 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 | |
61 | impl 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)] |
430 | mod 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 | |