tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }