diff --git a/README.md b/README.md index 26c2447..471f93e 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Iosevka supports accessing all letter variants using OpenType features. To build Iosevka you should: -1. Ensure that [`node`](http://nodejs.org) (≥ 5.0), [`FontForge`](http://fontforge.org) (with Python scripting support, ≥ Aug. 2015 release), [`ttfautohint`](http://www.freetype.org/ttfautohint/), [`otfcc`](https://github.com/caryll/otfcc) (≥ 0.1.5) and `make` are runnable in your terminal. +1. Ensure that [`node`](http://nodejs.org) (≥ 5.0), [`FontForge`](http://fontforge.org) (with Python scripting support, ≥ Aug. 2015 release), [`ttfautohint`](http://www.freetype.org/ttfautohint/), [`otfcc`](https://github.com/caryll/otfcc) (≥ 0.1.6) and `make` are runnable in your terminal. - Windows users may need to install MinGW and make \*nix utilities accessible (`mkdir.exe`, `cp.exe`, `cat.exe` and `rm.exe`, in particular) from Command Prompt. Utilities provided by [Git for Windows](https://git-for-windows.github.io/) works fine. 2. Install necessary libs by `npm install`. 3. `make`. diff --git a/features/common.fea b/features/common.fea deleted file mode 100644 index 7f66895..0000000 --- a/features/common.fea +++ /dev/null @@ -1,76 +0,0 @@ -lookup ccmpSubIota { sub iotaBelow by iotaLF; } ccmpSubIota; -lookup ccmpSubOgonek { sub ogonekBelow by ogonekTR; } ccmpSubOgonek; -lookup ccmpManual1 { - sub [i cyrUkrainiani j cyrje iogonekBelow]' @MG_above by [dotlessi dotlessi dotlessj dotlessj iogonek.dotless]; - sub eta iotaBelow' lookup ccmpSubIota; - sub eta @MG_above iotaBelow' lookup ccmpSubIota; - sub eta @MG_above @MG_above iotaBelow' lookup ccmpSubIota; - sub eta @MG_above @MG_above @MG_above iotaBelow' lookup ccmpSubIota; - sub [a A u cyra cyrA] ogonekBelow' lookup ccmpSubOgonek; - sub [a A u cyra cyrA] @MG_above ogonekBelow' lookup ccmpSubOgonek; - sub [a A u cyra cyrA] @MG_above @MG_above ogonekBelow' lookup ccmpSubOgonek; - sub [a A u cyra cyrA] @MG_above @MG_above @MG_above ogonekBelow' lookup ccmpSubOgonek; -} ccmpManual1; - -lookup ccmpManual2 { - sub commaAbove graveAbove by psilivaria; - sub commaAbove acuteAbove by psilioxia; - sub commaAbove perispomeniAbove by psiliperispomeni; - sub revCommaAbove graveAbove by dasiavaria; - sub revCommaAbove acuteAbove by dasiaoxia; - sub revCommaAbove perispomeniAbove by dasiaperispomeni; -} ccmpManual2; - -feature ccmp { - script latn; - language dflt; - lookup ccmpManual1; - script grek; - language dflt; - lookup ccmpManual1; - lookup ccmpManual2; - script cyrl; - language dflt; - lookup ccmpManual1; - script DFLT; - language dflt; - lookup ccmpManual1; -} ccmp; - -feature mark { - script latn; - language dflt; - lookup markAuto_letter1; - lookup markAuto_letter2; - lookup markAuto_overlay; - script grek; - language dflt; - lookup markAuto_letter1; - lookup markAuto_letter2; - lookup markAuto_overlay; - script cyrl; - language dflt; - lookup markAuto_letter1; - lookup markAuto_letter2; - lookup markAuto_overlay; - script DFLT; - language dflt; - lookup markAuto_letter1; - lookup markAuto_letter2; - lookup markAuto_overlay; -} mark; - -feature mkmk { - script latn; - language dflt; - lookup mkmkAuto; - script grek; - language dflt; - lookup mkmkAuto; - script cyrl; - language dflt; - lookup mkmkAuto; - script DFLT; - language dflt; - lookup mkmkAuto; -} mkmk; \ No newline at end of file diff --git a/features/italiconly.fea b/features/italiconly.fea deleted file mode 100644 index 1552828..0000000 --- a/features/italiconly.fea +++ /dev/null @@ -1,9 +0,0 @@ -lookup loclSerbian { - sub [cyrbe cyrghe cyrde cyrpe cyrte] by [cyrbe.serbian cyrghe.serbian cyrde.serbian cyrpe.serbian cyrte.serbian]; -} loclSerbian; - -feature locl { - script cyrl; - language SRB exclude_dflt; - lookup loclSerbian; -} locl; \ No newline at end of file diff --git a/features/ligation.fea b/features/ligation.fea deleted file mode 100644 index 76586f1..0000000 --- a/features/ligation.fea +++ /dev/null @@ -1,96 +0,0 @@ -# Programming ligations -lookup arrowStickFR { sub [hyphen equal] by [lighy.fr ligeq.fr]; } arrowStickFR; -lookup arrowStickLF { sub [hyphen equal] by [lighy.lf ligeq.lf]; } arrowStickLF; -lookup arrowStickFR1 { sub [hyphen equal] by [lighy.fr1 ligeq.fr1]; } arrowStickFR1; -lookup arrowStickL1F { sub [hyphen equal] by [lighy.l1f ligeq.l1f]; } arrowStickL1F; -lookup arrowStickCR { sub [hyphen equal] by [lighy.cr ligeq.cr]; } arrowStickCR; -lookup arrowStickLC { sub [hyphen equal] by [lighy.lc ligeq.lc]; } arrowStickLC; -lookup arrowStickLXC { sub [hyphen equal] by [lighy.lxc ligeq.lxc]; } arrowStickLXC; -lookup arrowStickCF { sub [hyphen equal] by [lighy.cf ligeq.cf]; } arrowStickCF; -lookup arrowStickFC { sub [hyphen equal] by [lighy.fc ligeq.fc]; } arrowStickFC; -lookup arrowStickJF { sub [hyphen equal] by [lighy.jf ligeq.jf]; } arrowStickJF; -lookup arrowStickFJ { sub [hyphen equal] by [lighy.fj ligeq.fj]; } arrowStickFJ; -lookup arrowStickJ1F { sub [hyphen equal] by [lighy.j1f ligeq.j1f]; } arrowStickJ1F; -lookup arrowStickFJ1 { sub [hyphen equal] by [lighy.fj1 ligeq.fj1]; } arrowStickFJ1; -lookup arrowStickJR { sub [hyphen equal] by [lighy.jr ligeq.jr]; } arrowStickJR; -lookup arrowStickLJ { sub [hyphen equal] by [lighy.lj ligeq.lj]; } arrowStickLJ; -lookup arrowStickLR { sub [hyphen equal] by [lighy.lr ligeq.lr]; } arrowStickLR; - -lookup lessShift1 { sub less by ligless.shift1; } lessShift1; -lookup greaterShift1 { sub greater by liggreater.shift1; } greaterShift1; -lookup lessShiftN1 { sub less by ligless.shiftN1; } lessShiftN1; -lookup greaterShiftN1 { sub greater by liggreater.shiftN1; } greaterShiftN1; -lookup arrowExclamHTMLComment { sub exclam by ligexclam.htmlcommentstart; } arrowExclamHTMLComment; - -@arrowstick = [hyphen equal]; -lookup caltArrow1 { - # Arrows, sub - sub less @arrowstick' lookup arrowStickLC @arrowstick' lookup arrowStickCR greater; # <-->, <==> - sub less @arrowstick' lookup arrowStickLR greater; # <->, <=> - sub less @arrowstick' lookup arrowStickLJ less; # <-<, <=< - sub less @arrowstick' lookup arrowStickLC @arrowstick' lookup arrowStickCF; # <--, <== - sub less less' lookup lessShift1 @arrowstick' lookup arrowStickL1F; # <<-, <<= - sub less hyphen' lookup arrowStickLF; # <- - sub less exclam' lookup arrowExclamHTMLComment hyphen' lookup arrowStickLXC hyphen' lookup arrowStickCF; # , ==> - sub @arrowstick' lookup arrowStickFR1 greater' lookup greaterShift1 greater; # ->>, =>> - sub @arrowstick' lookup arrowStickFR greater; # ->, => - sub @arrowstick' lookup arrowStickFJ1 less' lookup lessShiftN1 less; # -<<, =<< - sub @arrowstick' lookup arrowStickFJ less; # -<, =< -} caltArrow1; - -feature calt { - script latn; - language dflt; - lookup caltArrow1; - script grek; - language dflt; - lookup caltArrow1; - script cyrl; - language dflt; - lookup caltArrow1; - script DFLT; - language dflt; - lookup caltArrow1; -} calt; - -@fwclose = [fwlcloseDoubleQuote fwlcloseSingleQuote dwlcjkSingleQuoteRight dwlcjkDoubleQuoteRight dwlparenRight]; -@hwclose = [closeDoubleQuote closeSingleQuote cjkSingleQuoteRight cjkDoubleQuoteRight parenRight]; -@fwopen = [fwropenDoubleQuote fwropenSingleQuote dwrcjkSingleQuoteLeft dwrcjkDoubleQuoteLeft dwrparenLeft]; -@hwopen = [openDoubleQuote openSingleQuote cjkSingleQuoteLeft cjkDoubleQuoteLeft parenLeft]; -@fwquoteopen = [fwropenDoubleQuote fwropenSingleQuote]; -@hwquoteopen = [openDoubleQuote openSingleQuote]; -@fwtrail = [dwlperiod dwlcomma dwlcjkperiod dwlcjkcomma]; -@hwtrail = [period comma cjkperiod cjkcomma]; -@fwmid = [dwccolon dwcsemicolon]; -@hwmid = [colon semicolon]; - - -lookup cjkCompress { - sub [@fwtrail @hwtrail @fwopen @hwopen @fwmid @hwmid] @fwopen' by @hwopen; - sub @fwclose' [@fwtrail @hwtrail @fwclose @hwclose @fwopen @hwopen @fwmid @hwmid] by @hwclose; -} cjkCompress; - -feature opbd { - script latn; - language dflt; - lookup cjkCompress; - script grek; - language dflt; - lookup cjkCompress; - script cyrl; - language dflt; - lookup cjkCompress; - script hani; - language dflt; - lookup cjkCompress; - script kana; - language dflt; - lookup cjkCompress; - script DFLT; - language dflt; - lookup cjkCompress; -} opbd; \ No newline at end of file diff --git a/features/uprightonly.fea b/features/uprightonly.fea deleted file mode 100644 index e702640..0000000 --- a/features/uprightonly.fea +++ /dev/null @@ -1,9 +0,0 @@ -lookup loclSerbian { - sub [cyrbe] by [cyrbe.serbian]; -} loclSerbian; - -feature locl { - script cyrl; - language SRB exclude_dflt; - lookup loclSerbian; -} locl; \ No newline at end of file diff --git a/generator.js b/generator.js index 72b7a1d..b813119 100644 --- a/generator.js +++ b/generator.js @@ -44,44 +44,11 @@ if (argv.charmap) (function() { if (argv.feature) (function() { console.log(' Writing feature file -> ' + argv.feature); var featurefile = '\n\n'; - // markGlyphs - for (var feature in font.features.cv) { - var base = [], replace = []; - for (var key in font.features.cv[feature]) { - base.push(key); - replace.push(font.features.cv[feature][key]); - }; - var lookupName = feature + 'Auto'; - featurefile += 'lookup ' + lookupName + ' { sub [' + base.join(' ') + '] by [' + replace.join(' ') + '];} ' + lookupName + ';\n\n'; - featurefile += 'feature ' + feature + ' { script latn; lookup ' + lookupName + '; script grek; lookup ' + lookupName + '; script cyrl; lookup ' + lookupName + '; script DFLT; lookup ' + lookupName + '; } ' + feature + ';\n\n'; - } - for (var feature in font.features.sscompose) { - var stmt = font.features.sscompose[feature].map(function(lookup) { return 'lookup ' + lookup + 'Auto' }).join(';') - featurefile += 'feature ' + feature + ' { script latn; ' + stmt + '; script grek; ' + stmt + '; script cyrl; ' + stmt + '; script DFLT; ' + stmt + '; } ' + feature + ';\n\n'; - } + + // MG groups for (var key in font.features.markGlyphs) { featurefile += '@MG_' + key + '= [' + font.features.markGlyphs[key].join(' ') + '];\n' } - // mark - var mark = font.features.mark; - for (var id in mark) { - var lookup = mark[id]; - var lookupName = 'markAuto_' + id; - featurefile += 'lookup ' + lookupName + ' {' + lookup.marks.join(';\n') + ';\n' - + lookup.bases.join(';\n') + ';} ' + lookupName + ';' - } - - // mkmk - var mkmk = font.features.mkmk; - featurefile += 'lookup mkmkAuto {' + mkmk.marks.join(';\n') + ';\n' - + mkmk.bases.join(';\n') + ';} mkmkAuto;' - - // gdef - var gdef = font.features.gdef; - featurefile += '@GDEF_Simple = [' + gdef.simple.join(' \n') + '];\n' - + '@GDEF_Ligature =[' + gdef.ligature.join(' \n') + '];\n' - + '@GDEF_Mark = [' + gdef.mark.join(' \n') + '];\n' - + 'table GDEF { GlyphClassDef @GDEF_Simple, @GDEF_Ligature, @GDEF_Mark, ;} GDEF;' featurefile += fs.readFileSync(__dirname + '/features/common.fea', 'utf-8'); featurefile += fs.readFileSync(__dirname + '/features/' + (font.parameters.isItalic ? 'italiconly.fea' : 'uprightonly.fea'), 'utf-8'); diff --git a/glyphs/autobuilds.ptl b/glyphs/autobuilds.ptl index c32e503..f30503f 100644 --- a/glyphs/autobuilds.ptl +++ b/glyphs/autobuilds.ptl @@ -821,25 +821,43 @@ if [not recursive] : begin set glyphList.length font.glyf.length for [local j 0] (j < font.glyf.length) [inc j] : set glyphList.(j) font.glyf.(j) - set font.features.cv {.} - foreach [name : items-of : Object.keys glyphs] : begin - if glyphs.(name).featureSelector : begin - local fs glyphs.(name).featureSelector - foreach [feature : items-of : Object.keys fs] : begin - if [not font.features.cv.(feature)] : set font.features.cv.(feature) {.} - set font.features.cv.(feature).(name) fs.(feature) - - set font.features.mark {.} - set font.features.mkmk {.marks {} .bases {}} - set font.features.markGlyphs {.} - set font.features.gdef {.simple {} .ligature {} .mark {}} - define [buildAnchorDescription glyph inserter propx propy prefix th] : begin - local buf '' - foreach key [items-of : Object.keys glyph.anchors] : if (!th || th.(key)) : buf = buf + ' ' + inserter + ' @' + prefix + key - return buf + # GPOS mark and mkmk + local markGlyphs {.} - # mark - define [createMarkLookup tableName anchorClasses] : let [lookup : set font.features.mark.(tableName) {.marks {} .bases {}}] : begin + local lookup_mark + .type 'gpos_mark_to_base' + .subtables {} + local lookup_mkmk + .type 'gpos_mark_to_mark' + .subtables {} + + set font.GPOS : object + languages + .DFLT_DFLT {.features {'mark0', 'mkmk0'}} + .latn_DFLT {.features {'mark0', 'mkmk0'}} + .grek_DFLT {.features {'mark0', 'mkmk0'}} + .cyrl_DFLT {.features {'mark0', 'mkmk0'}} + features + .mark0 {'l_mark'} + .mkmk0 {'l_mkmk'} + lookups + .l_mark lookup_mark + .l_mkmk lookup_mkmk + set font.GDEF {.glyphClassDef {.}} + + # mark and mkmk + define [createBaseInfo g th px py] : begin + local res {.} + local pushed false + foreach key [items-of : Object.keys g.anchors] : if (!th || th.(key)) : begin + set res.(key) : object + .x g.anchors.(key).(px || 'x') + .y g.anchors.(key).(py || 'y') + set pushed true + return : if pushed res nothing + + define [createMTSSubtable lookup anchorClasses] : begin + local subtable {.marks {.} .bases {.}} local th {.} foreach [ac : items-of anchorClasses] : set th.(ac) true foreach glyph [items-of glyphList] : if glyph.anchors : begin @@ -848,29 +866,214 @@ if [not recursive] : begin foreach [key : items-of anchorKeys] : if th.(key) : set hasAnchor true if hasAnchor : begin local isMarkGlyph false - foreach key [items-of anchorKeys] : if (glyph.anchors.(key).type == 'mark') : set isMarkGlyph true + local markKey nothing + foreach key [items-of anchorKeys] : if (glyph.anchors.(key).type == 'mark') : begin + set isMarkGlyph true + set markKey key if isMarkGlyph - then : lookup.marks.push : 'markClass ' + glyph.name + [buildAnchorDescription glyph '' 'x' 'y' 'mark' th] - else : lookup.bases.push : 'pos base ' + glyph.name + [buildAnchorDescription glyph 'mark' 'x' 'y' 'mark' th] + : then : begin + set subtable.marks.(glyph.name) : object + class markKey + x glyph.anchors.(markKey).x + y glyph.anchors.(markKey).y + if (lookup == lookup_mkmk) : begin + local r : createBaseInfo glyph th 'mbx' 'mby' + if r : set subtable.bases.(glyph.name) r + : else : if (lookup == lookup_mark) : begin + local r : createBaseInfo glyph th 'x' 'y' + if r : set subtable.bases.(glyph.name) r + lookup.subtables.push subtable - createMarkLookup 'letter1' {'above' 'below'} - createMarkLookup 'letter2' {'trailing' 'lf' 'topright' 'bottomright'} - createMarkLookup 'overlay' {'overlay' 'slash'} - # mkmk and GDEF - foreach glyph [items-of glyphList] : if (glyph.anchors && [begin [local anchorKeys : Object.keys glyph.anchors] anchorKeys.length]) - then - local isMarkGlyph false - foreach key [items-of anchorKeys] : if (glyph.anchors.(key).type == 'mark') : set isMarkGlyph true + createMTSSubtable lookup_mark {'above' 'below' 'overlay' 'slash'} + createMTSSubtable lookup_mark {'trailing' 'lf' 'topright' 'bottomright'} + createMTSSubtable lookup_mkmk {'above'} + createMTSSubtable lookup_mkmk {'below'} + createMTSSubtable lookup_mkmk {'trailing' 'lf' 'topright' 'bottomright' 'overlay' 'slash'} + # GDEF + foreach glyph [items-of glyphList] : begin + set font.GDEF.glyphClassDef.(glyph.name) : if [[regex '_'].test glyph.name] 2 1 + if (glyph.anchors && [begin [local anchorKeys : Object.keys glyph.anchors] anchorKeys.length]) : begin + foreach key [items-of anchorKeys] : if (glyph.anchors.(key).type == 'mark') : begin + if [not markGlyphs.(key)] : set markGlyphs.(key) {} + markGlyphs.(key).push glyph.name + set font.GDEF.glyphClassDef.(glyph.name) 3 + + # GSUB + let : begin + local commonList {} + local languages + .DFLT_DFLT {.features commonList} + .latn_DFLT {.features commonList} + .grek_DFLT {.features commonList} + .cyrl_DFLT {.features commonList} + .kana_DFLT {.features commonList} + .hani_DFLT {.features commonList} + local features {.} + local lookups {.} + + define [lookup-single name f t] : begin + local subtable {.} + set lookups.(name) {.type 'gsub_single' .subtables {subtable}} + foreach [j : range 0 f.length] : set subtable.(f.(j)) t.(j) + define [chain-rule] : begin + local terms : {}.slice.call arguments 0 + local subtable {.match {} .apply {} .inputBegins 0 .inputEnds 0} + local foundi false + local founde false + foreach [j : range 0 terms.length] : if (!foundi && terms.(j).1) : begin + set subtable.inputBegins j + set foundi true + foreach [j : range (terms.length - 1) downtill 0] : if (!founde && terms.(j).1) : begin + set subtable.inputEnds (j + 1) + set founde true + foreach [j : range 0 terms.length] : begin + local term terms.(j) + subtable.match.push term.0 + if term.1 : begin + subtable.apply.push {.at j .lookup term.1} + return subtable + define [flatten] : begin + local ans {} + foreach [term : items-of : {}.slice.call arguments 0] : begin + if (term <@ Array) + : then : set ans : ans.concat term + : else : ans.push term + return ans + + # cvxx + foreach [name : items-of : Object.keys glyphs] : begin + if glyphs.(name).featureSelector : begin + local fs glyphs.(name).featureSelector + foreach [feature : items-of : Object.keys fs] : begin + if [not lookups.(feature)] : begin + set features.(feature) {feature} + set lookups.(feature) {.type 'gsub_single' .subtables{{.}}} + commonList.push feature + set lookups.(feature).subtables.0.(name) fs.(feature) + # ssxx + foreach [name : items-of : Object.keys para.sscompose] : begin + commonList.push name + set features.(name) para.sscompose.(name) + #ccmp + commonList.push 'ccmp' + set features.ccmp {'ccmp1' 'ccmp2'} + set lookups.ccmpSubIota {.type 'gsub_single' .subtables {{.iotaBelow 'iotaLF'}}} + set lookups.ccmpSubOgonek {.type 'gsub_single' .subtables {{.ogonekBelow 'ogonekTR'}}} + set lookups.ccmpSubIJ {.type 'gsub_single' .subtables {{ + .i 'dotlessi' + .cyrUkrainiani 'dotlessi' + .j 'dotlessj' + .cyrje 'dotlessj' + .iogonekBelow 'iogonek.dotless' + }}} + set lookups.ccmp1 + .type 'gsub_chaining' + .subtables : list + chain-rule {{'i' 'cyrUkrainiani' 'j' 'cyrje' 'iogonekBelow'} 'ccmpSubIJ'} {markGlyphs.above} + chain-rule {{'eta'}} {{'iotaBelow'} 'ccmpSubIota'} + chain-rule {{'eta'}} {markGlyphs.above} {{'iotaBelow'} 'ccmpSubIota'} + chain-rule {{'eta'}} {markGlyphs.above} {markGlyphs.above} {{'iotaBelow'} 'ccmpSubIota'} + chain-rule {{'eta'}} {markGlyphs.above} {markGlyphs.above} {markGlyphs.above} {{'iotaBelow'} 'ccmpSubIota'} + chain-rule {{'A' 'a' 'u' 'cyrA' 'cyra'}} {{'ogonekBelow'} 'ccmpSubOgonek'} + chain-rule {{'A' 'a' 'u' 'cyrA' 'cyra'}} {markGlyphs.above} {{'ogonekBelow'} 'ccmpSubOgonek'} + chain-rule {{'A' 'a' 'u' 'cyrA' 'cyra'}} {markGlyphs.above} {markGlyphs.above} {{'ogonekBelow'} 'ccmpSubOgonek'} + chain-rule {{'A' 'a' 'u' 'cyrA' 'cyra'}} {markGlyphs.above} {markGlyphs.above} {markGlyphs.above} {{'ogonekBelow'} 'ccmpSubOgonek'} + set lookups.ccmp2 + .type 'gsub_ligature' + .subtables : list : object + psilivaria {'commaAbove' 'graveAbove'} + psilioxia {'commaAbove' 'acuteAbove'} + psiliperispomeni {'commaAbove' 'perispomeniAbove'} + dasiavaria {'revCommaAbove' 'graveAbove'} + dasiaoxia {'revCommaAbove' 'acuteAbove'} + dasiaperispomeni {'revCommaAbove' 'perispomeniAbove'} + + if (para.spacing > 0) : let : begin + #calt + local arrowStick {'hyphen' 'equal'} + local less {'less'} + local greater {'greater'} + lookup-single 'arrowStickFR' {'hyphen' 'equal'} {'lighy.fr' 'ligeq.fr'} + lookup-single 'arrowStickLF' {'hyphen' 'equal'} {'lighy.lf' 'ligeq.lf'} + lookup-single 'arrowStickFR1' {'hyphen' 'equal'} {'lighy.fr1' 'ligeq.fr1'} + lookup-single 'arrowStickL1F' {'hyphen' 'equal'} {'lighy.l1f' 'ligeq.l1f'} + lookup-single 'arrowStickCR' {'hyphen' 'equal'} {'lighy.cr' 'ligeq.cr'} + lookup-single 'arrowStickLC' {'hyphen' 'equal'} {'lighy.lc' 'ligeq.lc'} + lookup-single 'arrowStickLXC' {'hyphen' 'equal'} {'lighy.lxc' 'ligeq.lxc'} + lookup-single 'arrowStickCF' {'hyphen' 'equal'} {'lighy.cf' 'ligeq.cf'} + lookup-single 'arrowStickFC' {'hyphen' 'equal'} {'lighy.fc' 'ligeq.fc'} + lookup-single 'arrowStickJF' {'hyphen' 'equal'} {'lighy.jf' 'ligeq.jf'} + lookup-single 'arrowStickFJ' {'hyphen' 'equal'} {'lighy.fj' 'ligeq.fj'} + lookup-single 'arrowStickJ1F' {'hyphen' 'equal'} {'lighy.j1f' 'ligeq.j1f'} + lookup-single 'arrowStickFJ1' {'hyphen' 'equal'} {'lighy.fj1' 'ligeq.fj1'} + lookup-single 'arrowStickJR' {'hyphen' 'equal'} {'lighy.jr' 'ligeq.jr'} + lookup-single 'arrowStickLJ' {'hyphen' 'equal'} {'lighy.lj' 'ligeq.lj'} + lookup-single 'arrowStickLR' {'hyphen' 'equal'} {'lighy.lr' 'ligeq.lr'} - if isMarkGlyph - then - font.features.mkmk.marks.push : 'markClass ' + glyph.name + ' ' + [buildAnchorDescription glyph '' 'x' 'y' 'mkmk'] - font.features.mkmk.bases.push : 'pos mark ' + glyph.name + ' ' + [buildAnchorDescription glyph 'mark' 'mbx' 'mby' 'mkmk'] - foreach key [items-of anchorKeys] : begin - if [not font.features.markGlyphs.(key)] : set font.features.markGlyphs.(key) {} - font.features.markGlyphs.(key).push glyph.name - font.features.gdef.mark.push glyph.name - else : if [[regex '_'].test glyph.name] [font.features.gdef.ligature.push glyph.name] [font.features.gdef.simple.push glyph.name] - else : if [[regex '_'].test glyph.name] [font.features.gdef.ligature.push glyph.name] [font.features.gdef.simple.push glyph.name] + lookup-single 'lessShift1' {'less'} {'ligless.shift1'} + lookup-single 'greaterShift1' {'greater'} {'liggreater.shift1'} + lookup-single 'lessShiftN1' {'less'} {'ligless.shiftN1'} + lookup-single 'greaterShiftN1' {'greater'} {'liggreater.shiftN1'} + lookup-single 'arrowExclamHTMLComment' {'exclam'} {'ligexclam.htmlcommentstart'} + + commonList.push 'calt' + set features.calt {'caltArrow1'} + set lookups.caltArrow1 + .type 'gsub_chaining' + .subtables : list + chain-rule {less} {arrowStick 'arrowStickLC'} {arrowStick 'arrowStickCR'} {greater} + chain-rule {less} {arrowStick 'arrowStickLR'} {greater} # <->, <=> + chain-rule {less} {arrowStick 'arrowStickLJ'} {less} # <-<, <=< + chain-rule {less} {arrowStick 'arrowStickLC'} {arrowStick 'arrowStickCF'} # <--, <== + chain-rule {less} {less 'lessShift1'} {arrowStick 'arrowStickL1F'} # <<-, <<= + chain-rule {less} {{'hyphen'} 'arrowStickLF'} # <- + chain-rule {less} {{'exclam'} 'arrowExclamHTMLComment'} {{'hyphen'} 'arrowStickLXC'} {{'hyphen'} 'arrowStickCF'} # , ==> + chain-rule {arrowStick 'arrowStickFR1'} {greater 'greaterShift1'} {greater} # ->>, =>> + chain-rule {arrowStick 'arrowStickFR'} {greater} # ->, => + chain-rule {arrowStick 'arrowStickFJ1'} {less 'lessShiftN1'} {less} # -<<, =<< + chain-rule {arrowStick 'arrowStickFJ'} {less} # -<, =< + + #opbd + local fwclose {'fwlcloseDoubleQuote' 'fwlcloseSingleQuote' 'dwlcjkSingleQuoteRight' 'dwlcjkDoubleQuoteRight' 'dwlparenRight'} + local hwclose {'closeDoubleQuote' 'closeSingleQuote' 'cjkSingleQuoteRight' 'cjkDoubleQuoteRight' 'parenRight'} + local fwopen {'fwropenDoubleQuote' 'fwropenSingleQuote' 'dwrcjkSingleQuoteLeft' 'dwrcjkDoubleQuoteLeft' 'dwrparenLeft'} + local hwopen {'openDoubleQuote' 'openSingleQuote' 'cjkSingleQuoteLeft' 'cjkDoubleQuoteLeft' 'parenLeft'} + local fwquoteopen {'fwropenDoubleQuote' 'fwropenSingleQuote'} + local hwquoteopen {'openDoubleQuote' 'openSingleQuote'} + local fwtrail {'dwlperiod' 'dwlcomma' 'dwlcjkperiod' 'dwlcjkcomma'} + local hwtrail {'period' 'comma' 'cjkperiod' 'cjkcomma'} + local fwmid {'dwccolon' 'dwcsemicolon'} + local hwmid {'colon' 'semicolon'} + + lookup-single 'closefw' [flatten fwopen fwclose] [flatten hwopen hwclose] + commonList.push 'opbd' + set features.opbd {'opbd1'} + set lookups.opbd1 + .type 'gsub_chaining' + .subtables : list + chain-rule {[flatten fwtrail hwtrail fwopen hwopen fwmid hwmid]} {fwopen 'closefw'} + chain-rule {fwclose 'closefw'} {[flatten fwtrail hwtrail fwclose hwclose fwopen hwopen fwmid hwmid]} + + #localized SRB + local srbSubtable null + if para.isItalic + : then : set srbSubtable : object + cyrbe 'cyrbe.serbian' + cyrghe 'cyrghe.serbian' + cyrde 'cyrde.serbian' + cyrpe 'cyrpe.serbian' + cyrte 'cyrte.serbian' + : else : set srbSubtable : object + cyrbe 'cyrbe.serbian' + + set lookups.locl_srb {.type 'gsub_single' .subtables {srbSubtable}} + set features.locl_srb {'locl_srb'} + set languages.'cyrl_SRB ' {.features [{'locl_srb'}.concat commonList]} + + set font.GSUB {.languages languages .features features .lookups lookups} progress 'Features' \ No newline at end of file diff --git a/onegroup.mk b/onegroup.mk index 2659eb5..2f648f8 100644 --- a/onegroup.mk +++ b/onegroup.mk @@ -32,12 +32,9 @@ OBLIQUE = $(OBJDIR)/$(PREFIX)-thinoblique.ttf $(OBJDIR)/$(PREFIX)-extralightobli TARGETS = $(UPRIGHT) $(ITALIC) $(OBLIQUE) MAPS = $(if $(NOCHARMAP),,$(OBJDIR)/$(PREFIX)-regular.charmap) -FEASRC = features/common.fea features/ligation.fea features/uprightonly.fea features/italiconly.fea - FDTS = $(subst .ttf,.fdt,$(subst $(OBJDIR)/,$(OBJDIR)/.pass0-,$(TARGETS))) SVG0 = $(subst .ttf,.svg,$(subst $(OBJDIR)/,$(OBJDIR)/.pass0-,$(TARGETS))) -FEATURE = $(subst .ttf,.fea,$(subst $(OBJDIR)/,$(OBJDIR)/.pass0-,$(TARGETS))) PASS1 = $(subst $(OBJDIR)/,$(OBJDIR)/.pass0-,$(TARGETS)) PASS1 = $(subst $(OBJDIR)/,$(OBJDIR)/.pass1-,$(TARGETS)) PASS2 = $(subst $(OBJDIR)/,$(OBJDIR)/.pass2-,$(TARGETS)) @@ -48,64 +45,62 @@ fonts : $(DISTTARGETS) svgs : $(SVG0) # Pass 0 : file construction -OUTPUTS = --meta $@ --feature $(subst .fdt,.fea,$@) --svg $(subst .fdt,.svg,$@) +OUTPUTS = --meta $@ --svg $(subst .fdt,.svg,$@) OUTPUT_CM = $(if $(NOCHARMAP),,--charmap $(subst .fdt,.charmap,$(subst $(OBJDIR)/.pass0-,$(OBJDIR)/,$@))) -$(OBJDIR)/.pass0-$(PREFIX)-thin.fdt : $(SCRIPTS) $(FEASRC) | $(OBJDIR) $(DISTDIR) +$(OBJDIR)/.pass0-$(PREFIX)-thin.fdt : $(SCRIPTS) | $(OBJDIR) $(DISTDIR) $(NODE_FDT) generator iosevka $(STYLE_COMMON) w-thin s-upright $(STYLE_UPRIGHT) $(STYLE_SUFFIX) $(OUTPUTS) -$(OBJDIR)/.pass0-$(PREFIX)-extralight.fdt : $(SCRIPTS) $(FEASRC) | $(OBJDIR) $(DISTDIR) +$(OBJDIR)/.pass0-$(PREFIX)-extralight.fdt : $(SCRIPTS) | $(OBJDIR) $(DISTDIR) $(NODE_FDT) generator iosevka $(STYLE_COMMON) w-extralight s-upright $(STYLE_UPRIGHT) $(STYLE_SUFFIX) $(OUTPUTS) -$(OBJDIR)/.pass0-$(PREFIX)-light.fdt : $(SCRIPTS) $(FEASRC) | $(OBJDIR) $(DISTDIR) +$(OBJDIR)/.pass0-$(PREFIX)-light.fdt : $(SCRIPTS) | $(OBJDIR) $(DISTDIR) $(NODE_FDT) generator iosevka $(STYLE_COMMON) w-light s-upright $(STYLE_UPRIGHT) $(STYLE_SUFFIX) $(OUTPUTS) -$(OBJDIR)/.pass0-$(PREFIX)-regular.fdt : $(SCRIPTS) $(FEASRC) | $(OBJDIR) $(DISTDIR) +$(OBJDIR)/.pass0-$(PREFIX)-regular.fdt : $(SCRIPTS) | $(OBJDIR) $(DISTDIR) $(NODE_FDT) generator iosevka $(STYLE_COMMON) w-book s-upright $(STYLE_UPRIGHT) $(STYLE_SUFFIX) $(OUTPUTS) $(OUTPUT_CM) -$(OBJDIR)/.pass0-$(PREFIX)-medium.fdt : $(SCRIPTS) $(FEASRC) | $(OBJDIR) $(DISTDIR) +$(OBJDIR)/.pass0-$(PREFIX)-medium.fdt : $(SCRIPTS) | $(OBJDIR) $(DISTDIR) $(NODE_FDT) generator iosevka $(STYLE_COMMON) w-medium s-upright $(STYLE_UPRIGHT) $(STYLE_SUFFIX) $(OUTPUTS) -$(OBJDIR)/.pass0-$(PREFIX)-bold.fdt : $(SCRIPTS) $(FEASRC) | $(OBJDIR) $(DISTDIR) +$(OBJDIR)/.pass0-$(PREFIX)-bold.fdt : $(SCRIPTS) | $(OBJDIR) $(DISTDIR) $(NODE_FDT) generator iosevka $(STYLE_COMMON) w-bold s-upright $(STYLE_UPRIGHT) $(STYLE_SUFFIX) $(OUTPUTS) -$(OBJDIR)/.pass0-$(PREFIX)-heavy.fdt : $(SCRIPTS) $(FEASRC) | $(OBJDIR) $(DISTDIR) +$(OBJDIR)/.pass0-$(PREFIX)-heavy.fdt : $(SCRIPTS) | $(OBJDIR) $(DISTDIR) $(NODE_FDT) generator iosevka $(STYLE_COMMON) w-heavy s-upright $(STYLE_UPRIGHT) $(STYLE_SUFFIX) $(OUTPUTS) -$(OBJDIR)/.pass0-$(PREFIX)-thinitalic.fdt : $(SCRIPTS) $(FEASRC) | $(OBJDIR) $(DISTDIR) +$(OBJDIR)/.pass0-$(PREFIX)-thinitalic.fdt : $(SCRIPTS) | $(OBJDIR) $(DISTDIR) $(NODE_FDT) generator iosevka $(STYLE_COMMON) w-thin s-italic $(STYLE_ITALIC) $(STYLE_SUFFIX) $(OUTPUTS) --uprightify 1 -$(OBJDIR)/.pass0-$(PREFIX)-extralightitalic.fdt : $(SCRIPTS) $(FEASRC) | $(OBJDIR) $(DISTDIR) +$(OBJDIR)/.pass0-$(PREFIX)-extralightitalic.fdt : $(SCRIPTS) | $(OBJDIR) $(DISTDIR) $(NODE_FDT) generator iosevka $(STYLE_COMMON) w-extralight s-italic $(STYLE_ITALIC) $(STYLE_SUFFIX) $(OUTPUTS) --uprightify 1 -$(OBJDIR)/.pass0-$(PREFIX)-lightitalic.fdt : $(SCRIPTS) $(FEASRC) | $(OBJDIR) $(DISTDIR) +$(OBJDIR)/.pass0-$(PREFIX)-lightitalic.fdt : $(SCRIPTS) | $(OBJDIR) $(DISTDIR) $(NODE_FDT) generator iosevka $(STYLE_COMMON) w-light s-italic $(STYLE_ITALIC) $(STYLE_SUFFIX) $(OUTPUTS) --uprightify 1 -$(OBJDIR)/.pass0-$(PREFIX)-italic.fdt : $(SCRIPTS) $(FEASRC) | $(OBJDIR) $(DISTDIR) +$(OBJDIR)/.pass0-$(PREFIX)-italic.fdt : $(SCRIPTS) | $(OBJDIR) $(DISTDIR) $(NODE_FDT) generator iosevka $(STYLE_COMMON) w-book s-italic $(STYLE_ITALIC) $(STYLE_SUFFIX) $(OUTPUTS) --uprightify 1 -$(OBJDIR)/.pass0-$(PREFIX)-mediumitalic.fdt : $(SCRIPTS) $(FEASRC) | $(OBJDIR) $(DISTDIR) +$(OBJDIR)/.pass0-$(PREFIX)-mediumitalic.fdt : $(SCRIPTS) | $(OBJDIR) $(DISTDIR) $(NODE_FDT) generator iosevka $(STYLE_COMMON) w-medium s-italic $(STYLE_ITALIC) $(STYLE_SUFFIX) $(OUTPUTS) --uprightify 1 -$(OBJDIR)/.pass0-$(PREFIX)-bolditalic.fdt : $(SCRIPTS) $(FEASRC) | $(OBJDIR) $(DISTDIR) +$(OBJDIR)/.pass0-$(PREFIX)-bolditalic.fdt : $(SCRIPTS) | $(OBJDIR) $(DISTDIR) $(NODE_FDT) generator iosevka $(STYLE_COMMON) w-bold s-italic $(STYLE_ITALIC) $(STYLE_SUFFIX) $(OUTPUTS) --uprightify 1 -$(OBJDIR)/.pass0-$(PREFIX)-heavyitalic.fdt : $(SCRIPTS) $(FEASRC) | $(OBJDIR) $(DISTDIR) +$(OBJDIR)/.pass0-$(PREFIX)-heavyitalic.fdt : $(SCRIPTS) | $(OBJDIR) $(DISTDIR) $(NODE_FDT) generator iosevka $(STYLE_COMMON) w-heavy s-italic $(STYLE_ITALIC) $(STYLE_SUFFIX) $(OUTPUTS) --uprightify 1 -$(OBJDIR)/.pass0-$(PREFIX)-thinoblique.fdt : $(SCRIPTS) $(FEASRC) | $(OBJDIR) $(DISTDIR) +$(OBJDIR)/.pass0-$(PREFIX)-thinoblique.fdt : $(SCRIPTS) | $(OBJDIR) $(DISTDIR) $(NODE_FDT) generator iosevka $(STYLE_COMMON) w-thin s-oblique $(STYLE_UPRIGHT) $(STYLE_SUFFIX) $(OUTPUTS) --uprightify 1 -$(OBJDIR)/.pass0-$(PREFIX)-extralightoblique.fdt : $(SCRIPTS) $(FEASRC) | $(OBJDIR) $(DISTDIR) +$(OBJDIR)/.pass0-$(PREFIX)-extralightoblique.fdt : $(SCRIPTS) | $(OBJDIR) $(DISTDIR) $(NODE_FDT) generator iosevka $(STYLE_COMMON) w-extralight s-oblique $(STYLE_UPRIGHT) $(STYLE_SUFFIX) $(OUTPUTS) --uprightify 1 -$(OBJDIR)/.pass0-$(PREFIX)-lightoblique.fdt : $(SCRIPTS) $(FEASRC) | $(OBJDIR) $(DISTDIR) +$(OBJDIR)/.pass0-$(PREFIX)-lightoblique.fdt : $(SCRIPTS) | $(OBJDIR) $(DISTDIR) $(NODE_FDT) generator iosevka $(STYLE_COMMON) w-light s-oblique $(STYLE_UPRIGHT) $(STYLE_SUFFIX) $(OUTPUTS) --uprightify 1 -$(OBJDIR)/.pass0-$(PREFIX)-oblique.fdt : $(SCRIPTS) $(FEASRC) | $(OBJDIR) $(DISTDIR) +$(OBJDIR)/.pass0-$(PREFIX)-oblique.fdt : $(SCRIPTS) | $(OBJDIR) $(DISTDIR) $(NODE_FDT) generator iosevka $(STYLE_COMMON) w-book s-oblique $(STYLE_UPRIGHT) $(STYLE_SUFFIX) $(OUTPUTS) --uprightify 1 -$(OBJDIR)/.pass0-$(PREFIX)-mediumoblique.fdt : $(SCRIPTS) $(FEASRC) | $(OBJDIR) $(DISTDIR) +$(OBJDIR)/.pass0-$(PREFIX)-mediumoblique.fdt : $(SCRIPTS) | $(OBJDIR) $(DISTDIR) $(NODE_FDT) generator iosevka $(STYLE_COMMON) w-medium s-oblique $(STYLE_UPRIGHT) $(STYLE_SUFFIX) $(OUTPUTS) --uprightify 1 -$(OBJDIR)/.pass0-$(PREFIX)-boldoblique.fdt : $(SCRIPTS) $(FEASRC) | $(OBJDIR) $(DISTDIR) +$(OBJDIR)/.pass0-$(PREFIX)-boldoblique.fdt : $(SCRIPTS) | $(OBJDIR) $(DISTDIR) $(NODE_FDT) generator iosevka $(STYLE_COMMON) w-bold s-oblique $(STYLE_UPRIGHT) $(STYLE_SUFFIX) $(OUTPUTS) --uprightify 1 -$(OBJDIR)/.pass0-$(PREFIX)-heavyoblique.fdt : $(SCRIPTS) $(FEASRC) | $(OBJDIR) $(DISTDIR) +$(OBJDIR)/.pass0-$(PREFIX)-heavyoblique.fdt : $(SCRIPTS) | $(OBJDIR) $(DISTDIR) $(NODE_FDT) generator iosevka $(STYLE_COMMON) w-heavy s-oblique $(STYLE_UPRIGHT) $(STYLE_SUFFIX) $(OUTPUTS) --uprightify 1 $(SVG0) : $(OBJDIR)/.pass0-%.svg : $(OBJDIR)/.pass0-%.fdt $(PASS) -$(FEATURE) : $(OBJDIR)/.pass0-%.fea : $(OBJDIR)/.pass0-%.fdt - $(PASS) $(MAPS) : $(OBJDIR)/%.charmap : $(OBJDIR)/.pass0-%.fdt $(PASS) HINT = ttfautohint --increase-x-height=0 # Pass 1 : Outline cleanup and merge features -$(PASS1) : $(OBJDIR)/.pass1-%.ttf : pass1-cleanup.py $(OBJDIR)/.pass0-%.svg $(OBJDIR)/.pass0-%.fea +$(PASS1) : $(OBJDIR)/.pass1-%.ttf : pass1-cleanup.py $(OBJDIR)/.pass0-%.svg @fontforge -quiet -script $^ $@.a.ttf $(if $(findstring italic,$@),10,$(if $(findstring oblique,$@),10,0)) $(FAST) $(SUPPRESS_ERRORS) @$(HINT) $@.a.ttf $@ @-rm $@.a.ttf diff --git a/pass1-cleanup.py b/pass1-cleanup.py index 0f87709..46638a2 100644 --- a/pass1-cleanup.py +++ b/pass1-cleanup.py @@ -5,7 +5,6 @@ import sys source = sys.argv[1] font = fontforge.open(source) -font.mergeFeature(sys.argv[2]) font.selection.all() # Replace accented characters into references font.selection.select(("ranges", "unicode", None), 0x1FCD, 0x1FCF, 0x1FDD, 0x1FDF) @@ -40,7 +39,7 @@ font.simplify(0.05, ("smoothcurves", "choosehv"), 0.1) #font.em = 2000 font.selection.all() font.layers["Fore"].is_quadratic = True -font.transform(psMat.skew(float(sys.argv[4]) / 180 * math.pi)) +font.transform(psMat.skew(float(sys.argv[3]) / 180 * math.pi)) font.em = 1000 font.selection.all() @@ -52,4 +51,4 @@ font.removeOverlap() font.canonicalContours() font.canonicalStart() -font.generate(sys.argv[3], flags = ("opentype")) \ No newline at end of file +font.generate(sys.argv[2], flags = ("opentype")) \ No newline at end of file diff --git a/pass2-finalize.js b/pass2-finalize.js index 2cbd2cf..ec6c16e 100644 --- a/pass2-finalize.js +++ b/pass2-finalize.js @@ -18,8 +18,8 @@ process.stdin.on('end', function () { ttf.cvt_ = glyfs.cvt_; ttf.maxp = glyfs.maxp; ttf.gasp = glyfs.gasp; - ttf.GDEF = glyfs.GDEF; - ttf.GSUB = glyfs.GSUB; - ttf.GPOS = glyfs.GPOS; + //ttf.GDEF = glyfs.GDEF; + //ttf.GSUB = glyfs.GSUB; + //ttf.GPOS = glyfs.GPOS; process.stdout.write(JSON.stringify(ttf)); }); \ No newline at end of file diff --git a/testdrive/index.html b/testdrive/index.html index 7df0a01..8f54c39 100644 --- a/testdrive/index.html +++ b/testdrive/index.html @@ -201,7 +201,7 @@
-

float Fox.quick(h){!isBrown && jumpOver(doges.lazy)}

+

float Fox.quick(h){!isBrown && jumpO̶̸ver(dogeś̠̣.lazy)}

{{item}}

define samples : object