| 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.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 | // convenience function |
| 258 | 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 | // convenience function |
| 263 | 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 | // TODO: getPaths() (needs a function to be passed, but supports a context). |
| 410 | |
| 411 | 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)] |
| 424 | mod 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 | } |
| 448 | |