font.rs (38128B)
1 use super::hb::*; 2 3 use std::collections::HashMap; 4 use std::ffi::c_void; 5 use std::mem::transmute; 6 use std::ptr::null_mut; 7 use std::sync::atomic::{AtomicPtr, AtomicU32, Ordering}; 8 use std::sync::Mutex; 9 10 use skrifa::charmap::Charmap; 11 use skrifa::charmap::MapVariant::Variant; 12 use skrifa::color::{ 13 Brush, ColorGlyphCollection, ColorPainter, ColorStop, CompositeMode, Extend, Transform, 14 }; 15 use skrifa::font::FontRef; 16 use skrifa::instance::{Location, NormalizedCoord, Size}; 17 use skrifa::metrics::{BoundingBox, GlyphMetrics}; 18 use skrifa::outline::pen::OutlinePen; 19 use skrifa::outline::DrawSettings; 20 use skrifa::raw::tables::cpal::ColorRecord; 21 use skrifa::raw::tables::vmtx::Vmtx; 22 use skrifa::raw::tables::vorg::Vorg; 23 use skrifa::raw::tables::vvar::Vvar; 24 use skrifa::raw::TableProvider; 25 use skrifa::OutlineGlyphCollection; 26 use skrifa::{GlyphId, GlyphNames, MetadataProvider}; 27 28 // A struct for storing your “fontations” data 29 #[repr(C)] 30 struct FontationsData<'a> { 31 face_blob: *mut hb_blob_t, 32 font: *mut hb_font_t, 33 font_ref: FontRef<'a>, 34 char_map: Charmap<'a>, 35 outline_glyphs: OutlineGlyphCollection<'a>, 36 color_glyphs: ColorGlyphCollection<'a>, 37 glyph_names: GlyphNames<'a>, 38 size: Size, 39 vert_metrics: Option<Vmtx<'a>>, 40 vert_origin: Option<Vorg<'a>>, 41 vert_vars: Option<Vvar<'a>>, 42 43 // Mutex for the below 44 mutex: Mutex<()>, 45 serial: AtomicU32, 46 x_mult: f32, 47 y_mult: f32, 48 location: Location, 49 glyph_metrics: Option<GlyphMetrics<'a>>, 50 } 51 52 impl FontationsData<'_> { 53 unsafe fn from_hb_font(font: *mut hb_font_t) -> Option<Self> { 54 let face_index = hb_face_get_index(hb_font_get_face(font)); 55 let face_blob = hb_face_reference_blob(hb_font_get_face(font)); 56 let blob_length = hb_blob_get_length(face_blob); 57 let blob_data = hb_blob_get_data(face_blob, null_mut()); 58 if blob_data.is_null() { 59 return None; 60 } 61 let face_data = std::slice::from_raw_parts(blob_data as *const u8, blob_length as usize); 62 63 let font_ref = FontRef::from_index(face_data, face_index); 64 let font_ref = match font_ref { 65 Ok(f) => f, 66 Err(_) => return None, 67 }; 68 69 let char_map = Charmap::new(&font_ref); 70 71 let outline_glyphs = font_ref.outline_glyphs(); 72 73 let color_glyphs = font_ref.color_glyphs(); 74 75 let glyph_names = font_ref.glyph_names(); 76 77 let upem = hb_face_get_upem(hb_font_get_face(font)); 78 79 let vert_metrics = font_ref.vmtx().ok(); 80 let vert_origin = font_ref.vorg().ok(); 81 let vert_vars = font_ref.vvar().ok(); 82 83 let mut data = FontationsData { 84 face_blob, 85 font, 86 font_ref, 87 char_map, 88 outline_glyphs, 89 color_glyphs, 90 glyph_names, 91 size: Size::new(upem as f32), 92 vert_metrics, 93 vert_origin, 94 vert_vars, 95 mutex: Mutex::new(()), 96 x_mult: 1.0, 97 y_mult: 1.0, 98 serial: AtomicU32::new(u32::MAX), 99 location: Location::default(), 100 glyph_metrics: None, 101 }; 102 103 data.check_for_updates(); 104 105 Some(data) 106 } 107 108 unsafe fn _check_for_updates(&mut self) { 109 let font_serial = hb_font_get_serial(self.font); 110 let serial = self.serial.load(Ordering::Relaxed); 111 if serial == font_serial { 112 return; 113 } 114 115 let _lock = self.mutex.lock().unwrap(); 116 117 let mut x_scale: i32 = 0; 118 let mut y_scale: i32 = 0; 119 hb_font_get_scale(self.font, &mut x_scale, &mut y_scale); 120 let upem = hb_face_get_upem(hb_font_get_face(self.font)); 121 self.x_mult = x_scale as f32 / upem as f32; 122 self.y_mult = y_scale as f32 / upem as f32; 123 124 let mut num_coords: u32 = 0; 125 let coords = hb_font_get_var_coords_normalized(self.font, &mut num_coords); 126 let coords = if coords.is_null() { 127 &[] 128 } else { 129 std::slice::from_raw_parts(coords, num_coords as usize) 130 }; 131 let all_zeros = coords.iter().all(|&x| x == 0); 132 // if all zeros, use Location::default() 133 // otherwise, use the provided coords. 134 // This currently doesn't seem to have a perf effect on fontations, but it's a good idea to 135 // check if the coords are all zeros before creating a Location. 136 self.location = if all_zeros { 137 Location::default() 138 } else { 139 let mut location = Location::new(num_coords as usize); 140 let coords_mut = location.coords_mut(); 141 coords_mut 142 .iter_mut() 143 .zip(coords.iter().map(|v| NormalizedCoord::from_bits(*v as i16))) 144 .for_each(|(dest, source)| *dest = source); 145 location 146 }; 147 148 let location = transmute::<&Location, &Location>(&self.location); 149 self.glyph_metrics = Some(self.font_ref.glyph_metrics(self.size, location)); 150 151 self.serial.store(font_serial, Ordering::Release); 152 } 153 fn check_for_updates(&mut self) { 154 unsafe { self._check_for_updates() } 155 } 156 } 157 158 extern "C" fn _hb_fontations_data_destroy(font_data: *mut c_void) { 159 let data = unsafe { Box::from_raw(font_data as *mut FontationsData) }; 160 161 unsafe { 162 hb_blob_destroy(data.face_blob); 163 } 164 } 165 166 fn struct_at_offset<T: Copy>(first: *const T, index: u32, stride: u32) -> T { 167 unsafe { *((first as *const u8).offset((index * stride) as isize) as *const T) } 168 } 169 170 fn struct_at_offset_mut<T: Copy>(first: *mut T, index: u32, stride: u32) -> &'static mut T { 171 unsafe { &mut *((first as *mut u8).offset((index * stride) as isize) as *mut T) } 172 } 173 174 extern "C" fn _hb_fontations_get_nominal_glyphs( 175 _font: *mut hb_font_t, 176 font_data: *mut ::std::os::raw::c_void, 177 count: ::std::os::raw::c_uint, 178 first_unicode: *const hb_codepoint_t, 179 unicode_stride: ::std::os::raw::c_uint, 180 first_glyph: *mut hb_codepoint_t, 181 glyph_stride: ::std::os::raw::c_uint, 182 _user_data: *mut ::std::os::raw::c_void, 183 ) -> ::std::os::raw::c_uint { 184 let data = unsafe { &*(font_data as *const FontationsData) }; 185 let char_map = &data.char_map; 186 187 for i in 0..count { 188 let unicode = struct_at_offset(first_unicode, i, unicode_stride); 189 let Some(glyph) = char_map.map(unicode) else { 190 return i; 191 }; 192 let glyph_id = glyph.to_u32() as hb_codepoint_t; 193 *struct_at_offset_mut(first_glyph, i, glyph_stride) = glyph_id; 194 } 195 196 count 197 } 198 extern "C" fn _hb_fontations_get_variation_glyph( 199 _font: *mut hb_font_t, 200 font_data: *mut ::std::os::raw::c_void, 201 unicode: hb_codepoint_t, 202 variation_selector: hb_codepoint_t, 203 glyph: *mut hb_codepoint_t, 204 _user_data: *mut ::std::os::raw::c_void, 205 ) -> hb_bool_t { 206 let data = unsafe { &*(font_data as *const FontationsData) }; 207 208 let char_map = &data.char_map; 209 210 match char_map.map_variant(unicode, variation_selector) { 211 Some(Variant(glyph_id)) => { 212 unsafe { *glyph = glyph_id.to_u32() as hb_codepoint_t }; 213 true as hb_bool_t 214 } 215 _ => false as hb_bool_t, 216 } 217 } 218 219 extern "C" fn _hb_fontations_get_glyph_h_advances( 220 _font: *mut hb_font_t, 221 font_data: *mut ::std::os::raw::c_void, 222 count: ::std::os::raw::c_uint, 223 first_glyph: *const hb_codepoint_t, 224 glyph_stride: ::std::os::raw::c_uint, 225 first_advance: *mut hb_position_t, 226 advance_stride: ::std::os::raw::c_uint, 227 _user_data: *mut ::std::os::raw::c_void, 228 ) { 229 let data = unsafe { &mut *(font_data as *mut FontationsData) }; 230 data.check_for_updates(); 231 232 let glyph_metrics = &data.glyph_metrics.as_ref().unwrap(); 233 234 for i in 0..count { 235 let glyph = struct_at_offset(first_glyph, i, glyph_stride); 236 let glyph_id = GlyphId::new(glyph); 237 let advance = glyph_metrics.advance_width(glyph_id).unwrap_or_default(); 238 let scaled = (advance * data.x_mult).round() as hb_position_t; 239 *struct_at_offset_mut(first_advance, i, advance_stride) = scaled; 240 } 241 } 242 243 extern "C" fn _hb_fontations_get_glyph_v_advances( 244 font: *mut hb_font_t, 245 font_data: *mut ::std::os::raw::c_void, 246 count: ::std::os::raw::c_uint, 247 first_glyph: *const hb_codepoint_t, 248 glyph_stride: ::std::os::raw::c_uint, 249 first_advance: *mut hb_position_t, 250 advance_stride: ::std::os::raw::c_uint, 251 _user_data: *mut ::std::os::raw::c_void, 252 ) { 253 let data = unsafe { &mut *(font_data as *mut FontationsData) }; 254 data.check_for_updates(); 255 256 if let Some(vert_metrics) = &data.vert_metrics { 257 let vert_vars = &data.vert_vars; 258 for i in 0..count { 259 let glyph = struct_at_offset(first_glyph, i, glyph_stride); 260 let glyph_id = GlyphId::new(glyph); 261 let mut advance = vert_metrics.advance(glyph_id).unwrap_or_default() as f32; 262 if let Some(vert_vars) = vert_vars { 263 let coords = data.location.coords(); 264 if !coords.is_empty() { 265 advance += vert_vars 266 .advance_height_delta(glyph_id, coords) 267 .unwrap_or_default() 268 .to_f32(); 269 } 270 } 271 let scaled = -(advance * data.y_mult).round() as hb_position_t; 272 *struct_at_offset_mut(first_advance, i, advance_stride) = scaled; 273 } 274 } else { 275 let mut font_extents = unsafe { std::mem::zeroed() }; 276 unsafe { 277 hb_font_get_extents_for_direction( 278 font, 279 hb_direction_t_HB_DIRECTION_LTR, 280 &mut font_extents, 281 ); 282 } 283 let advance: hb_position_t = -(font_extents.ascender - font_extents.descender); 284 285 for i in 0..count { 286 *struct_at_offset_mut(first_advance, i, advance_stride) = advance; 287 } 288 } 289 } 290 291 extern "C" fn _hb_fontations_get_glyph_v_origin( 292 font: *mut hb_font_t, 293 font_data: *mut ::std::os::raw::c_void, 294 glyph: hb_codepoint_t, 295 x: *mut hb_position_t, 296 y: *mut hb_position_t, 297 _user_data: *mut ::std::os::raw::c_void, 298 ) -> hb_bool_t { 299 let data = unsafe { &mut *(font_data as *mut FontationsData) }; 300 data.check_for_updates(); 301 302 unsafe { 303 *x = hb_font_get_glyph_h_advance(font, glyph) / 2; 304 } 305 306 let vert_origin = &data.vert_origin; 307 if let Some(vert_origin) = vert_origin { 308 let glyph_id = GlyphId::new(glyph); 309 310 let mut y_origin = vert_origin.vertical_origin_y(glyph_id) as f32; 311 let vert_vars = &data.vert_vars; 312 if let Some(vert_vars) = vert_vars { 313 let coords = data.location.coords(); 314 if !coords.is_empty() { 315 y_origin += vert_vars 316 .v_org_delta(glyph_id, coords) 317 .unwrap_or_default() 318 .to_f32(); 319 } 320 } 321 322 unsafe { 323 *y = (y_origin * data.y_mult).round() as hb_position_t; 324 } 325 326 return true as hb_bool_t; 327 } 328 329 let mut extents: hb_glyph_extents_t = unsafe { std::mem::zeroed() }; 330 if unsafe { hb_font_get_glyph_extents(font, glyph, &mut extents) != 0 } { 331 if let Some(vert_metrics) = &data.vert_metrics { 332 let glyph = GlyphId::new(glyph); 333 let mut tsb: f32 = vert_metrics.side_bearing(glyph).unwrap_or_default() as f32; 334 if let Some(vert_vars) = &data.vert_vars { 335 let coords = data.location.coords(); 336 if !coords.is_empty() { 337 tsb += vert_vars 338 .tsb_delta(glyph, coords) 339 .unwrap_or_default() 340 .to_f32(); 341 } 342 } 343 unsafe { 344 *y = extents.y_bearing + (tsb * data.y_mult).round() as hb_position_t; 345 } 346 return true as hb_bool_t; 347 } 348 349 let mut font_extents: hb_font_extents_t = unsafe { std::mem::zeroed() }; 350 unsafe { 351 hb_font_get_extents_for_direction( 352 font, 353 hb_direction_t_HB_DIRECTION_LTR, 354 &mut font_extents, 355 ); 356 } 357 let advance: hb_position_t = font_extents.ascender - font_extents.descender; 358 let diff: hb_position_t = advance - -extents.height; 359 unsafe { 360 *y = extents.y_bearing + (diff >> 1); 361 } 362 return true as hb_bool_t; 363 } 364 365 let mut font_extents: hb_font_extents_t = unsafe { std::mem::zeroed() }; 366 unsafe { 367 hb_font_get_extents_for_direction(font, hb_direction_t_HB_DIRECTION_LTR, &mut font_extents); 368 } 369 unsafe { 370 *y = font_extents.ascender; 371 } 372 373 true as hb_bool_t 374 } 375 376 extern "C" fn _hb_fontations_get_glyph_extents( 377 _font: *mut hb_font_t, 378 font_data: *mut ::std::os::raw::c_void, 379 glyph: hb_codepoint_t, 380 extents: *mut hb_glyph_extents_t, 381 _user_data: *mut ::std::os::raw::c_void, 382 ) -> hb_bool_t { 383 let data = unsafe { &mut *(font_data as *mut FontationsData) }; 384 data.check_for_updates(); 385 386 let glyph_id = GlyphId::new(glyph); 387 388 // COLRv1 color glyphs are not supported by glyph_metrics. 389 let color_glyphs = &data.color_glyphs; 390 if color_glyphs.get(glyph_id).is_some() { 391 return false as hb_bool_t; 392 }; 393 394 let glyph_metrics = &data.glyph_metrics.as_ref().unwrap(); 395 let Some(glyph_extents) = glyph_metrics.bounds(glyph_id) else { 396 return false as hb_bool_t; 397 }; 398 399 let x_bearing = (glyph_extents.x_min * data.x_mult).round() as hb_position_t; 400 let width = (glyph_extents.x_max * data.x_mult).round() as hb_position_t - x_bearing; 401 let y_bearing = (glyph_extents.y_max * data.y_mult).round() as hb_position_t; 402 let height = (glyph_extents.y_min * data.y_mult).round() as hb_position_t - y_bearing; 403 404 unsafe { 405 *extents = hb_glyph_extents_t { 406 x_bearing, 407 y_bearing, 408 width, 409 height, 410 }; 411 } 412 413 true as hb_bool_t 414 } 415 416 extern "C" fn _hb_fontations_get_font_h_extents( 417 _font: *mut hb_font_t, 418 font_data: *mut ::std::os::raw::c_void, 419 extents: *mut hb_font_extents_t, 420 _user_data: *mut ::std::os::raw::c_void, 421 ) -> hb_bool_t { 422 let data = unsafe { &mut *(font_data as *mut FontationsData) }; 423 data.check_for_updates(); 424 425 let font_ref = &data.font_ref; 426 let size = &data.size; 427 let location = &data.location; 428 let metrics = font_ref.metrics(*size, location); 429 430 unsafe { 431 (*extents).ascender = (metrics.ascent * data.y_mult).round() as hb_position_t; 432 (*extents).descender = (metrics.descent * data.y_mult).round() as hb_position_t; 433 (*extents).line_gap = (metrics.leading * data.y_mult).round() as hb_position_t; 434 } 435 436 true as hb_bool_t 437 } 438 439 struct HbPen { 440 x_mult: f32, 441 y_mult: f32, 442 draw_state: *mut hb_draw_state_t, 443 draw_funcs: *mut hb_draw_funcs_t, 444 draw_data: *mut c_void, 445 } 446 447 impl OutlinePen for HbPen { 448 fn move_to(&mut self, x: f32, y: f32) { 449 unsafe { 450 hb_draw_move_to( 451 self.draw_funcs, 452 self.draw_data, 453 self.draw_state, 454 x * self.x_mult, 455 y * self.y_mult, 456 ); 457 } 458 } 459 fn line_to(&mut self, x: f32, y: f32) { 460 unsafe { 461 hb_draw_line_to( 462 self.draw_funcs, 463 self.draw_data, 464 self.draw_state, 465 x * self.x_mult, 466 y * self.y_mult, 467 ); 468 } 469 } 470 fn quad_to(&mut self, x1: f32, y1: f32, x: f32, y: f32) { 471 unsafe { 472 hb_draw_quadratic_to( 473 self.draw_funcs, 474 self.draw_data, 475 self.draw_state, 476 x1 * self.x_mult, 477 y1 * self.y_mult, 478 x * self.x_mult, 479 y * self.y_mult, 480 ); 481 } 482 } 483 fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32) { 484 unsafe { 485 hb_draw_cubic_to( 486 self.draw_funcs, 487 self.draw_data, 488 self.draw_state, 489 x1 * self.x_mult, 490 y1 * self.y_mult, 491 x2 * self.x_mult, 492 y2 * self.y_mult, 493 x * self.x_mult, 494 y * self.y_mult, 495 ); 496 } 497 } 498 fn close(&mut self) { 499 unsafe { 500 hb_draw_close_path(self.draw_funcs, self.draw_data, self.draw_state); 501 } 502 } 503 } 504 505 extern "C" fn _hb_fontations_draw_glyph_or_fail( 506 _font: *mut hb_font_t, 507 font_data: *mut ::std::os::raw::c_void, 508 glyph: hb_codepoint_t, 509 draw_funcs: *mut hb_draw_funcs_t, 510 draw_data: *mut ::std::os::raw::c_void, 511 _user_data: *mut ::std::os::raw::c_void, 512 ) -> hb_bool_t { 513 let data = unsafe { &mut *(font_data as *mut FontationsData) }; 514 data.check_for_updates(); 515 516 let size = &data.size; 517 let location = &data.location; 518 let outline_glyphs = &data.outline_glyphs; 519 520 let glyph_id = GlyphId::new(glyph); 521 let Some(outline_glyph) = outline_glyphs.get(glyph_id) else { 522 return false as hb_bool_t; 523 }; 524 let draw_settings = DrawSettings::unhinted(*size, location); 525 526 let mut draw_state = unsafe { std::mem::zeroed::<hb_draw_state_t>() }; 527 528 let mut pen = HbPen { 529 x_mult: data.x_mult, 530 y_mult: data.y_mult, 531 draw_state: &mut draw_state, 532 draw_funcs, 533 draw_data, 534 }; 535 536 let _ = outline_glyph.draw(draw_settings, &mut pen); 537 true as hb_bool_t 538 } 539 540 struct HbColorPainter<'a> { 541 font: *mut hb_font_t, 542 paint_funcs: *mut hb_paint_funcs_t, 543 paint_data: *mut c_void, 544 color_records: &'a [ColorRecord], 545 foreground: hb_color_t, 546 is_glyph_clip: u64, 547 clip_depth: u32, 548 } 549 550 impl HbColorPainter<'_> { 551 fn lookup_color(&self, color_index: u16, alpha: f32) -> hb_color_t { 552 if color_index == 0xFFFF { 553 // Apply alpha to foreground color 554 return ((self.foreground & 0xFFFFFF00) 555 | (((self.foreground & 0xFF) as f32 * alpha).round() as u32)) 556 as hb_color_t; 557 } 558 559 let c = self.color_records.get(color_index as usize); 560 if let Some(c) = c { 561 (((c.blue as u32) << 24) 562 | ((c.green as u32) << 16) 563 | ((c.red as u32) << 8) 564 | ((c.alpha as f32 * alpha).round() as u32)) as hb_color_t 565 } else { 566 0 as hb_color_t 567 } 568 } 569 570 fn make_color_line(&self, color_line: &ColorLineData) -> hb_color_line_t { 571 let mut cl = unsafe { std::mem::zeroed::<hb_color_line_t>() }; 572 cl.data = color_line as *const ColorLineData as *mut ::std::os::raw::c_void; 573 cl.get_color_stops = Some(_hb_fontations_get_color_stops); 574 cl.get_extend = Some(_hb_fontations_get_extend); 575 cl 576 } 577 } 578 579 struct ColorLineData<'a> { 580 painter: &'a HbColorPainter<'a>, 581 color_stops: &'a [ColorStop], 582 extend: Extend, 583 } 584 extern "C" fn _hb_fontations_get_color_stops( 585 _color_line: *mut hb_color_line_t, 586 color_line_data: *mut ::std::os::raw::c_void, 587 start: ::std::os::raw::c_uint, 588 count_out: *mut ::std::os::raw::c_uint, 589 color_stops_out: *mut hb_color_stop_t, 590 _user_data: *mut ::std::os::raw::c_void, 591 ) -> ::std::os::raw::c_uint { 592 let color_line_data = unsafe { &*(color_line_data as *const ColorLineData) }; 593 let color_stops = &color_line_data.color_stops; 594 if count_out.is_null() { 595 return color_stops.len() as u32; 596 } 597 let count = unsafe { *count_out }; 598 for i in 0..count { 599 let Some(stop) = color_stops.get(start as usize + i as usize) else { 600 unsafe { 601 *count_out = i; 602 }; 603 break; 604 }; 605 unsafe { 606 *(color_stops_out.offset(i as isize)) = hb_color_stop_t { 607 offset: stop.offset, 608 color: color_line_data 609 .painter 610 .lookup_color(stop.palette_index, stop.alpha), 611 is_foreground: (stop.palette_index == 0xFFFF) as hb_bool_t, 612 }; 613 } 614 } 615 color_stops.len() as u32 616 } 617 extern "C" fn _hb_fontations_get_extend( 618 _color_line: *mut hb_color_line_t, 619 color_line_data: *mut ::std::os::raw::c_void, 620 _user_data: *mut ::std::os::raw::c_void, 621 ) -> hb_paint_extend_t { 622 let color_line_data = unsafe { &*(color_line_data as *const ColorLineData) }; 623 color_line_data.extend as hb_paint_extend_t // They are the same 624 } 625 626 pub fn _hb_fontations_unreduce_anchors( 627 x0: f32, 628 y0: f32, 629 x1: f32, 630 y1: f32, 631 ) -> (f32, f32, f32, f32, f32, f32) { 632 /* Returns (x0, y0, x1, y1, x2, y2) such that the original 633 * `_hb_cairo_reduce_anchors` would produce (xx0, yy0, xx1, yy1) 634 * as outputs. 635 * The OT spec has the following wording; we just need to 636 * invert that operation here: 637 * 638 * Note: An implementation can derive a single vector, from p₀ to a point p₃, by computing the 639 * orthogonal projection of the vector from p₀ to p₁ onto a line perpendicular to line p₀p₂ and 640 * passing through p₀ to obtain point p₃. The linear gradient defined using p₀, p₁ and p₂ as 641 * described above is functionally equivalent to a linear gradient defined by aligning stop 642 * offset 0 to p₀ and aligning stop offset 1.0 to p₃, with each color projecting on either side 643 * of that line in a perpendicular direction. This specification uses three points, p₀, p₁ and 644 * p₂, as that provides greater flexibility in controlling the placement and rotation of the 645 * gradient, as well as variations thereof. 646 */ 647 648 let dx = x1 - x0; 649 let dy = y1 - y0; 650 651 (x0, y0, x1, y1, x0 + dy, y0 - dx) 652 } 653 654 impl ColorPainter for HbColorPainter<'_> { 655 fn push_transform(&mut self, transform: Transform) { 656 unsafe { 657 hb_paint_push_transform( 658 self.paint_funcs, 659 self.paint_data, 660 transform.xx, 661 transform.yx, 662 transform.xy, 663 transform.yy, 664 transform.dx, 665 transform.dy, 666 ); 667 } 668 } 669 fn pop_transform(&mut self) { 670 unsafe { 671 hb_paint_pop_transform(self.paint_funcs, self.paint_data); 672 } 673 } 674 fn fill_glyph( 675 &mut self, 676 glyph_id: GlyphId, 677 brush_transform: Option<Transform>, 678 brush: Brush<'_>, 679 ) { 680 unsafe { 681 hb_paint_push_inverse_font_transform(self.paint_funcs, self.paint_data, self.font); 682 hb_paint_push_clip_glyph( 683 self.paint_funcs, 684 self.paint_data, 685 glyph_id.to_u32() as hb_codepoint_t, 686 self.font, 687 ); 688 hb_paint_push_font_transform(self.paint_funcs, self.paint_data, self.font); 689 } 690 if let Some(wrap_in_transform) = brush_transform { 691 self.push_transform(wrap_in_transform); 692 self.fill(brush); 693 self.pop_transform(); 694 } else { 695 self.fill(brush); 696 } 697 self.pop_transform(); 698 unsafe { 699 hb_paint_pop_clip(self.paint_funcs, self.paint_data); 700 } 701 self.pop_transform(); 702 } 703 fn push_clip_glyph(&mut self, glyph_id: GlyphId) { 704 if self.clip_depth < 64 { 705 self.is_glyph_clip |= 1 << self.clip_depth; 706 self.clip_depth += 1; 707 } else { 708 return; 709 } 710 unsafe { 711 hb_paint_push_inverse_font_transform(self.paint_funcs, self.paint_data, self.font); 712 hb_paint_push_clip_glyph( 713 self.paint_funcs, 714 self.paint_data, 715 glyph_id.to_u32() as hb_codepoint_t, 716 self.font, 717 ); 718 hb_paint_push_font_transform(self.paint_funcs, self.paint_data, self.font); 719 } 720 } 721 fn push_clip_box(&mut self, bbox: BoundingBox) { 722 if self.clip_depth < 64 { 723 self.is_glyph_clip &= !(1 << self.clip_depth); 724 self.clip_depth += 1; 725 } else { 726 return; 727 } 728 unsafe { 729 hb_paint_push_clip_rectangle( 730 self.paint_funcs, 731 self.paint_data, 732 bbox.x_min, 733 bbox.y_min, 734 bbox.x_max, 735 bbox.y_max, 736 ); 737 } 738 } 739 fn pop_clip(&mut self) { 740 if self.clip_depth > 0 { 741 self.clip_depth -= 1; 742 } else { 743 return; 744 } 745 unsafe { 746 if (self.is_glyph_clip & (1 << self.clip_depth)) != 0 { 747 hb_paint_pop_transform(self.paint_funcs, self.paint_data); 748 } 749 hb_paint_pop_clip(self.paint_funcs, self.paint_data); 750 if (self.is_glyph_clip & (1 << self.clip_depth)) != 0 { 751 hb_paint_pop_transform(self.paint_funcs, self.paint_data); 752 } 753 } 754 } 755 fn fill(&mut self, brush: Brush) { 756 match brush { 757 Brush::Solid { 758 palette_index: color_index, 759 alpha, 760 } => { 761 let is_foreground = color_index == 0xFFFF; 762 unsafe { 763 hb_paint_color( 764 self.paint_funcs, 765 self.paint_data, 766 is_foreground as hb_bool_t, 767 self.lookup_color(color_index, alpha), 768 ); 769 } 770 } 771 Brush::LinearGradient { 772 color_stops, 773 extend, 774 p0, 775 p1, 776 } => { 777 let color_stops = ColorLineData { 778 painter: self, 779 color_stops, 780 extend, 781 }; 782 let mut color_line = self.make_color_line(&color_stops); 783 784 let (x0, y0, x1, y1, x2, y2) = 785 _hb_fontations_unreduce_anchors(p0.x, p0.y, p1.x, p1.y); 786 787 unsafe { 788 hb_paint_linear_gradient( 789 self.paint_funcs, 790 self.paint_data, 791 &mut color_line, 792 x0, 793 y0, 794 x1, 795 y1, 796 x2, 797 y2, 798 ); 799 } 800 } 801 Brush::RadialGradient { 802 color_stops, 803 extend, 804 c0, 805 r0, 806 c1, 807 r1, 808 } => { 809 let color_stops = ColorLineData { 810 painter: self, 811 color_stops, 812 extend, 813 }; 814 let mut color_line = self.make_color_line(&color_stops); 815 unsafe { 816 hb_paint_radial_gradient( 817 self.paint_funcs, 818 self.paint_data, 819 &mut color_line, 820 c0.x, 821 c0.y, 822 r0, 823 c1.x, 824 c1.y, 825 r1, 826 ); 827 } 828 } 829 Brush::SweepGradient { 830 color_stops, 831 extend, 832 c0, 833 start_angle, 834 end_angle, 835 } => { 836 let color_stops = ColorLineData { 837 painter: self, 838 color_stops, 839 extend, 840 }; 841 let mut color_line = self.make_color_line(&color_stops); 842 // Skrifa has this gem, so we swap end_angle and start_angle 843 // when passing to our API: 844 // 845 // * Convert angles and stops from counter-clockwise to clockwise 846 // * for the shader if the gradient is not already reversed due to 847 // * start angle being larger than end angle. 848 // 849 // Undo that. 850 let (start_angle, end_angle) = (360. - start_angle, 360. - end_angle); 851 let start_angle = start_angle.to_radians(); 852 let end_angle = end_angle.to_radians(); 853 unsafe { 854 hb_paint_sweep_gradient( 855 self.paint_funcs, 856 self.paint_data, 857 &mut color_line, 858 c0.x, 859 c0.y, 860 start_angle, 861 end_angle, 862 ); 863 } 864 } 865 } 866 } 867 fn push_layer(&mut self, _mode: CompositeMode) { 868 unsafe { 869 hb_paint_push_group(self.paint_funcs, self.paint_data); 870 } 871 } 872 fn pop_layer_with_mode(&mut self, mode: CompositeMode) { 873 let mode = mode as hb_paint_composite_mode_t; // They are the same 874 unsafe { 875 hb_paint_pop_group(self.paint_funcs, self.paint_data, mode); 876 } 877 } 878 } 879 880 extern "C" fn _hb_fontations_paint_glyph_or_fail( 881 font: *mut hb_font_t, 882 font_data: *mut ::std::os::raw::c_void, 883 glyph: hb_codepoint_t, 884 paint_funcs: *mut hb_paint_funcs_t, 885 paint_data: *mut ::std::os::raw::c_void, 886 palette_index: ::std::os::raw::c_uint, 887 foreground: hb_color_t, 888 _user_data: *mut ::std::os::raw::c_void, 889 ) -> hb_bool_t { 890 let data = unsafe { &mut *(font_data as *mut FontationsData) }; 891 data.check_for_updates(); 892 893 let font_ref = &data.font_ref; 894 let location = &data.location; 895 let color_glyphs = &data.color_glyphs; 896 897 let glyph_id = GlyphId::new(glyph); 898 let Some(color_glyph) = color_glyphs.get(glyph_id) else { 899 return false as hb_bool_t; 900 }; 901 902 let cpal = font_ref.cpal(); 903 let color_records = if let Ok(cpal) = cpal { 904 let num_entries = cpal.num_palette_entries().into(); 905 let color_records = cpal.color_records_array(); 906 let start_index = cpal 907 .color_record_indices() 908 .get(palette_index as usize) 909 .or_else(|| { 910 // https://github.com/harfbuzz/harfbuzz/issues/5116 911 cpal.color_record_indices().first() 912 }); 913 914 if let (Some(Ok(color_records)), Some(start_index)) = (color_records, start_index) { 915 let start_index: usize = start_index.get().into(); 916 let color_records = &color_records[start_index..start_index + num_entries]; 917 unsafe { std::slice::from_raw_parts(color_records.as_ptr(), num_entries) } 918 } else { 919 &[] 920 } 921 } else { 922 &[] 923 }; 924 925 let font = if (unsafe { hb_font_is_synthetic(font) } != false as hb_bool_t) { 926 unsafe { 927 let sub_font = hb_font_create_sub_font(font); 928 hb_font_set_synthetic_bold(sub_font, 0.0, 0.0, true as hb_bool_t); 929 hb_font_set_synthetic_slant(sub_font, 0.0); 930 sub_font 931 } 932 } else { 933 unsafe { hb_font_reference(font) } 934 }; 935 936 let mut painter = HbColorPainter { 937 font, 938 paint_funcs, 939 paint_data, 940 color_records, 941 foreground, 942 is_glyph_clip: 0, 943 clip_depth: 0, 944 }; 945 unsafe { 946 hb_paint_push_font_transform(paint_funcs, paint_data, font); 947 } 948 let _ = color_glyph.paint(location, &mut painter); 949 unsafe { 950 hb_paint_pop_transform(paint_funcs, paint_data); 951 hb_font_destroy(font); 952 } 953 true as hb_bool_t 954 } 955 956 extern "C" fn _hb_fontations_glyph_name( 957 _font: *mut hb_font_t, 958 font_data: *mut ::std::os::raw::c_void, 959 glyph: hb_codepoint_t, 960 name: *mut ::std::os::raw::c_char, 961 size: ::std::os::raw::c_uint, 962 _user_data: *mut ::std::os::raw::c_void, 963 ) -> hb_bool_t { 964 let data = unsafe { &mut *(font_data as *mut FontationsData) }; 965 966 if let Some(glyph_name) = data.glyph_names.get(GlyphId::new(glyph)) { 967 let glyph_name = glyph_name.as_str(); 968 // Copy the glyph name into the buffer, up to size-1 bytes 969 let len = glyph_name.len().min(size as usize - 1); 970 unsafe { 971 std::slice::from_raw_parts_mut(name as *mut u8, len) 972 .copy_from_slice(&glyph_name.as_bytes()[..len]); 973 *name.add(len) = 0; 974 } 975 true as hb_bool_t 976 } else { 977 false as hb_bool_t 978 } 979 } 980 981 static mut GLYPH_FROM_NAMES_KEY: hb_user_data_key_t = hb_user_data_key_t { unused: 0 }; 982 983 extern "C" fn _hb_glyph_from_names_destroy(data: *mut c_void) { 984 let _ = unsafe { Box::from_raw(data as *mut HashMap<String, u32>) }; 985 } 986 987 extern "C" fn _hb_fontations_glyph_from_name( 988 font: *mut hb_font_t, 989 font_data: *mut ::std::os::raw::c_void, 990 name: *const ::std::os::raw::c_char, 991 len: ::std::os::raw::c_int, 992 glyph: *mut hb_codepoint_t, 993 _user_data: *mut ::std::os::raw::c_void, 994 ) -> hb_bool_t { 995 let data = unsafe { &*(font_data as *const FontationsData) }; 996 997 // SAFETY: HarfBuzz guarantees the string is valid memory for `len` bytes. 998 let name_bytes = unsafe { std::slice::from_raw_parts(name as *const u8, len as usize) }; 999 let name_str = match std::str::from_utf8(name_bytes) { 1000 Ok(s) => s, 1001 Err(_) => return false as hb_bool_t, 1002 }; 1003 1004 let face = unsafe { hb_font_get_face(font) }; 1005 let mut user_data_ptr: *mut c_void; 1006 1007 loop { 1008 user_data_ptr = 1009 unsafe { hb_face_get_user_data(face, std::ptr::addr_of_mut!(GLYPH_FROM_NAMES_KEY)) }; 1010 if !user_data_ptr.is_null() { 1011 break; 1012 } 1013 1014 // Build the HashMap from glyph names to IDs 1015 let mut map = HashMap::new(); 1016 for (glyph_id, glyph_name) in data.glyph_names.iter() { 1017 map.insert(glyph_name.to_string(), glyph_id.to_u32()); 1018 } 1019 1020 let boxed_map = Box::new(map); 1021 let ptr = Box::into_raw(boxed_map) as *mut c_void; 1022 1023 let success = unsafe { 1024 hb_face_set_user_data( 1025 face, 1026 std::ptr::addr_of_mut!(GLYPH_FROM_NAMES_KEY), 1027 ptr, 1028 Some(_hb_glyph_from_names_destroy), 1029 true as hb_bool_t, 1030 ) 1031 }; 1032 1033 if success != false as hb_bool_t { 1034 user_data_ptr = ptr; 1035 break; 1036 } 1037 1038 // We failed to set user data — reclaim the pointer to avoid leaking 1039 _hb_glyph_from_names_destroy(ptr); 1040 // Try again in next loop iteration 1041 } 1042 1043 let glyph_from_names = unsafe { &*(user_data_ptr as *const HashMap<String, u32>) }; 1044 1045 match glyph_from_names.get(name_str) { 1046 Some(gid) => { 1047 unsafe { *glyph = *gid }; 1048 true as hb_bool_t 1049 } 1050 None => false as hb_bool_t, 1051 } 1052 } 1053 1054 fn _hb_fontations_font_funcs_get() -> *mut hb_font_funcs_t { 1055 static STATIC_FFUNCS: AtomicPtr<hb_font_funcs_t> = AtomicPtr::new(null_mut()); 1056 1057 loop { 1058 let mut ffuncs = STATIC_FFUNCS.load(Ordering::Acquire); 1059 1060 if !ffuncs.is_null() { 1061 return ffuncs; 1062 } 1063 1064 ffuncs = unsafe { hb_font_funcs_create() }; 1065 1066 unsafe { 1067 hb_font_funcs_set_nominal_glyphs_func( 1068 ffuncs, 1069 Some(_hb_fontations_get_nominal_glyphs), 1070 null_mut(), 1071 None, 1072 ); 1073 hb_font_funcs_set_variation_glyph_func( 1074 ffuncs, 1075 Some(_hb_fontations_get_variation_glyph), 1076 null_mut(), 1077 None, 1078 ); 1079 hb_font_funcs_set_glyph_h_advances_func( 1080 ffuncs, 1081 Some(_hb_fontations_get_glyph_h_advances), 1082 null_mut(), 1083 None, 1084 ); 1085 hb_font_funcs_set_glyph_v_advances_func( 1086 ffuncs, 1087 Some(_hb_fontations_get_glyph_v_advances), 1088 null_mut(), 1089 None, 1090 ); 1091 hb_font_funcs_set_glyph_v_origin_func( 1092 ffuncs, 1093 Some(_hb_fontations_get_glyph_v_origin), 1094 null_mut(), 1095 None, 1096 ); 1097 hb_font_funcs_set_glyph_extents_func( 1098 ffuncs, 1099 Some(_hb_fontations_get_glyph_extents), 1100 null_mut(), 1101 None, 1102 ); 1103 hb_font_funcs_set_font_h_extents_func( 1104 ffuncs, 1105 Some(_hb_fontations_get_font_h_extents), 1106 null_mut(), 1107 None, 1108 ); 1109 hb_font_funcs_set_draw_glyph_or_fail_func( 1110 ffuncs, 1111 Some(_hb_fontations_draw_glyph_or_fail), 1112 null_mut(), 1113 None, 1114 ); 1115 hb_font_funcs_set_paint_glyph_or_fail_func( 1116 ffuncs, 1117 Some(_hb_fontations_paint_glyph_or_fail), 1118 null_mut(), 1119 None, 1120 ); 1121 hb_font_funcs_set_glyph_name_func( 1122 ffuncs, 1123 Some(_hb_fontations_glyph_name), 1124 null_mut(), 1125 None, 1126 ); 1127 hb_font_funcs_set_glyph_from_name_func( 1128 ffuncs, 1129 Some(_hb_fontations_glyph_from_name), 1130 null_mut(), 1131 None, 1132 ); 1133 } 1134 1135 if (STATIC_FFUNCS.compare_exchange(null_mut(), ffuncs, Ordering::SeqCst, Ordering::Relaxed)) 1136 == Ok(null_mut()) 1137 { 1138 return ffuncs; 1139 } else { 1140 unsafe { 1141 hb_font_funcs_destroy(ffuncs); 1142 } 1143 } 1144 } 1145 } 1146 1147 /// # Safety 1148 /// 1149 /// This function is unsafe because it connects with the HarfBuzz API. 1150 #[no_mangle] 1151 pub unsafe extern "C" fn hb_fontations_font_set_funcs(font: *mut hb_font_t) { 1152 let ffuncs = _hb_fontations_font_funcs_get(); 1153 1154 let data = FontationsData::from_hb_font(font); 1155 let data = match data { 1156 Some(d) => d, 1157 None => return, 1158 }; 1159 let data_ptr = Box::into_raw(Box::new(data)) as *mut c_void; 1160 1161 hb_font_set_funcs(font, ffuncs, data_ptr, Some(_hb_fontations_data_destroy)); 1162 }