Files
Iosevka/meta/features.ptl
T

245 lines
8.6 KiB
Plaintext

import 'topsort' as topsort
import '../support/glyph' as Glyph
import '../support/transform' as Transform
import [progLigNameMap buildLigations] from './feature/ligation'
import './feature/opbd' as buildOPBD
import './feature/ccmp' as buildCCMP
import [BuildCompatLigatures] from './feature/compat-ligature'
define GDEF_SIMPLE 1
define GDEF_LIGATURE 2
define GDEF_MARK 3
define-operator "~>" 880 'right' : syntax-rules
`(@l ~> @r) `{.left @l .right @r}
# GSUB
define [buildGSUB para glyphs glyphList markGlyphs] : 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 {.}
local lookupOrder {}
# Chaining lookup builder
define [lookup-single name f t] : begin
local subtable {.}
foreach [j : range 0 f.length] : set subtable.(f.(j)) t.(j)
set lookups.(name) {.type 'gsub_single' .subtables {subtable}}
define [getsublookup left right] : piecewise
[not right] null
([typeof right] === "string") right
(right <@ Function) : getsublookup left [right left]
true : begin
local found null
foreach [{name lookup} : pairs-of lookups] : match lookup
{.type "gsub_single" .subtables {st}} : begin
local check true
foreach [j : range 0 left.length] : if (st.(left.(j)) !== right.(j)) : set check false
if check : set found name
if found : return found
local name "_lookup_\([Object.keys lookups].length)"
lookup-single name left right
return name
define [chain-rule] : begin
local terms : [{}.slice.call arguments 0].map (x -> [if x.left x (x ~> null)])
local subtable {.match {} .apply {} .inputBegins 0 .inputEnds 0}
local foundi false
local founde false
foreach [j : range 0 terms.length] : if (!foundi && terms.(j).right) : begin
set subtable.inputBegins j
set foundi true
foreach [j : range (terms.length - 1) downtill 0] : if (!founde && terms.(j).right) : begin
set subtable.inputEnds (j + 1)
set founde true
foreach [j : range 0 terms.length] : begin
local term terms.(j)
subtable.match.push term.left
local lutn : getsublookup term.left term.right
if lutn : subtable.apply.push {.at j .lookup lutn}
return subtable
# hwid-fwid, lnum-onum
define [MakePairFrature tag1 tag2] : begin
local mapTag2 {.}
local mapTag1 {.}
define reHidden : regex "^\\."
define reTag1 : new RegExp ("\\." + tag1 + "$")
foreach [glyph : items-of glyphList] : begin
if ([reTag1.test glyph.name] && ![reHidden.test glyph.name]) : do
local gnTag2 : glyph.name.replace reTag1 ('.' + tag2)
if (glyphs.(gnTag2)) : begin
set mapTag2.(glyph.name) gnTag2
set mapTag1.(gnTag2) glyph.name
set lookups.(tag2) {.type 'gsub_single' .subtables {mapTag2}}
set lookups.(tag1) {.type 'gsub_single' .subtables {mapTag1}}
set features.(tag2) {tag2}
set features.(tag1) {tag1}
commonList.push tag2 tag1
MakePairFrature 'hwid' 'fwid'
MakePairFrature 'lnum' 'onum'
# CCMP
buildCCMP chain-rule markGlyphs commonList features lookups
# Ligation
if para.enableLigation : do
define plm : progLigNameMap
set plm.calt : para.customLigSet || plm.(para.defLigSet) || plm.calt
buildLigations chain-rule lookupOrder commonList features lookups plm glyphs
# CVxx/SSxx
if para.enableCvSs : begin
# cvxx
foreach [glyph : items-of glyphList] : if glyph.featureSelector : begin
local fs glyph.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.(glyph.name) fs.(feature)
# ssxx
foreach [{name composition} : pairs-of para.variants] : begin
if (name.length === 4 && composition.__isComposite && [name.slice 0 2] === 'ss') : begin
commonList.push name
local tags {.}
foreach [{ch tag} : pairs-of composition.__cvmap] : set tags.(tag) true
set features.(name) : [Object.keys tags].filter (tag => tags.(tag))
# locl, SRB
local srbSubtable null
if para.isItalic
: then : set srbSubtable : object
cyrbe 'cyrbe.SRB'
cyrghe 'cyrghe.SRB'
cyrde 'cyrde.SRB'
cyrpe 'cyrpe.SRB'
cyrte 'cyrte.SRB'
: else : set srbSubtable : object
cyrbe 'cyrbe.SRB'
set lookups.locl_srb {.type 'gsub_single' .subtables {srbSubtable}}
set features.locl_srb {'locl_srb'}
# locl, BGR
local bgrSubtable : object
cyrve 'cyrve.BGR'
cyrghe 'cyrghe.italic'
cyrde 'g'
cyrzhe 'cyrzhe.BGR'
cyrze 'cyrze.BGR'
cyri 'u'
cyribreve 'ubreve'
cyrka 'k'
cyrEl 'Lambda'
cyrel 'turnv'
cyrpe 'n'
cyrte 'm'
cyrsha 'cyrsha.italic'
cyrshcha 'cyrshcha.italic'
cyryu 'cyryu.BGR'
cyrtse 'cyrtse.italic'
set lookups.locl_bgr {.type 'gsub_single' .subtables {bgrSubtable}}
set features.locl_bgr {'locl_bgr'}
set languages.'cyrl_SRB ' {.features [{'locl_srb'}.concat commonList]}
set languages.'cyrl_MKD ' {.features [{'locl_srb'}.concat commonList]}
set languages.'cyrl_BGR ' {.features [{'locl_bgr'}.concat commonList]}
return {.languages languages .features features .lookups lookups .lookupOrder [topsort lookupOrder]}
# GPOS
define [buildGPOS para glyphs glyphList markGlyphs] : begin
# 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 [createMTLookup lookupType 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
local anchorKeys : Object.keys glyph.anchors
local hasAnchor false
foreach [key : items-of anchorKeys] : if th.(key) : set hasAnchor true
if hasAnchor : begin
local isMarkGlyph false
local markKey nothing
foreach key [items-of anchorKeys] : if (glyph.anchors.(key).type == 'mark') : begin
set isMarkGlyph true
set markKey key
if isMarkGlyph
: then : begin
set subtable.marks.(glyph.name) : object
class markKey
x glyph.anchors.(markKey).x
y glyph.anchors.(markKey).y
if (lookupType == 'gpos_mark_to_mark'): begin
local r : createBaseInfo glyph th 'mbx' 'mby'
if r : set subtable.bases.(glyph.name) r
: else : if (lookupType == 'gpos_mark_to_base') : begin
local r : createBaseInfo glyph th 'x' 'y'
if r : set subtable.bases.(glyph.name) r
return {.type lookupType .subtables {subtable}}
local lookupSet {.}
local markLookupNames {}
local mkmkLookupNames {}
foreach [marktag : items-of {'above' 'below' 'overlay' 'slash' 'topright' 'bottomright' 'trailing' 'lf'}] : begin
set lookupSet.('lookup_mark_' + marktag) : createMTLookup 'gpos_mark_to_base' {marktag}
set lookupSet.('lookup_mkmk_' + marktag) : createMTLookup 'gpos_mark_to_mark' {marktag}
markLookupNames.push ('lookup_mark_' + marktag)
mkmkLookupNames.push ('lookup_mkmk_' + marktag)
return : object
languages
.DFLT_DFLT {.features {'mark0', 'mkmk0'}}
.latn_DFLT {.features {'mark0', 'mkmk0'}}
.grek_DFLT {.features {'mark0', 'mkmk0'}}
.cyrl_DFLT {.features {'mark0', 'mkmk0'}}
features
.mark0 markLookupNames
.mkmk0 mkmkLookupNames
lookups lookupSet
# GDEF
define [buildGDEF para glyphs glyphList markGlyphs] : begin
local GDEF {.glyphClassDef {.}}
foreach glyph [items-of glyphList] : begin
set GDEF.glyphClassDef.(glyph.name) : if [[regex '_'].test glyph.name] GDEF_LIGATURE GDEF_SIMPLE
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
markGlyphs.all.push glyph.name
set GDEF.glyphClassDef.(glyph.name) GDEF_MARK
return GDEF
export : define [apply para glyphs glyphList unicodeGlyphs] : begin
local markGlyphs {.all {} }
local GPOS : buildGPOS para glyphs glyphList markGlyphs
local GDEF : buildGDEF para glyphs glyphList markGlyphs
local GSUB : buildGSUB para glyphs glyphList markGlyphs
# Build compatibility ligatures
if (para.spacing > 0 && para.compLig) : begin
BuildCompatLigatures glyphs glyphList unicodeGlyphs GSUB GDEF para.compLig
return [object GSUB GPOS GDEF]