tor-browser

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

shape.rs (12229B)


      1 #![allow(non_upper_case_globals)]
      2 
      3 use super::hb::*;
      4 
      5 use std::ffi::c_void;
      6 use std::mem::transmute;
      7 use std::ptr::null_mut;
      8 use std::str::FromStr;
      9 
     10 use harfrust::{FontRef, NormalizedCoord, Shaper, ShaperData, ShaperInstance, Tag};
     11 
     12 pub struct HBHarfRustFaceData<'a> {
     13    face_blob: *mut hb_blob_t,
     14    font_ref: FontRef<'a>,
     15    shaper_data: ShaperData,
     16 }
     17 
     18 #[no_mangle]
     19 pub unsafe extern "C" fn _hb_harfrust_shaper_face_data_create_rs(
     20    face: *mut hb_face_t,
     21 ) -> *mut c_void {
     22    let face_index = hb_face_get_index(face);
     23    let face_blob = hb_face_reference_blob(face);
     24    let blob_length = hb_blob_get_length(face_blob);
     25    let blob_data = hb_blob_get_data(face_blob, null_mut());
     26    if blob_data.is_null() {
     27        return null_mut();
     28    }
     29    let face_data = std::slice::from_raw_parts(blob_data as *const u8, blob_length as usize);
     30 
     31    let font_ref = match FontRef::from_index(face_data, face_index) {
     32        Ok(f) => f,
     33        Err(_) => return null_mut(),
     34    };
     35    let shaper_data = ShaperData::new(&font_ref);
     36 
     37    let hr_face_data = Box::new(HBHarfRustFaceData {
     38        face_blob,
     39        font_ref,
     40        shaper_data,
     41    });
     42 
     43    Box::into_raw(hr_face_data) as *mut c_void
     44 }
     45 
     46 #[no_mangle]
     47 pub unsafe extern "C" fn _hb_harfrust_shaper_face_data_destroy_rs(data: *mut c_void) {
     48    let data = data as *mut HBHarfRustFaceData;
     49    let hr_face_data = Box::from_raw(data);
     50    let blob = hr_face_data.face_blob;
     51    hb_blob_destroy(blob);
     52 }
     53 
     54 pub struct HBHarfRustFontData {
     55    shaper_instance: Box<ShaperInstance>,
     56    shaper: Shaper<'static>,
     57 }
     58 
     59 fn font_to_shaper_instance(font: *mut hb_font_t, font_ref: &FontRef<'_>) -> ShaperInstance {
     60    let mut num_coords: u32 = 0;
     61    let coords = unsafe { hb_font_get_var_coords_normalized(font, &mut num_coords) };
     62    let coords = if coords.is_null() {
     63        &[]
     64    } else {
     65        unsafe { std::slice::from_raw_parts(coords, num_coords as usize) }
     66    };
     67    let coords = coords.iter().map(|&v| NormalizedCoord::from_bits(v as i16));
     68    ShaperInstance::from_coords(font_ref, coords)
     69 }
     70 
     71 #[no_mangle]
     72 pub unsafe extern "C" fn _hb_harfrust_shaper_font_data_create_rs(
     73    font: *mut hb_font_t,
     74    face_data: *const c_void,
     75 ) -> *mut c_void {
     76    let face_data = face_data as *const HBHarfRustFaceData;
     77 
     78    let font_ref = &(*face_data).font_ref;
     79    let shaper_instance = Box::new(font_to_shaper_instance(font, font_ref));
     80 
     81    let shaper_instance_ref = &*(&*shaper_instance as *const _);
     82    let shaper = (*face_data)
     83        .shaper_data
     84        .shaper(font_ref)
     85        .instance(Some(shaper_instance_ref))
     86        .build();
     87 
     88    let hr_font_data = Box::new(HBHarfRustFontData {
     89        shaper_instance,
     90        shaper: transmute::<harfrust::Shaper<'_>, harfrust::Shaper<'_>>(shaper),
     91    });
     92    let hr_font_data_ptr = Box::into_raw(hr_font_data);
     93 
     94    hr_font_data_ptr as *mut c_void
     95 }
     96 
     97 #[no_mangle]
     98 pub unsafe extern "C" fn _hb_harfrust_shaper_font_data_destroy_rs(data: *mut c_void) {
     99    let data = data as *mut HBHarfRustFontData;
    100    let _hr_font_data = Box::from_raw(data);
    101 }
    102 
    103 fn hb_language_to_hr_language(language: hb_language_t) -> Option<harfrust::Language> {
    104    let language_str = unsafe { hb_language_to_string(language) };
    105    if language_str.is_null() {
    106        return None;
    107    }
    108    let language_str = unsafe { std::ffi::CStr::from_ptr(language_str) };
    109    let language_str = language_str.to_str().unwrap_or_default();
    110    Some(harfrust::Language::from_str(language_str).unwrap())
    111 }
    112 
    113 #[no_mangle]
    114 pub unsafe extern "C" fn _hb_harfrust_buffer_create_rs() -> *mut c_void {
    115    let hr_buffer = Box::new(harfrust::UnicodeBuffer::new());
    116    Box::into_raw(hr_buffer) as *mut c_void
    117 }
    118 
    119 #[no_mangle]
    120 pub unsafe extern "C" fn _hb_harfrust_buffer_destroy_rs(data: *mut c_void) {
    121    let data = data as *mut harfrust::UnicodeBuffer;
    122    let _hr_buffer = Box::from_raw(data);
    123 }
    124 
    125 #[no_mangle]
    126 pub unsafe extern "C" fn _hb_harfrust_shape_plan_create_rs(
    127    font_data: *const c_void,
    128    script: hb_script_t,
    129    language: hb_language_t,
    130    direction: hb_direction_t,
    131 ) -> *mut c_void {
    132    let font_data = font_data as *const HBHarfRustFontData;
    133 
    134    let script = harfrust::Script::from_iso15924_tag(Tag::from_u32(script));
    135    let language = hb_language_to_hr_language(language);
    136    let direction = match direction {
    137        hb_direction_t_HB_DIRECTION_LTR => harfrust::Direction::LeftToRight,
    138        hb_direction_t_HB_DIRECTION_RTL => harfrust::Direction::RightToLeft,
    139        hb_direction_t_HB_DIRECTION_TTB => harfrust::Direction::TopToBottom,
    140        hb_direction_t_HB_DIRECTION_BTT => harfrust::Direction::BottomToTop,
    141        _ => harfrust::Direction::Invalid,
    142    };
    143 
    144    let shaper = &(*font_data).shaper;
    145 
    146    let hr_shape_plan = harfrust::ShapePlan::new(shaper, direction, script, language.as_ref(), &[]);
    147    let hr_shape_plan = Box::new(hr_shape_plan);
    148    Box::into_raw(hr_shape_plan) as *mut c_void
    149 }
    150 
    151 #[no_mangle]
    152 pub unsafe extern "C" fn _hb_harfrust_shape_plan_destroy_rs(data: *mut c_void) {
    153    let data = data as *mut harfrust::ShapePlan;
    154    let _hr_shape_plan = Box::from_raw(data);
    155 }
    156 
    157 #[no_mangle]
    158 pub unsafe extern "C" fn _hb_harfrust_shape_rs(
    159    font_data: *const c_void,
    160    face_data: *const c_void,
    161    shape_plan: *const c_void,
    162    hr_buffer_box: *const c_void,
    163    font: *mut hb_font_t,
    164    buffer: *mut hb_buffer_t,
    165    pre_context: *const u8,
    166    pre_context_length: u32,
    167    post_context: *const u8,
    168    post_context_length: u32,
    169    features: *const hb_feature_t,
    170    num_features: u32,
    171 ) -> hb_bool_t {
    172    let font_data = font_data as *const HBHarfRustFontData;
    173    let face_data = face_data as *const HBHarfRustFaceData;
    174 
    175    let font_ref = &(*face_data).font_ref;
    176 
    177    let hr_buffer_box = hr_buffer_box as *mut harfrust::UnicodeBuffer;
    178    let mut hr_buffer_box = Box::from_raw(hr_buffer_box);
    179    let mut hr_buffer = *hr_buffer_box;
    180 
    181    // Set buffer properties
    182    let cluster_level = hb_buffer_get_cluster_level(buffer);
    183    let cluster_level = match cluster_level {
    184        hb_buffer_cluster_level_t_HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES => {
    185            harfrust::BufferClusterLevel::MonotoneGraphemes
    186        }
    187        hb_buffer_cluster_level_t_HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS => {
    188            harfrust::BufferClusterLevel::MonotoneCharacters
    189        }
    190        hb_buffer_cluster_level_t_HB_BUFFER_CLUSTER_LEVEL_CHARACTERS => {
    191            harfrust::BufferClusterLevel::Characters
    192        }
    193        hb_buffer_cluster_level_t_HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES => {
    194            harfrust::BufferClusterLevel::Graphemes
    195        }
    196        _ => harfrust::BufferClusterLevel::default(),
    197    };
    198    hr_buffer.set_cluster_level(cluster_level);
    199    let flags = hb_buffer_get_flags(buffer);
    200    hr_buffer.set_flags(harfrust::BufferFlags::from_bits_truncate(flags));
    201    let not_found_variation_selector_glyph =
    202        hb_buffer_get_not_found_variation_selector_glyph(buffer);
    203    if not_found_variation_selector_glyph != u32::MAX {
    204        hr_buffer.set_not_found_variation_selector_glyph(not_found_variation_selector_glyph);
    205    }
    206 
    207    // Segment properties:
    208    let script = hb_buffer_get_script(buffer);
    209    let language = hb_buffer_get_language(buffer);
    210    let direction = hb_buffer_get_direction(buffer);
    211    // Convert to HarfRust types
    212    let script = harfrust::Script::from_iso15924_tag(Tag::from_u32(script))
    213        .unwrap_or(harfrust::script::UNKNOWN);
    214    let language = hb_language_to_hr_language(language);
    215    let direction = match direction {
    216        hb_direction_t_HB_DIRECTION_LTR => harfrust::Direction::LeftToRight,
    217        hb_direction_t_HB_DIRECTION_RTL => harfrust::Direction::RightToLeft,
    218        hb_direction_t_HB_DIRECTION_TTB => harfrust::Direction::TopToBottom,
    219        hb_direction_t_HB_DIRECTION_BTT => harfrust::Direction::BottomToTop,
    220        _ => harfrust::Direction::Invalid,
    221    };
    222    // Set properties on the buffer
    223    hr_buffer.set_script(script);
    224    if let Some(lang) = language {
    225        hr_buffer.set_language(lang);
    226    }
    227    hr_buffer.set_direction(direction);
    228 
    229    // Populate buffer
    230    let count = hb_buffer_get_length(buffer);
    231    let infos = hb_buffer_get_glyph_infos(buffer, null_mut());
    232 
    233    hr_buffer.reserve(count as usize);
    234 
    235    for i in 0..count {
    236        let info = &*infos.add(i as usize);
    237        let unicode = info.codepoint;
    238        let cluster = info.cluster;
    239        hr_buffer.add(char::from_u32_unchecked(unicode), cluster);
    240    }
    241 
    242    let pre_context = std::slice::from_raw_parts(pre_context, pre_context_length as usize);
    243    hr_buffer.set_pre_context(str::from_utf8(pre_context).unwrap());
    244    let post_context = std::slice::from_raw_parts(post_context, post_context_length as usize);
    245    hr_buffer.set_post_context(str::from_utf8(post_context).unwrap());
    246 
    247    let ptem = hb_font_get_ptem(font);
    248    let ptem = if ptem > 0.0 { Some(ptem) } else { None };
    249 
    250    let shaper = if ptem.is_some() {
    251        (*face_data)
    252            .shaper_data
    253            .shaper(font_ref)
    254            .instance(Some(&(*font_data).shaper_instance))
    255            .point_size(ptem)
    256            .build()
    257    } else {
    258        (*font_data).shaper.clone()
    259    };
    260 
    261    let features = if features.is_null() {
    262        Vec::new()
    263    } else {
    264        let features = std::slice::from_raw_parts(features, num_features as usize);
    265        features
    266            .iter()
    267            .map(|f| {
    268                let tag = f.tag;
    269                let value = f.value;
    270                let start = f.start;
    271                let end = f.end;
    272                harfrust::Feature {
    273                    tag: Tag::from_u32(tag),
    274                    value,
    275                    start,
    276                    end,
    277                }
    278            })
    279            .collect::<Vec<_>>()
    280    };
    281 
    282    let glyphs = if shape_plan.is_null() {
    283        shaper.shape(hr_buffer, &features)
    284    } else {
    285        let shape_plan = shape_plan as *const harfrust::ShapePlan;
    286        shaper.shape_with_plan(shape_plan.as_ref().unwrap(), hr_buffer, &features)
    287    };
    288 
    289    let count = glyphs.len();
    290    hb_buffer_set_length(buffer, 0u32);
    291    hb_buffer_set_content_type(
    292        buffer,
    293        hb_buffer_content_type_t_HB_BUFFER_CONTENT_TYPE_GLYPHS,
    294    );
    295    hb_buffer_set_length(buffer, count as u32);
    296    let mut count_out: u32 = 0;
    297    let infos = hb_buffer_get_glyph_infos(buffer, &mut count_out);
    298    let positions = hb_buffer_get_glyph_positions(buffer, null_mut());
    299    if count != count_out as usize {
    300        return false as hb_bool_t;
    301    }
    302 
    303    let mut x_scale: i32 = 0;
    304    let mut y_scale: i32 = 0;
    305    hb_font_get_scale(font, &mut x_scale, &mut y_scale);
    306    let upem = shaper.units_per_em();
    307    let upem = if upem > 0 { upem } else { 1000 };
    308    let x_mult = if x_scale < 0 {
    309        -((-x_scale as i64) << 16)
    310    } else {
    311        (x_scale as i64) << 16
    312    } / upem as i64;
    313    let y_mult = if y_scale < 0 {
    314        -((-y_scale as i64) << 16)
    315    } else {
    316        (y_scale as i64) << 16
    317    } / upem as i64;
    318 
    319    let em_mult =
    320        |v: i32, mult: i64| -> hb_position_t { ((v as i64 * mult + 32768) >> 16) as hb_position_t };
    321 
    322    for (i, (hr_info, hr_pos)) in glyphs
    323        .glyph_infos()
    324        .iter()
    325        .zip(glyphs.glyph_positions())
    326        .enumerate()
    327    {
    328        let info = &mut *infos.add(i);
    329        let pos = &mut *positions.add(i);
    330        info.codepoint = hr_info.glyph_id;
    331        info.cluster = hr_info.cluster;
    332        info.mask = 0;
    333        if hr_info.unsafe_to_break() {
    334            info.mask |= hb_glyph_flags_t_HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
    335        }
    336        if hr_info.unsafe_to_concat() {
    337            info.mask |= hb_glyph_flags_t_HB_GLYPH_FLAG_UNSAFE_TO_CONCAT;
    338        }
    339        if hr_info.safe_to_insert_tatweel() {
    340            info.mask |= hb_glyph_flags_t_HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL;
    341        }
    342        pos.x_advance = em_mult(hr_pos.x_advance, x_mult);
    343        pos.y_advance = em_mult(hr_pos.y_advance, y_mult);
    344        pos.x_offset = em_mult(hr_pos.x_offset, x_mult);
    345        pos.y_offset = em_mult(hr_pos.y_offset, y_mult);
    346    }
    347 
    348    let hr_buffer = glyphs.clear();
    349    *hr_buffer_box = hr_buffer; // Move the buffer back into the box
    350    let _ = Box::into_raw(hr_buffer_box); // Prevent double free
    351 
    352    true as hb_bool_t
    353 }