rustybuzz icon indicating copy to clipboard operation
rustybuzz copied to clipboard

`script::SCRIPT_MATH` seems to not pick up the `math` script tag in the font

Open mkorje opened this issue 7 months ago • 5 comments

MRE (at least as minimal as I could get) in rust:

rustybuzz v0.20.1
use rustybuzz::{Face, Feature, UnicodeBuffer, ttf_parser};
use std::fs::File;
use std::io::BufReader;
use std::io::Read;

fn main() {
    let f = File::open("NewCMMath-Book.otf").unwrap();
    let mut reader = BufReader::new(f);
    let mut buffer = Vec::new();
    reader.read_to_end(&mut buffer).unwrap();
    let ttf_face = ttf_parser::Face::parse(buffer.as_slice(), 0).unwrap();

    let c = '𝑖';
    let id = ttf_face.glyph_index(c).unwrap().0;

    let rusty_face = Face::from_face(ttf_face);
    let features = [Feature::new(ttf_parser::Tag::from_bytes(b"ssty"), 1, ..)];

    // With script set to "Zmth"
    let mut buffer = UnicodeBuffer::new();
    buffer.add(c, 0);
    buffer.set_script(rustybuzz::script::SCRIPT_MATH);
    let buffer = rustybuzz::shape(&rusty_face, &features, buffer);
    let new_id = buffer.glyph_infos()[0].glyph_id as u16;
    assert_eq!(new_id, id);

    // With script set to "math"
    let mut buffer = buffer.clear();
    buffer.add(c, 0);
    buffer.set_script(
        rustybuzz::Script::from_iso15924_tag(ttf_parser::Tag::from_bytes(b"math")).unwrap(),
    );
    let buffer = rustybuzz::shape(&rusty_face, &features, buffer);
    let new_id = buffer.glyph_infos()[0].glyph_id as u16;
    assert_ne!(new_id, id);
}

Here's what happens with harfbuzz:

hb-shape (HarfBuzz) 10.2.0
$ hb-shape --trace --script=Zmth --features=ssty NewCMMath-Book.otf "𝑖"
trace: start table GSUB script tag 'math'       buffer: [u1D456=0]
trace: start lookup 7 feature 'ssty'    buffer: [u1D456=0]
trace: replacing glyph at 0 (alternate substitution)    buffer: [u1D456=0]
trace: replaced glyph at 0 (alternate substitution)     buffer: [u1D456.st=0]
trace: end lookup 7 feature 'ssty'      buffer: [u1D456.st=0]
trace: end table GSUB script tag 'math' buffer: [u1D456.st=0]
trace: start table GPOS script tag 'math'       buffer: [u1D456.st=0+404]
trace: start lookup 0 feature 'kern'    buffer: [u1D456.st=0+404]
trace: skipped lookup 0 feature 'kern' because no glyph matches buffer: [u1D456.st=0+404]
trace: end lookup 0 feature 'kern'      buffer: [u1D456.st=0+404]
trace: start lookup 1 feature 'kern'    buffer: [u1D456.st=0+404]
trace: skipped lookup 1 feature 'kern' because no glyph matches buffer: [u1D456.st=0+404]
trace: end lookup 1 feature 'kern'      buffer: [u1D456.st=0+404]
trace: end table GPOS script tag 'math' buffer: [u1D456.st=0+404]
[u1D456.st=0+404]

$ hb-shape --trace --script=math --features=ssty NewCMMath-Book.otf "𝑖"
trace: start table GSUB script tag 'math'       buffer: [u1D456=0]
trace: start lookup 7 feature 'ssty'    buffer: [u1D456=0]
trace: replacing glyph at 0 (alternate substitution)    buffer: [u1D456=0]
trace: replaced glyph at 0 (alternate substitution)     buffer: [u1D456.st=0]
trace: end lookup 7 feature 'ssty'      buffer: [u1D456.st=0]
trace: end table GSUB script tag 'math' buffer: [u1D456.st=0]
trace: start table GPOS script tag 'math'       buffer: [u1D456.st=0+404]
trace: start lookup 0 feature 'kern'    buffer: [u1D456.st=0+404]
trace: skipped lookup 0 feature 'kern' because no glyph matches buffer: [u1D456.st=0+404]
trace: end lookup 0 feature 'kern'      buffer: [u1D456.st=0+404]
trace: start lookup 1 feature 'kern'    buffer: [u1D456.st=0+404]
trace: skipped lookup 1 feature 'kern' because no glyph matches buffer: [u1D456.st=0+404]
trace: end lookup 1 feature 'kern'      buffer: [u1D456.st=0+404]
trace: end table GPOS script tag 'math' buffer: [u1D456.st=0+404]
[u1D456.st=0+404]

$ hb-shape --version
hb-shape (HarfBuzz) 10.2.0
Available shapers: graphite2,ot,fallback

mkorje avatar May 28 '25 04:05 mkorje

Thanks for the MRE, how urgent is it (i.e. is it necessary for the PR to lang)? If it's critical I can try to find some time to debug it.

LaurenzV avatar May 28 '25 08:05 LaurenzV

Not very urgent, everything appears to work just fine using the "math" script tag so it shouldn't block the PR.

mkorje avatar May 28 '25 11:05 mkorje

old_tag_from_script() implementation is different between rustybuzz and harfbuzz:

hb_ot_old_tag_from_script (hb_script_t script)
{
  /* This seems to be accurate as of end of 2012. */


  switch ((hb_tag_t) script)
  {
    case HB_SCRIPT_INVALID:		return HB_OT_TAG_DEFAULT_SCRIPT;
    case HB_SCRIPT_MATH:		return HB_OT_TAG_MATH_SCRIPT;


    /* KATAKANA and HIRAGANA both map to 'kana' */
    case HB_SCRIPT_HIRAGANA:		return HB_TAG('k','a','n','a');


    /* Spaces at the end are preserved, unlike ISO 15924 */
    case HB_SCRIPT_LAO:			return HB_TAG('l','a','o',' ');
    case HB_SCRIPT_YI:			return HB_TAG('y','i',' ',' ');
    /* Unicode-5.0 additions */
    case HB_SCRIPT_NKO:			return HB_TAG('n','k','o',' ');
    /* Unicode-5.1 additions */
    case HB_SCRIPT_VAI:			return HB_TAG('v','a','i',' ');
  }


  /* Else, just change first char to lowercase and return */
  return ((hb_tag_t) script) | 0x20000000u;
}

Rustybuzz is not handling INVALID or MATH scripts:

fn old_tag_from_script(script: Script) -> hb_tag_t {
    // This seems to be accurate as of end of 2012.
    match script {
        // Katakana and Hiragana both map to 'kana'.
        script::HIRAGANA => hb_tag_t::from_bytes(b"kana"),


        // Spaces at the end are preserved, unlike ISO 15924.
        script::LAO => hb_tag_t::from_bytes(b"lao "),
        script::YI => hb_tag_t::from_bytes(b"yi  "),
        // Unicode-5.0 additions.
        script::NKO => hb_tag_t::from_bytes(b"nko "),
        // Unicode-5.1 additions.
        script::VAI => hb_tag_t::from_bytes(b"vai "),


        // Else, just change first char to lowercase and return.
        _ => hb_tag_t(script.tag().as_u32() | 0x20000000),
    }
}

Probably it is missing this commit from HarfBuzz? https://github.com/harfbuzz/harfbuzz/commit/1bc4bad7a59e9d4d79d8faeb9e695df19aa494da

khaledhosny avatar May 28 '25 11:05 khaledhosny

74b4fcdc4c09a9420aee5b54f77e556133bd0142 seems to have missed the conversion from HB_SCRIPT_MATH to HB_OT_TAG_MATH_SCRIPT.

khaledhosny avatar May 28 '25 11:05 khaledhosny

74b4fcd seems to have missed the conversion from HB_SCRIPT_MATH to HB_OT_TAG_MATH_SCRIPT.

We should also fix in harfRuzz.

behdad avatar May 28 '25 22:05 behdad

I tried applying https://github.com/harfbuzz/harfruzz/pull/58 but needs porting.

behdad avatar Jun 07 '25 09:06 behdad