opentypejs / opentype.js

Read and write OpenType fonts using JavaScript.
https://opentype.js.org/
MIT License
4.38k stars 468 forks source link

Ligature #414

Closed yne closed 4 years ago

yne commented 4 years ago

Expected Behavior

Created ligature, using

font.substitution.addLigature("liga", {sub: [65,66], by:64})

shall be visible. (AB shall be replaced with the @ Glyph)

Current Behavior

The ligature is successfully created (according to font.tables.gsub.lookups) and match the expected results from the /tests/substitution.js testcase. However the ligature is not applied by the browser (see: steps to reproduce).

Possible Solution

I tried the ~5 example available on github and comparing the generated bsub table to the tests. However to be sure that this is not a browser-related issue I used the following sample (require IcoMoon otf/ttf):

<style>@font-face {font-family: 'IM';src: url('IcoMoon-Free.otf') format('opentype');}</style>
<textarea style=font-family:IM cols=5>house</textarea>

And it perfectly work ("house" is replaced by the Glyph in realtime) without any CSS/JS/HTML code.

Steps to Reproduce (for bugs)

This is a small example that create 3 glyphs and add a ligature

<script src="https://cdn.jsdelivr.net/npm/opentype.js"></script>
<script>
const advanceWidth=16;//<16 is not valid ?!
const undefGlyph = new opentype.Glyph({name: '.notdef',
    unicode: 0, advanceWidth, path: new opentype.Path()});
const arrowGlyph = new opentype.Glyph({name: 'arrow',
    unicode:64, advanceWidth, path: new opentype.Path()});
arrowGlyph.path.moveTo(0,8);arrowGlyph.path.lineTo(8,0);arrowGlyph.path.lineTo(8,8);
const alph1Glyph = new opentype.Glyph({name: 'A',
    unicode:65, advanceWidth, path: new opentype.Path()});
alph1Glyph.path.moveTo(0,8);alph1Glyph.path.lineTo(8,0);alph1Glyph.path.lineTo(8,4);
const alph2Glyph = new opentype.Glyph({name: 'B',
    unicode:66, advanceWidth, path: new opentype.Path()});
alph2Glyph.path.moveTo(0,8);alph2Glyph.path.lineTo(8,0);alph2Glyph.path.lineTo(4,8);

const font = new opentype.Font({
    familyName: 'Acme',
    styleName: 'Medium',
    unitsPerEm: advanceWidth,
    ascender: advanceWidth,
    descender: -Number.EPSILON, // 0 os not valid ?!
    glyphs: [undefGlyph, arrowGlyph, alph1Glyph, alph2Glyph]
});
font.substitution.addLigature("liga", {sub: [65,66], by:64});//AB=>@
document.fonts.add(new FontFace(font.names.fontFamily.en, font.toArrayBuffer()));
</script>
<textarea style=font-family:acme rows=4>
AB shall be @ or &#64;
</textarea>

Context

I was trying to create a ligature for a font an stumble upon this issue. Most of my research are based on https://github.com/opentypejs/opentype.js/issues/194 code examples, so maybe some codes are outdated ? maybe I need to font.substitution.createDefaultTable() first ? Maybe I need to declare the ligature feature as "available" before exporting the font ?

Your Environment

fizfaz commented 4 years ago

you have to use the glyph-index. Changing the addLigature call to

font.substitution.addLigature("liga", {sub: [2,3], by:1});//AB=>@

substitutes AB:

image