Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

missing ligature characters #187

Closed
jossef opened this issue Feb 16, 2019 · 2 comments
Closed

missing ligature characters #187

jossef opened this issue Feb 16, 2019 · 2 comments

Comments

@jossef
Copy link

jossef commented Feb 16, 2019

I have an existing ttf font where I wish to extract all Ligature mappings into this form:

{
    "calendar_today": "E935",
    "calendar_view_day": "E936",
    ...
}

I'm using this snippet:

const fontkit = require('fontkit');
let font = fontkit.openSync('./MaterialIcons-Regular.ttf');
let lookupList = font.GSUB.lookupList.toArray();
let lookupListIndexes = font.GSUB.featureList[0].feature.lookupListIndexes;

lookupListIndexes.forEach(index => {
    let subTable = lookupList[index].subTables[0];
    let ligatureSets = subTable.ligatureSets.toArray();

    ligatureSets.forEach(ligatureSet => {
        ligatureSet.forEach(ligature => {
            let character = font.stringsForGlyph(ligature.glyph)[0];
            let characterCode = character.charCodeAt(0).toString(16).toUpperCase();

            let ligatureText = ligature
                .components
                .map(x => font.stringsForGlyph(x)[0])
                .join('');

            console.log(`${ligatureText} -> ${characterCode}`);
        });
    });
});

However, I'm not getting the full Ligature name. output:

...
alendar_today -> E935
rop_portrait -> E3C5
ontact_phone -> E0CF
ontrol_point -> E3BA
hevron_right -> E5CC
...

Am I doing something wrong? Judging by the analysis with FontForge, the font's Ligature names are not missing any characters.

image

@Pomax
Copy link
Contributor

Pomax commented Feb 16, 2019

Remember that the substitution table's coverage gives you the first glyph, and then the ligaturesets are for "everything after that". To quote the spec:

For example, if the Coverage table lists the glyph index for a lowercase “f,” then a LigatureSet table will define the “ffl,” “fl,” “ffi,” “fi,” and “ff” ligatures.

It does this by not "double-encoding" that first letter, so that first code point is left out of the actual substitution rules.

@jossef
Copy link
Author

jossef commented Feb 16, 2019

thanks!

posting my fixed snippet here
https://stackoverflow.com/questions/54721774/extracting-ttf-font-ligature-mappings/54728584#54728584

const fontkit = require('fontkit');
let font = fontkit.openSync('./MaterialIcons-Regular.ttf');
let lookupList = font.GSUB.lookupList.toArray();
let lookupListIndexes = font.GSUB.featureList[0].feature.lookupListIndexes;

lookupListIndexes.forEach(index => {
    let subTable = lookupList[index].subTables[0];

    let leadingCharacters = [];
    subTable.coverage.rangeRecords.forEach((coverage) => {
        for (let i = coverage.start; i <= coverage.end; i++) {
            let character = font.stringsForGlyph(i)[0];
            leadingCharacters.push(character);
        }
    });

    let ligatureSets = subTable.ligatureSets.toArray();

    ligatureSets.forEach((ligatureSet, ligatureSetIndex) => {

        let leadingCharacter = leadingCharacters[ligatureSetIndex];

        ligatureSet.forEach(ligature => {
            let character = font.stringsForGlyph(ligature.glyph)[0];
            let characterCode = character.charCodeAt(0).toString(16).toUpperCase();

            let ligatureText = ligature
                .components
                .map(x => font.stringsForGlyph(x)[0])
                .join('');

            ligatureText = leadingCharacter + ligatureText;

            console.log(`${ligatureText} -> ${characterCode}`);
        });
    });
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants