Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 10dd25fd26 | |||
| 135f6eb156 | |||
| 4499ba4809 | |||
| fff435748f | |||
| eec76d8792 | |||
| 7a86cd065f | |||
| 834a086e09 | |||
| 298723b87e | |||
| 0956c0e569 | |||
| 30ef51ace3 | |||
| 8aa2677ffc | |||
| 5c25311fdf | |||
| a55ef07837 | |||
| 09bbb2bb76 | |||
| 4ff7dbde28 | |||
| 0d7089f840 | |||
| 8a32259fdc | |||
| ee481cc744 | |||
| 196e13856c | |||
| 2029e07965 | |||
| 4955c58098 | |||
| c63a5b0abb | |||
| 8f7db7bc4c | |||
| 3813319b42 | |||
| f2a61c74ad | |||
| 1fce61fe50 | |||
| 1028c96291 | |||
| 043c160546 | |||
| 445828c8bf | |||
| 66fd3f94a1 | |||
| 9bf5f6197c | |||
| bd48389313 |
@@ -66,6 +66,33 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Kilua99",
|
||||
"name": "kilua99",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/44760686?v=4",
|
||||
"profile": "https://github.com/Kilua99",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "GlorifiedBicycle",
|
||||
"name": "Reland Boyle",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/71753585?v=4",
|
||||
"profile": "https://github.com/GlorifiedBicycle",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "killua99",
|
||||
"name": "Luigi",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/457822?v=4",
|
||||
"profile": "http://killua.me/",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
es6: true,
|
||||
node: true
|
||||
node: true,
|
||||
},
|
||||
extends: 'eslint:recommended',
|
||||
extends: ['eslint:recommended', 'prettier'],
|
||||
parserOptions: {
|
||||
sourceType: 'module'
|
||||
sourceType: 'module',
|
||||
},
|
||||
rules: {
|
||||
indent: ['error', 2],
|
||||
'linebreak-style': ['error', 'unix'],
|
||||
quotes: ['error', 'single'],
|
||||
semi: ['error', 'always'],
|
||||
'no-console': 'off'
|
||||
}
|
||||
};
|
||||
'no-console': 'off',
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
build
|
||||
node_modules
|
||||
.idea
|
||||
.vscode/launch.json
|
||||
.vscode
|
||||
.DS_Store
|
||||
pnpm-lock.yaml
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"semi": true,
|
||||
"singleQuote": true
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"arrowParens": "avoid"
|
||||
}
|
||||
|
||||
@@ -10,6 +10,10 @@ those found in the popular [Fira Code](https://github.com/tonsky/FiraCode) font.
|
||||
These ligatures were custom created using [Glyphs](https://glyphsapp.com/).
|
||||
There are even italic versions of the ligatures.
|
||||
|
||||
## 🎉 What's New in Version 2.5
|
||||
|
||||
<img src="./images/new-ligatures-2.5.png"/>
|
||||
|
||||
## 🎉 What's New in Version 2
|
||||
|
||||
<img src="./images/new-ligatures.png"/>
|
||||
@@ -20,6 +24,8 @@ characters properly.
|
||||
|
||||
<img src="./images/caret-position.gif" />
|
||||
|
||||
## 👀 <a href="https://htmlpreview.github.io/?https://github.com/kiliman/operator-mono-lig/blob/master/images/preview/normal/index.html">Click here to see preview images of all ligatures</a>
|
||||
|
||||
With the awesome help from [Mark Skelton](https://github.com/mskelton), we now have the full set of ligatures for
|
||||
the following fonts. Thanks Mark, and thanks to all of you who have been patiently waiting for these ligatures to be completed.
|
||||
|
||||
@@ -54,10 +60,13 @@ Which font weight of Operator Mono do you use? Also note difference between Scre
|
||||
|
||||
- The original _Operator Mono_ font... of course.
|
||||
- Python (v2.7+)
|
||||
- **NOTE**: For Mac, the default system Python v2.7 doesn't work. Make sure you install Python 3.
|
||||
- Node.js
|
||||
- Install _fonttools_ from https://github.com/fonttools/fonttools
|
||||
- Windows/Linux: `pip install fonttools`
|
||||
- Mac: `pip3 install fonttools`
|
||||
- **NOTE**: For Windows you should use a console with administrative permissions if your Python sit under `C:\PythonX`
|
||||
- **NOTE**: For Linux in WSL/WSL2, ensure that _fonttools_ is added to PATH after install. Alternatively, consider installing via `sudo apt install fonttools`.
|
||||
- Mac: `pip3 install fonttools` (from Python 3)
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -152,17 +161,22 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<!-- markdownlint-disable -->
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/kiliman"><img src="https://avatars3.githubusercontent.com/u/47168?v=4" width="100px;" alt="Kiliman"/><br /><sub><b>Kiliman</b></sub></a><br /><a href="https://github.com/kiliman/operator-mono-lig/commits?author=kiliman" title="Code">💻</a> <a href="https://github.com/kiliman/operator-mono-lig/commits?author=kiliman" title="Documentation">📖</a> <a href="#design-kiliman" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/mskelton"><img src="https://avatars3.githubusercontent.com/u/25914066?v=4" width="100px;" alt="Mark Skelton"/><br /><sub><b>Mark Skelton</b></sub></a><br /><a href="#design-mskelton" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/drod3763"><img src="https://avatars2.githubusercontent.com/u/7785716?v=4" width="100px;" alt="Derick Rodriguez"/><br /><sub><b>Derick Rodriguez</b></sub></a><br /><a href="https://github.com/kiliman/operator-mono-lig/commits?author=drod3763" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/amitkparekh"><img src="https://avatars3.githubusercontent.com/u/7276308?v=4" width="100px;" alt="Amit Parekh"/><br /><sub><b>Amit Parekh</b></sub></a><br /><a href="https://github.com/kiliman/operator-mono-lig/commits?author=amitkparekh" title="Documentation">📖</a> <a href="#design-amitkparekh" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/CandySunPlus"><img src="https://avatars0.githubusercontent.com/u/502700?v=4" width="100px;" alt="NikSun"/><br /><sub><b>NikSun</b></sub></a><br /><a href="#design-CandySunPlus" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/Jakob6174"><img src="https://avatars3.githubusercontent.com/u/40262817?v=4" width="100px;" alt="Jakob Pearson"/><br /><sub><b>Jakob Pearson</b></sub></a><br /><a href="https://github.com/kiliman/operator-mono-lig/commits?author=Jakob6174" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/kiliman"><img src="https://avatars3.githubusercontent.com/u/47168?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kiliman</b></sub></a><br /><a href="https://github.com/kiliman/operator-mono-lig/commits?author=kiliman" title="Code">💻</a> <a href="https://github.com/kiliman/operator-mono-lig/commits?author=kiliman" title="Documentation">📖</a> <a href="#design-kiliman" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/mskelton"><img src="https://avatars3.githubusercontent.com/u/25914066?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mark Skelton</b></sub></a><br /><a href="#design-mskelton" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/drod3763"><img src="https://avatars2.githubusercontent.com/u/7785716?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Derick Rodriguez</b></sub></a><br /><a href="https://github.com/kiliman/operator-mono-lig/commits?author=drod3763" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/amitkparekh"><img src="https://avatars3.githubusercontent.com/u/7276308?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Amit Parekh</b></sub></a><br /><a href="https://github.com/kiliman/operator-mono-lig/commits?author=amitkparekh" title="Documentation">📖</a> <a href="#design-amitkparekh" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/CandySunPlus"><img src="https://avatars0.githubusercontent.com/u/502700?v=4?s=100" width="100px;" alt=""/><br /><sub><b>NikSun</b></sub></a><br /><a href="#design-CandySunPlus" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/Jakob6174"><img src="https://avatars3.githubusercontent.com/u/40262817?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jakob Pearson</b></sub></a><br /><a href="https://github.com/kiliman/operator-mono-lig/commits?author=Jakob6174" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://killua.me/"><img src="https://avatars.githubusercontent.com/u/457822?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Luigi</b></sub></a><br /><a href="https://github.com/kiliman/operator-mono-lig/commits?author=killua99" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/GlorifiedBicycle"><img src="https://avatars.githubusercontent.com/u/71753585?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Reland Boyle</b></sub></a><br /><a href="https://github.com/kiliman/operator-mono-lig/commits?author=GlorifiedBicycle" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- markdownlint-enable -->
|
||||
<!-- markdownlint-restore -->
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
|
||||
|
||||
@@ -31,4 +31,13 @@ if not exist .\ligature\%lig%\glyphs\* exit /b
|
||||
ttx -f .\original\%otf%.otf
|
||||
node index.js %otf% %flags%
|
||||
ttx -f .\build\%lig%.ttx
|
||||
rem check if "SSm" is in name since the features are slightly different
|
||||
@echo.%lig% | findstr /C:"SSm" 1>nul
|
||||
if errorlevel 1 (
|
||||
set fea=".\features\default.fea"
|
||||
) else (
|
||||
set fea=".\features\defaultSSm.fea"
|
||||
)
|
||||
fonttools feaLib -v -o ".\build\%lig%.otf" %fea% ".\build\%lig%.otf"
|
||||
|
||||
exit /b
|
||||
|
||||
@@ -16,11 +16,17 @@ build_font() {
|
||||
return
|
||||
fi
|
||||
|
||||
echo Building $1
|
||||
echo Building "$1"
|
||||
ttx -f "./original/$otf.otf"
|
||||
node index.js $otf $flags
|
||||
node index.js "$otf" "$flags"
|
||||
|
||||
ttx -f ./build/$1.ttx
|
||||
ttx -f "./build/$1.ttx"
|
||||
if [[ $lig == *"SSm"* ]]; then
|
||||
fea="./features/defaultSSm.fea"
|
||||
else
|
||||
fea="./features/default.fea"
|
||||
fi
|
||||
fonttools feaLib -v -o "./build/$1.otf" $fea "./build/$1.otf"
|
||||
}
|
||||
|
||||
flags=
|
||||
@@ -32,10 +38,10 @@ fi
|
||||
if [ -n "$1" ]
|
||||
then
|
||||
# build specified font
|
||||
build_font $1 $flags
|
||||
build_font "$1" "$flags"
|
||||
else
|
||||
# build all available fonts
|
||||
for d in ./ligature/*/ ; do
|
||||
build_font $(basename $d) $flags
|
||||
build_font "$(basename "$d")" "$flags"
|
||||
done
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
const fs = require('fs')
|
||||
|
||||
const rules = [
|
||||
'',
|
||||
`
|
||||
lookup 1 {
|
||||
sub 1 by glyph;
|
||||
} 1;`,
|
||||
`
|
||||
lookup 1_2 {
|
||||
ignore sub 1 1' 2;
|
||||
ignore sub 1' 2 2;
|
||||
sub 1.spacer 2' by glyph;
|
||||
sub 1' 2 by 1.spacer;
|
||||
} 1_2;`,
|
||||
`
|
||||
lookup 1_2_3 {
|
||||
ignore sub 1 1' 2 3;
|
||||
ignore sub 1' 2 3 3;
|
||||
sub 1.spacer 2.spacer 3' by glyph;
|
||||
sub 1.spacer 2' 3 by 2.spacer;
|
||||
sub 1' 2 3 by 1.spacer;
|
||||
} 1_2_3;`,
|
||||
`
|
||||
lookup 1_2_3_4 {
|
||||
ignore sub 1 1' 2 3 4;
|
||||
ignore sub 1' 2 3 4 4;
|
||||
sub 1.spacer 2.spacer 3.spacer 4' by glyph;
|
||||
sub 1.spacer 2.spacer 3' 4 by 3.spacer;
|
||||
sub 1.spacer 2' 3 4 by 2.spacer;
|
||||
sub 1' 2 3 4 by 1.spacer;
|
||||
} 1_2_3_4;`,
|
||||
]
|
||||
|
||||
const gencalt = ligatures => {
|
||||
let calt = 'feature calt {\n'
|
||||
const ligs = {}
|
||||
|
||||
ligatures
|
||||
.filter(l => !!l.name.match(/\.liga$/) || l.name !== l.glyph)
|
||||
.map(l => l.glyph)
|
||||
.sort((a, b) => {
|
||||
const length = b.split('_').length - a.split('_').length
|
||||
if (length !== 0) return length
|
||||
return a < b ? -1 : 1
|
||||
})
|
||||
.forEach(g => {
|
||||
g.split('.')
|
||||
.slice(0, 1)
|
||||
.forEach(l => {
|
||||
if (ligs[l]) return
|
||||
ligs[l] = true
|
||||
const c = l.split('_')
|
||||
let rule = rules[c.length]
|
||||
rule = rule
|
||||
.replace(/\d/g, m => c[parseInt(m) - 1])
|
||||
.replace(/glyph/g, g)
|
||||
calt += rule + '\n'
|
||||
})
|
||||
})
|
||||
|
||||
return calt + '\n} calt;\n'
|
||||
}
|
||||
|
||||
exports.gencalt = gencalt
|
||||
@@ -0,0 +1 @@
|
||||
calt.fea
|
||||
@@ -0,0 +1,234 @@
|
||||
##############################
|
||||
# Languagesystem definitions #
|
||||
##############################
|
||||
languagesystem DFLT dflt; # Default default
|
||||
languagesystem latn dflt; # Latin default
|
||||
languagesystem latn CAT ; # Latin Catalan
|
||||
##########
|
||||
# Prefix #
|
||||
##########
|
||||
@HexDigit = [a b c d e f A B C D E F];
|
||||
@Digit = [zero one two three four five six seven eight nine];
|
||||
@DigitAll = [zero one two three four five six seven eight nine zero.num one.num two.num three.num four.num five.num six.num seven.num eight.num nine.num zero.den one.den two.den three.den four.den five.den six.den seven.den eight.den nine.den];
|
||||
@DigitSmall = [zero.small one.small two.small three.small four.small five.small six.small seven.small eight.small nine.small];
|
||||
@DigitNumerator = [zero.num one.num two.num three four.num five.num six.num seven.num eight.num nine.num];
|
||||
@DigitDenominator = [zero.den one.den two.den three.den four.den five.den six.den seven.den eight.den nine.den];
|
||||
@DigitSuperior = [zero.sup one.sup two.sup three.sup four.sup five.sup six.sup seven.sup eight.sup nine.sup];
|
||||
@DigitInferior = [zero.inf one.inf two.inf three.inf four.inf five.inf six.inf seven.inf eight.inf nine.inf];
|
||||
#######################
|
||||
# Feature definitions #
|
||||
#######################
|
||||
feature locl {
|
||||
# GSUB feature: Localized Forms
|
||||
script latn; # Latin
|
||||
language CAT; # Catalan
|
||||
sub l' periodcentered' by ldot;
|
||||
sub L' periodcentered' by Ldot;
|
||||
} locl;
|
||||
|
||||
feature aalt useExtension {
|
||||
# GSUB feature: Access All Alternates
|
||||
feature case;
|
||||
feature dnom;
|
||||
feature numr;
|
||||
feature salt;
|
||||
feature sinf;
|
||||
feature ss01;
|
||||
feature ss03;
|
||||
feature ss04;
|
||||
feature ss05;
|
||||
feature ss07;
|
||||
feature ss08;
|
||||
feature ss09;
|
||||
feature ss10;
|
||||
feature subs;
|
||||
feature sups;
|
||||
feature smcp;
|
||||
feature c2sc;
|
||||
} aalt;
|
||||
|
||||
feature frac {
|
||||
# GSUB feature: Fractions
|
||||
lookup frac0 {
|
||||
sub @Digit slash' @Digit by fraction;
|
||||
} frac0;
|
||||
|
||||
lookup frac1 {
|
||||
ignore sub @DigitAll @DigitAll fraction';
|
||||
ignore sub fraction' @DigitAll @DigitAll;
|
||||
sub @DigitAll fraction' @DigitAll by fraction.afrc;
|
||||
} frac1;
|
||||
|
||||
lookup frac2 {
|
||||
sub @Digit' fraction.afrc by @DigitNumerator;
|
||||
sub fraction.afrc @Digit' by @DigitDenominator;
|
||||
} frac2;
|
||||
|
||||
lookup frac3 {
|
||||
sub one.num fraction.afrc two.den by onehalf;
|
||||
sub one.num fraction.afrc three.den by onethird;
|
||||
sub one.num fraction.afrc four.den by onequarter;
|
||||
sub one.num fraction.afrc five.den by onefifth;
|
||||
sub one.num fraction.afrc six.den by onesixth;
|
||||
sub one.num fraction.afrc eight.den by oneeighth;
|
||||
sub two.num fraction.afrc three.den by twothirds;
|
||||
sub two.num fraction.afrc five.den by twofifths;
|
||||
sub three.num fraction.afrc four.den by threequarters;
|
||||
sub three.num fraction.afrc five.den by threefifths;
|
||||
sub three.num fraction.afrc eight.den by threeeighths;
|
||||
sub four.num fraction.afrc five.den by fourfifths;
|
||||
sub five.num fraction.afrc six.den by fivesixths;
|
||||
sub five.num fraction.afrc eight.den by fiveeighths;
|
||||
sub seven.num fraction.afrc eight.den by seveneighths;
|
||||
} frac3;
|
||||
} frac;
|
||||
|
||||
feature numr {
|
||||
# GSUB feature: Numerators
|
||||
sub @Digit by @DigitNumerator;
|
||||
} numr;
|
||||
|
||||
feature dnom {
|
||||
# GSUB feature: Denominators
|
||||
sub @Digit by @DigitDenominator;
|
||||
} dnom;
|
||||
|
||||
feature sups {
|
||||
# GSUB feature: Superscript
|
||||
sub @Digit by @DigitSuperior;
|
||||
} sups;
|
||||
|
||||
feature subs {
|
||||
# GSUB feature: Subscript
|
||||
sub @Digit by @DigitInferior;
|
||||
} subs;
|
||||
|
||||
feature sinf {
|
||||
# GSUB feature: Scientific Inferiors
|
||||
sub @Digit by @DigitInferior;
|
||||
} sinf;
|
||||
|
||||
feature ordn {
|
||||
# Ordinals
|
||||
sub @Digit [A a]' by ordfeminine;
|
||||
sub @Digit [O o]' by ordmasculine;
|
||||
sub N o period by numero;
|
||||
} ordn;
|
||||
|
||||
feature smcp {
|
||||
# Small Caps
|
||||
sub @Digit by @DigitSmall;
|
||||
} smcp;
|
||||
|
||||
feature c2sc {
|
||||
# Capitals to Small Caps
|
||||
sub @Digit by @DigitSmall;
|
||||
} c2sc;
|
||||
|
||||
feature case {
|
||||
# GSUB feature: Case-Sensitive Forms
|
||||
sub guillemotleft by guillemotleft.cap;
|
||||
sub guillemotright by guillemotright.cap;
|
||||
sub guilsinglleft by guilsinglleft.cap;
|
||||
sub guilsinglright by guilsinglright.cap;
|
||||
sub parenleft by parenleft.cap;
|
||||
sub parenright by parenright.cap;
|
||||
sub bracketleft by bracketleft.cap;
|
||||
sub bracketright by bracketright.cap;
|
||||
sub braceleft by braceleft.cap;
|
||||
sub braceright by braceright.cap;
|
||||
} case;
|
||||
|
||||
|
||||
|
||||
include(calt.fea);
|
||||
|
||||
|
||||
|
||||
feature salt {
|
||||
# GSUB feature: Stylistic Alternates
|
||||
sub registered by registered.alt;
|
||||
sub colon by colon.alt;
|
||||
sub bullet by bullet.alt;
|
||||
sub asterisk by asterisk.alt;
|
||||
sub zero by zero.alt;
|
||||
sub underscore by underscore.alt;
|
||||
lookup salt {
|
||||
# GSUB lookup 20, type 16 (Chaining Context)
|
||||
sub @DigitAll slash' @DigitAll by fraction;
|
||||
} salt;
|
||||
} salt;
|
||||
|
||||
feature ss01 {
|
||||
featureNames {
|
||||
name "Large Registered Symbol";
|
||||
};
|
||||
sub registered by registered.alt;
|
||||
} ss01;
|
||||
|
||||
feature ss03 {
|
||||
featureNames {
|
||||
name "Raised Colon";
|
||||
};
|
||||
sub colon by colon.alt;
|
||||
} ss03;
|
||||
|
||||
feature ss04 {
|
||||
featureNames {
|
||||
name "Square Bullet";
|
||||
};
|
||||
sub bullet by bullet.alt;
|
||||
} ss04;
|
||||
|
||||
feature ss05 {
|
||||
featureNames {
|
||||
name "Six-Pointed Asterisk";
|
||||
};
|
||||
sub asterisk by asterisk.alt;
|
||||
} ss05;
|
||||
|
||||
feature ss07 {
|
||||
featureNames {
|
||||
name "Unslashed Zero";
|
||||
};
|
||||
sub zero by zero.alt;
|
||||
} ss07;
|
||||
|
||||
feature ss08 {
|
||||
featureNames {
|
||||
name "Connected Underscore";
|
||||
};
|
||||
sub underscore by underscore.alt;
|
||||
} ss08;
|
||||
|
||||
feature ss09 {
|
||||
featureNames {
|
||||
name "Fraction Bar";
|
||||
};
|
||||
sub @DigitAll slash' @DigitAll by fraction;
|
||||
} ss09;
|
||||
|
||||
feature ss10 {
|
||||
featureNames {
|
||||
name "Hexidecimal Multiply Sign";
|
||||
};
|
||||
### 0xFF
|
||||
sub [zero zero.alt] x' [@Digit @HexDigit] by multiply;
|
||||
### 800x600
|
||||
sub [@Digit zero.alt] x' [@Digit zero.alt] by multiply;
|
||||
} ss10;
|
||||
|
||||
feature rupa {
|
||||
sub R p by R_p;
|
||||
} rupa;
|
||||
|
||||
feature kern {
|
||||
# GPOS feature: Kerning
|
||||
lookup kern {
|
||||
# GPOS lookup 1, type 2 (Pair adjustment)
|
||||
pos fraction.afrc @DigitDenominator -550;
|
||||
pos @DigitNumerator fraction.afrc -550;
|
||||
} kern;
|
||||
} kern;
|
||||
|
||||
|
||||
@@ -0,0 +1,252 @@
|
||||
##############################
|
||||
# Languagesystem definitions #
|
||||
##############################
|
||||
languagesystem DFLT dflt; # Default default
|
||||
languagesystem latn dflt; # Latin default
|
||||
languagesystem latn CAT ; # Latin Catalan
|
||||
##########
|
||||
# Prefix #
|
||||
##########
|
||||
@HexDigit = [a b c d e f A B C D E F];
|
||||
@Digit = [zero one two three four five six seven eight nine];
|
||||
@DigitAll = [zero one two three four five six seven eight nine zero.num one.num two.num three.num four.num five.num six.num seven.num eight.num nine.num zero.den one.den two.den three.den four.den five.den six.den seven.den eight.den nine.den];
|
||||
@DigitSmall = [zero.small one.small two.small three.small four.small five.small six.small seven.small eight.small nine.small];
|
||||
@DigitNumerator = [zero.num one.num two.num three four.num five.num six.num seven.num eight.num nine.num];
|
||||
@DigitDenominator = [zero.den one.den two.den three.den four.den five.den six.den seven.den eight.den nine.den];
|
||||
@DigitSuperior = [zero.sup one.sup two.sup three.sup four.sup five.sup six.sup seven.sup eight.sup nine.sup];
|
||||
@DigitInferior = [zero.inf one.inf two.inf three.inf four.inf five.inf six.inf seven.inf eight.inf nine.inf];
|
||||
#######################
|
||||
# Feature definitions #
|
||||
#######################
|
||||
feature locl {
|
||||
# GSUB feature: Localized Forms
|
||||
script latn; # Latin
|
||||
language CAT; # Catalan
|
||||
sub l' periodcentered' by ldot;
|
||||
sub L' periodcentered' by Ldot;
|
||||
} locl;
|
||||
|
||||
feature aalt useExtension {
|
||||
# GSUB feature: Access All Alternates
|
||||
feature case;
|
||||
feature dnom;
|
||||
feature numr;
|
||||
feature salt;
|
||||
feature sinf;
|
||||
feature ss01;
|
||||
feature ss03;
|
||||
feature ss04;
|
||||
feature ss05;
|
||||
feature ss07;
|
||||
feature ss08;
|
||||
feature ss09;
|
||||
feature ss10;
|
||||
feature ss11;
|
||||
feature ss12;
|
||||
feature subs;
|
||||
feature sups;
|
||||
feature smcp;
|
||||
feature c2sc;
|
||||
} aalt;
|
||||
|
||||
feature frac {
|
||||
# GSUB feature: Fractions
|
||||
lookup frac0 {
|
||||
sub @Digit slash' @Digit by fraction;
|
||||
} frac0;
|
||||
|
||||
lookup frac1 {
|
||||
ignore sub @DigitAll @DigitAll fraction';
|
||||
ignore sub fraction' @DigitAll @DigitAll;
|
||||
sub @DigitAll fraction' @DigitAll by fraction.afrc;
|
||||
} frac1;
|
||||
|
||||
lookup frac2 {
|
||||
sub @Digit' fraction.afrc by @DigitNumerator;
|
||||
sub fraction.afrc @Digit' by @DigitDenominator;
|
||||
} frac2;
|
||||
|
||||
lookup frac3 {
|
||||
sub one.num fraction.afrc two.den by onehalf;
|
||||
sub one.num fraction.afrc three.den by onethird;
|
||||
sub one.num fraction.afrc four.den by onequarter;
|
||||
sub one.num fraction.afrc five.den by onefifth;
|
||||
sub one.num fraction.afrc six.den by onesixth;
|
||||
sub one.num fraction.afrc eight.den by oneeighth;
|
||||
sub two.num fraction.afrc three.den by twothirds;
|
||||
sub two.num fraction.afrc five.den by twofifths;
|
||||
sub three.num fraction.afrc four.den by threequarters;
|
||||
sub three.num fraction.afrc five.den by threefifths;
|
||||
sub three.num fraction.afrc eight.den by threeeighths;
|
||||
sub four.num fraction.afrc five.den by fourfifths;
|
||||
sub five.num fraction.afrc six.den by fivesixths;
|
||||
sub five.num fraction.afrc eight.den by fiveeighths;
|
||||
sub seven.num fraction.afrc eight.den by seveneighths;
|
||||
} frac3;
|
||||
} frac;
|
||||
|
||||
feature numr {
|
||||
# GSUB feature: Numerators
|
||||
sub @Digit by @DigitNumerator;
|
||||
} numr;
|
||||
|
||||
feature dnom {
|
||||
# GSUB feature: Denominators
|
||||
sub @Digit by @DigitDenominator;
|
||||
} dnom;
|
||||
|
||||
feature sups {
|
||||
# GSUB feature: Superscript
|
||||
sub @Digit by @DigitSuperior;
|
||||
} sups;
|
||||
|
||||
feature subs {
|
||||
# GSUB feature: Subscript
|
||||
sub @Digit by @DigitInferior;
|
||||
} subs;
|
||||
|
||||
feature sinf {
|
||||
# GSUB feature: Scientific Inferiors
|
||||
sub @Digit by @DigitInferior;
|
||||
} sinf;
|
||||
|
||||
feature ordn {
|
||||
# Ordinals
|
||||
sub @Digit [A a]' by ordfeminine;
|
||||
sub @Digit [O o]' by ordmasculine;
|
||||
sub N o period by numero;
|
||||
} ordn;
|
||||
|
||||
feature smcp {
|
||||
# Small Caps
|
||||
sub @Digit by @DigitSmall;
|
||||
} smcp;
|
||||
|
||||
feature c2sc {
|
||||
# Capitals to Small Caps
|
||||
sub @Digit by @DigitSmall;
|
||||
} c2sc;
|
||||
|
||||
feature case {
|
||||
# GSUB feature: Case-Sensitive Forms
|
||||
sub guillemotleft by guillemotleft.cap;
|
||||
sub guillemotright by guillemotright.cap;
|
||||
sub guilsinglleft by guilsinglleft.cap;
|
||||
sub guilsinglright by guilsinglright.cap;
|
||||
sub parenleft by parenleft.cap;
|
||||
sub parenright by parenright.cap;
|
||||
sub bracketleft by bracketleft.cap;
|
||||
sub bracketright by bracketright.cap;
|
||||
sub braceleft by braceleft.cap;
|
||||
sub braceright by braceright.cap;
|
||||
} case;
|
||||
|
||||
|
||||
|
||||
include(calt.fea);
|
||||
|
||||
|
||||
|
||||
feature salt {
|
||||
# GSUB feature: Stylistic Alternates
|
||||
sub registered by registered.alt;
|
||||
sub colon by colon.alt;
|
||||
sub bullet by bullet.alt;
|
||||
sub asterisk by asterisk.alt;
|
||||
sub zero by zero.alt;
|
||||
sub underscore by underscore.alt;
|
||||
lookup salt {
|
||||
# GSUB lookup 20, type 16 (Chaining Context)
|
||||
sub @DigitAll slash' @DigitAll by fraction;
|
||||
} salt;
|
||||
} salt;
|
||||
|
||||
feature ss01 {
|
||||
featureNames {
|
||||
name "Large Registered Symbol";
|
||||
};
|
||||
sub registered by registered.alt;
|
||||
} ss01;
|
||||
|
||||
feature ss03 {
|
||||
featureNames {
|
||||
name "Raised Colon";
|
||||
};
|
||||
sub colon by colon.alt;
|
||||
} ss03;
|
||||
|
||||
feature ss04 {
|
||||
featureNames {
|
||||
name "Square Bullet";
|
||||
};
|
||||
sub bullet by bullet.alt;
|
||||
} ss04;
|
||||
|
||||
feature ss05 {
|
||||
featureNames {
|
||||
name "Six-Pointed Asterisk";
|
||||
};
|
||||
sub asterisk by asterisk.alt;
|
||||
} ss05;
|
||||
|
||||
feature ss07 {
|
||||
featureNames {
|
||||
name "Unslashed Zero";
|
||||
};
|
||||
sub zero by zero.alt;
|
||||
} ss07;
|
||||
|
||||
feature ss08 {
|
||||
featureNames {
|
||||
name "Connected Underscore";
|
||||
};
|
||||
sub underscore by underscore.alt;
|
||||
} ss08;
|
||||
|
||||
feature ss09 {
|
||||
featureNames {
|
||||
name "Fraction Bar";
|
||||
};
|
||||
sub @DigitAll slash' @DigitAll by fraction;
|
||||
} ss09;
|
||||
|
||||
feature ss10 {
|
||||
featureNames {
|
||||
name "Hexidecimal Multiply Sign";
|
||||
};
|
||||
### 0xFF
|
||||
sub [zero zero.alt] x' [@Digit @HexDigit] by multiply;
|
||||
### 800x600
|
||||
sub [@Digit zero.alt] x' [@Digit zero.alt] by multiply;
|
||||
} ss10;
|
||||
|
||||
feature ss11 {
|
||||
featureNames {
|
||||
name "Equality Spaces";
|
||||
};
|
||||
sub equal_equal.liga by equal_equal.liga.ss11;
|
||||
sub equal_equal_equal.liga by equal_equal_equal.liga.ss11;
|
||||
} ss11;
|
||||
|
||||
feature ss12 {
|
||||
featureNames {
|
||||
name "Less-than/Greater-than Horizontal Bar";
|
||||
};
|
||||
sub less_equal.liga by less_equal.liga.ss12;
|
||||
sub greater_equal.liga by greater_equal.liga.ss12;
|
||||
} ss12;
|
||||
|
||||
feature rupa {
|
||||
sub R p by R_p;
|
||||
} rupa;
|
||||
|
||||
feature kern {
|
||||
# GPOS feature: Kerning
|
||||
lookup kern {
|
||||
# GPOS lookup 1, type 2 (Pair adjustment)
|
||||
pos fraction.afrc @DigitDenominator -625;
|
||||
pos @DigitNumerator fraction.afrc -625;
|
||||
} kern;
|
||||
} kern;
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
const fs = require('fs')
|
||||
const { createCanvas } = require('canvas')
|
||||
|
||||
const width = 64
|
||||
const height = 48
|
||||
const weight = 300
|
||||
|
||||
const map = {
|
||||
ampersand: '&',
|
||||
bar: '|',
|
||||
colon: ':',
|
||||
equal: '=',
|
||||
exclam: '!',
|
||||
greater: '>',
|
||||
hyphen: '-',
|
||||
less: '<',
|
||||
plus: '+',
|
||||
question: '?',
|
||||
slash: '/',
|
||||
underscore: '_',
|
||||
w: 'w',
|
||||
}
|
||||
|
||||
function generateLigaturePreview(style, filename) {
|
||||
const ligature = filename.split('.').slice(0, 1)[0]
|
||||
const chars = ligature.split('_')
|
||||
|
||||
const text = chars.reduce((t, c) => t + map[c], '')
|
||||
|
||||
const canvas = createCanvas(width, height)
|
||||
const context = canvas.getContext('2d')
|
||||
|
||||
context.fillStyle = '#000'
|
||||
context.fillRect(0, 0, width, height)
|
||||
|
||||
context.font = `${weight} ${style} 18pt "Operator Mono SSm Lig"`
|
||||
context.textAlign = 'center'
|
||||
context.fillStyle = '#fff'
|
||||
context.text = text
|
||||
context.fillText(text, 32, 32)
|
||||
|
||||
const buffer = canvas.toBuffer('image/png')
|
||||
console.log(ligature)
|
||||
fs.writeFileSync(`./images/preview/${style}/${ligature}.png`, buffer)
|
||||
|
||||
return { text, ligature, filename: `${ligature}.png` }
|
||||
}
|
||||
|
||||
function generate(style, filenames) {
|
||||
let html = `<html><head>
|
||||
<style>
|
||||
body { background-color: #000; color: #fff; font-family: sans-serif; margin: 16px;}
|
||||
a { color: #fff; text-decoration: none; padding: 4px;}
|
||||
a.active {color: #000; background-color: #fff;}
|
||||
.container { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
|
||||
.ligature { display: flex; flex-direction: column; align-items: center; margin: 8px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Operator Mono Ligatures</h1>
|
||||
<a href="https://htmlpreview.github.io/?https://github.com/kiliman/operator-mono-lig/blob/master/images/preview/normal/index.html" class="${
|
||||
style === 'normal' ? 'active' : ''
|
||||
}">Normal</a> |
|
||||
<a href="https://htmlpreview.github.io/?https://github.com/kiliman/operator-mono-lig/blob/master/images/preview/italic/index.html" class="${
|
||||
style === 'italic' ? 'active' : ''
|
||||
}">Italic</a>
|
||||
<div class="container">
|
||||
`
|
||||
|
||||
filenames.forEach(f => {
|
||||
const { ligature, filename } = generateLigaturePreview(style, f)
|
||||
html += `<div class="ligature"><img src="${filename}"/><div>${ligature}</div></div>`
|
||||
})
|
||||
|
||||
html += `</div></body></html>`
|
||||
|
||||
fs.writeFileSync(`./images/preview/${style}/index.html`, html)
|
||||
}
|
||||
|
||||
const filenames = fs
|
||||
.readdirSync('./ligature/OperatorMonoSSmLig-Book/glyphs')
|
||||
.filter(f => !!f.match(/[^\d]\.liga\.xml$/))
|
||||
|
||||
generate('normal', filenames)
|
||||
generate('italic', filenames)
|
||||
@@ -0,0 +1,36 @@
|
||||
const fs = require('fs');
|
||||
const lig = `<Glyph name="LIG" lsb="0" width="625">
|
||||
<CharString>
|
||||
endchar
|
||||
</CharString>
|
||||
<Subrs/>
|
||||
<GlobalSubrs/>
|
||||
</Glyph>`;
|
||||
|
||||
fs.readdirSync('./ligature')
|
||||
.filter((f) => !!f.match(/^OperatorMono/))
|
||||
.forEach((f) => {
|
||||
console.log(f);
|
||||
fs.readdirSync(`./ligature/${f}/glyphs`)
|
||||
.filter((g) => !!g.match(/\.liga\.xml$/))
|
||||
.forEach((g) => {
|
||||
console.log(g);
|
||||
g.split('.')
|
||||
.slice(0, 1)
|
||||
.forEach((l) => {
|
||||
l.split('_').forEach((c) => {
|
||||
const path = `./ligature/${f}/glyphs/${c}.spacer.xml`;
|
||||
const exists = fs.existsSync(path);
|
||||
console.log(path, exists);
|
||||
if (exists) return;
|
||||
|
||||
const width = !!f.match(/SSm/) ? 625 : 600;
|
||||
const spacer = lig
|
||||
.replace('LIG', `${c}.spacer`)
|
||||
.replace('625', width);
|
||||
console.log(f, c, width);
|
||||
fs.writeFileSync(path, spacer);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,313 +0,0 @@
|
||||
const xpath = require('xpath');
|
||||
const NodeType = {};
|
||||
NodeType.TEXT_NODE = 3;
|
||||
|
||||
let dom;
|
||||
let gsubDom;
|
||||
let scriptListDom;
|
||||
let featureListDom;
|
||||
let lookupListDom;
|
||||
let featureDom;
|
||||
let lookupIndex = 0;
|
||||
let chainIndex = 0;
|
||||
const substLookupMap = {};
|
||||
|
||||
const initGsubTables = (_dom, options) => {
|
||||
dom = _dom;
|
||||
|
||||
gsubDom = xpath.select('ttFont/GSUB', dom, true);
|
||||
|
||||
// look for 'calt' feature
|
||||
featureListDom = xpath.select('FeatureList', gsubDom, true);
|
||||
lookupListDom = xpath.select('LookupList', gsubDom, true);
|
||||
|
||||
if (options.italicsHack) {
|
||||
// remove all features from FeatureList
|
||||
Array.from(featureListDom.childNodes).forEach((c) => {
|
||||
featureListDom.removeChild(c);
|
||||
});
|
||||
|
||||
Array.from(xpath.select('ttFont/GSUB//FeatureIndex', dom)).forEach((c) => {
|
||||
c.parentNode.removeChild(c);
|
||||
});
|
||||
|
||||
// remove all lookups from LookupList
|
||||
Array.from(lookupListDom.childNodes).forEach((c) =>
|
||||
lookupListDom.removeChild(c)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const buildGsubTables = (_dom, ligature, options) => {
|
||||
dom = _dom;
|
||||
|
||||
if (/_/.test(ligature.glyph) === false) {
|
||||
// not a ligature, so see if glyph exists in font (as substitute)
|
||||
const glyphNode = xpath.select(
|
||||
`ttFont/GlyphOrder/GlyphID[@name="${ligature.name}"]`,
|
||||
dom,
|
||||
true
|
||||
);
|
||||
if (!glyphNode) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const glyphs = ligature.name.replace(/\.liga$/, '').split('_');
|
||||
const isSingleGlyph = glyphs.length == 1;
|
||||
|
||||
gsubDom = xpath.select('ttFont/GSUB', dom, true);
|
||||
|
||||
// look for 'calt' feature
|
||||
featureListDom = xpath.select('FeatureList', gsubDom, true);
|
||||
|
||||
let featureRecord;
|
||||
const featureTag = xpath.select(
|
||||
'FeatureRecord/FeatureTag[@value="calt"]',
|
||||
featureListDom,
|
||||
true
|
||||
);
|
||||
if (!featureTag) {
|
||||
const featureListCount = xpath.select(
|
||||
'count(FeatureRecord)',
|
||||
featureListDom,
|
||||
true
|
||||
);
|
||||
featureRecord = createElementWithAttributes('FeatureRecord', {
|
||||
index: featureListCount,
|
||||
});
|
||||
featureRecord.appendChild(
|
||||
createElementWithAttributes('FeatureTag', { value: 'calt' })
|
||||
);
|
||||
featureRecord.appendChild(dom.createElement('Feature'));
|
||||
featureListDom.appendChild(featureRecord);
|
||||
} else {
|
||||
featureRecord = featureTag.parentNode;
|
||||
}
|
||||
featureDom = xpath.select('Feature', featureRecord, true);
|
||||
|
||||
const featureIndex = featureRecord.getAttribute('index');
|
||||
|
||||
// add feature to scriptlist for DFLT and latn if not present
|
||||
addFeatureToScriptList('DFLT', featureIndex);
|
||||
addFeatureToScriptList('latn', featureIndex);
|
||||
|
||||
lookupIndex = xpath.select('count(Lookup)', lookupListDom, true);
|
||||
|
||||
const lookupDom = createElementWithAttributes('Lookup', {
|
||||
index: lookupIndex++,
|
||||
});
|
||||
appendChildren(
|
||||
lookupDom,
|
||||
createElementWithAttributes('LookupType', { value: isSingleGlyph ? 1 : 6 }),
|
||||
createElementWithAttributes('LookupFlag', { value: 0 })
|
||||
);
|
||||
|
||||
// add contextual lookup to feature
|
||||
const featureLookupCount = xpath.select(
|
||||
'count(LookupListIndex)',
|
||||
featureDom,
|
||||
true
|
||||
);
|
||||
featureDom.appendChild(
|
||||
createElementWithAttributes('LookupListIndex', {
|
||||
index: featureLookupCount,
|
||||
value: lookupDom.getAttribute('index'),
|
||||
})
|
||||
);
|
||||
|
||||
if (isSingleGlyph) {
|
||||
lookupDom.appendChild(
|
||||
getSubstLookup(ligature.name, ligature.glyph, lookupDom)
|
||||
);
|
||||
} else {
|
||||
lookupDom.appendChild(buildBacktrackFirst(glyphs));
|
||||
lookupDom.appendChild(buildLookAheadLast(glyphs));
|
||||
lookupDom.appendChild(buildLigatureSubst(glyphs, ligature.glyph));
|
||||
// remaining context
|
||||
for (let n = glyphs.length - 2; n >= 0; n--) {
|
||||
lookupDom.appendChild(
|
||||
buildChainContext(getLIGs(n), [glyphs[n]], glyphs.slice(n + 1), 'LIG')
|
||||
);
|
||||
}
|
||||
}
|
||||
lookupListDom.appendChild(lookupDom);
|
||||
};
|
||||
|
||||
const finalizeGsubTables = () => {
|
||||
// get current LookupList count
|
||||
let newIndex = xpath.select('count(Lookup)', lookupListDom, true);
|
||||
|
||||
// append added lookups
|
||||
Object.entries(substLookupMap).forEach(([, lookup]) => {
|
||||
// fixup existing lookups with new index
|
||||
const oldIndex = lookup.getAttribute('index');
|
||||
const substLookups = xpath.select(
|
||||
`//ChainContextSubst/SubstLookupRecord/LookupListIndex[@value="${oldIndex}"]`,
|
||||
lookupListDom,
|
||||
false
|
||||
);
|
||||
substLookups.forEach((substLookup) => {
|
||||
substLookup.setAttribute('value', newIndex);
|
||||
});
|
||||
lookup.setAttribute('index', newIndex++);
|
||||
lookupListDom.appendChild(lookup);
|
||||
});
|
||||
};
|
||||
|
||||
//const dump = dom => console.log(format(serialize(dom)));
|
||||
|
||||
const addFeatureToScriptList = (tag, featureIndex) => {
|
||||
scriptListDom = xpath.select('ScriptList', gsubDom, true);
|
||||
const defaultLangSys = xpath.select(
|
||||
`ScriptRecord/ScriptTag[@value="${tag}"]/../Script/DefaultLangSys`,
|
||||
scriptListDom,
|
||||
true
|
||||
);
|
||||
const featureIndexNode = xpath.select(
|
||||
`FeatureIndex[@value=${featureIndex}]`,
|
||||
defaultLangSys,
|
||||
true
|
||||
);
|
||||
if (!featureIndexNode) {
|
||||
const count = xpath.select('count(FeatureIndex)', defaultLangSys, true);
|
||||
defaultLangSys.appendChild(
|
||||
createElementWithAttributes('FeatureIndex', {
|
||||
index: count,
|
||||
value: featureIndex,
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const buildBacktrackFirst = (glyphs) => {
|
||||
// backtrack = first glyph
|
||||
// input = first glphy
|
||||
// lookAhead = [1..n]
|
||||
return buildChainContext([glyphs[0]], [glyphs[0]], glyphs.slice(1));
|
||||
};
|
||||
|
||||
const buildLookAheadLast = (glyphs) => {
|
||||
// backtrack = none
|
||||
// input = first glyph
|
||||
// lookAhead = [1..n] + [n]
|
||||
return buildChainContext(
|
||||
[],
|
||||
[glyphs[0]],
|
||||
[...glyphs.slice(1), glyphs.slice(-1)]
|
||||
);
|
||||
};
|
||||
|
||||
const buildLigatureSubst = (glyphs, lookup) => {
|
||||
// backtrack = LIG * n-1
|
||||
// input = last glyph
|
||||
// lookAhead = none
|
||||
return buildChainContext(
|
||||
getLIGs(glyphs.length - 1),
|
||||
glyphs.slice(-1),
|
||||
[],
|
||||
lookup
|
||||
);
|
||||
};
|
||||
|
||||
const getLIGs = (length) => new Array(length).fill('LIG', 0, length);
|
||||
|
||||
const buildChainContext = (backtrack, input, lookAhead, substitute) => {
|
||||
const chainDom = createElementWithAttributes('ChainContextSubst', {
|
||||
index: chainIndex++,
|
||||
Format: 3,
|
||||
});
|
||||
|
||||
buildCoverage(chainDom, 'BacktrackCoverage', backtrack);
|
||||
buildCoverage(chainDom, 'InputCoverage', input);
|
||||
buildCoverage(chainDom, 'LookAheadCoverage', lookAhead);
|
||||
|
||||
if (substitute) {
|
||||
const lookup = getSubstLookup(input[0], substitute);
|
||||
const listIndex = lookup.getAttribute('index');
|
||||
const substLookupRecordDom = chainDom.appendChild(
|
||||
createElementWithAttributes('SubstLookupRecord', { index: 0 })
|
||||
);
|
||||
appendChildren(
|
||||
substLookupRecordDom,
|
||||
createElementWithAttributes('SequenceIndex', { value: 0 }),
|
||||
createElementWithAttributes('LookupListIndex', { value: listIndex })
|
||||
);
|
||||
}
|
||||
return chainDom;
|
||||
};
|
||||
|
||||
const buildCoverage = (chainDom, tagName, coverage) => {
|
||||
if (coverage) {
|
||||
coverage.forEach((glyph, i) => {
|
||||
const coverageDom = createElementWithAttributes(tagName, {
|
||||
index: i++,
|
||||
Format: 1,
|
||||
});
|
||||
coverageDom.appendChild(
|
||||
createElementWithAttributes('Glyph', { value: glyph })
|
||||
);
|
||||
chainDom.appendChild(coverageDom);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const getSubstLookup = (input, output, lookupDom) => {
|
||||
if (!lookupDom) {
|
||||
lookupDom = substLookupMap[output];
|
||||
}
|
||||
|
||||
if (!lookupDom) {
|
||||
lookupDom = createElementWithAttributes('Lookup', {
|
||||
index: Object.keys(substLookupMap).length + 1,
|
||||
});
|
||||
lookupDom.appendChild(
|
||||
createElementWithAttributes('LookupType', { value: 1 })
|
||||
);
|
||||
lookupDom.appendChild(
|
||||
createElementWithAttributes('LookupFlag', { value: 0 })
|
||||
);
|
||||
substLookupMap[output] = lookupDom;
|
||||
}
|
||||
|
||||
let singleSubstDom = xpath.select('SingleSubst', lookupDom, true);
|
||||
|
||||
if (!singleSubstDom) {
|
||||
singleSubstDom = createElementWithAttributes('SingleSubst', {
|
||||
index: 0,
|
||||
Format: 2,
|
||||
});
|
||||
lookupDom.appendChild(singleSubstDom);
|
||||
}
|
||||
|
||||
// look for input subst
|
||||
const substitionDom = xpath.select(
|
||||
`Substitution[@in="${input}"]`,
|
||||
singleSubstDom,
|
||||
true
|
||||
);
|
||||
if (!substitionDom) {
|
||||
singleSubstDom.appendChild(
|
||||
createElementWithAttributes('Substitution', { in: input, out: output })
|
||||
);
|
||||
}
|
||||
return lookupDom;
|
||||
};
|
||||
|
||||
const createElementWithAttributes = (tagName, attributes) => {
|
||||
const element = dom.createElement(tagName);
|
||||
Object.entries(attributes).forEach((attribute) => {
|
||||
element.setAttribute(attribute[0], attribute[1]);
|
||||
});
|
||||
return element;
|
||||
};
|
||||
|
||||
const appendChildren = (node, ...children) => {
|
||||
children.forEach((child) => node.appendChild(child));
|
||||
};
|
||||
|
||||
//const serialize = dom => new XMLSerializer().serializeToString(dom);
|
||||
|
||||
exports.initGsubTables = initGsubTables;
|
||||
exports.buildGsubTables = buildGsubTables;
|
||||
exports.finalizeGsubTables = finalizeGsubTables;
|
||||
|
After Width: | Height: | Size: 166 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 612 B |
|
After Width: | Height: | Size: 805 B |
|
After Width: | Height: | Size: 423 B |
|
After Width: | Height: | Size: 439 B |
|
After Width: | Height: | Size: 293 B |
|
After Width: | Height: | Size: 338 B |
|
After Width: | Height: | Size: 566 B |
|
After Width: | Height: | Size: 564 B |
|
After Width: | Height: | Size: 828 B |
|
After Width: | Height: | Size: 677 B |
|
After Width: | Height: | Size: 731 B |
|
After Width: | Height: | Size: 506 B |
|
After Width: | Height: | Size: 771 B |
|
After Width: | Height: | Size: 691 B |
|
After Width: | Height: | Size: 740 B |
|
After Width: | Height: | Size: 849 B |
|
After Width: | Height: | Size: 327 B |
|
After Width: | Height: | Size: 518 B |
|
After Width: | Height: | Size: 290 B |
|
After Width: | Height: | Size: 521 B |
@@ -0,0 +1,15 @@
|
||||
<html><head>
|
||||
<style>
|
||||
body { background-color: #000; color: #fff; font-family: sans-serif; margin: 16px;}
|
||||
a { color: #fff; text-decoration: none; padding: 4px;}
|
||||
a.active {color: #000; background-color: #fff;}
|
||||
.container { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
|
||||
.ligature { display: flex; flex-direction: column; align-items: center; margin: 8px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Operator Mono Ligatures</h1>
|
||||
<a href="https://htmlpreview.github.io/?https://github.com/kiliman/operator-mono-lig/blob/master/images/preview/normal/index.html" class="">Normal</a> |
|
||||
<a href="https://htmlpreview.github.io/?https://github.com/kiliman/operator-mono-lig/blob/master/images/preview/italic/index.html" class="active">Italic</a>
|
||||
<div class="container">
|
||||
<div class="ligature"><img src="ampersand_ampersand.png"/><div>ampersand_ampersand</div></div><div class="ligature"><img src="asterisk_equal.png"/><div>asterisk_equal</div></div><div class="ligature"><img src="bar_bar.png"/><div>bar_bar</div></div><div class="ligature"><img src="bar_greater.png"/><div>bar_greater</div></div><div class="ligature"><img src="colon_colon.png"/><div>colon_colon</div></div><div class="ligature"><img src="colon_equal.png"/><div>colon_equal</div></div><div class="ligature"><img src="equal_equal.png"/><div>equal_equal</div></div><div class="ligature"><img src="equal_equal_equal.png"/><div>equal_equal_equal</div></div><div class="ligature"><img src="equal_equal_greater.png"/><div>equal_equal_greater</div></div><div class="ligature"><img src="equal_greater.png"/><div>equal_greater</div></div><div class="ligature"><img src="equal_less_less.png"/><div>equal_less_less</div></div><div class="ligature"><img src="exclam_equal.png"/><div>exclam_equal</div></div><div class="ligature"><img src="exclam_equal_equal.png"/><div>exclam_equal_equal</div></div><div class="ligature"><img src="exclam_exclam.png"/><div>exclam_exclam</div></div><div class="ligature"><img src="greater_equal.png"/><div>greater_equal</div></div><div class="ligature"><img src="greater_equal_greater.png"/><div>greater_equal_greater</div></div><div class="ligature"><img src="greater_greater.png"/><div>greater_greater</div></div><div class="ligature"><img src="greater_greater_equal.png"/><div>greater_greater_equal</div></div><div class="ligature"><img src="hyphen_equal.png"/><div>hyphen_equal</div></div><div class="ligature"><img src="hyphen_greater.png"/><div>hyphen_greater</div></div><div class="ligature"><img src="hyphen_hyphen.png"/><div>hyphen_hyphen</div></div><div class="ligature"><img src="hyphen_hyphen_greater.png"/><div>hyphen_hyphen_greater</div></div><div class="ligature"><img src="less_bar.png"/><div>less_bar</div></div><div class="ligature"><img src="less_equal.png"/><div>less_equal</div></div><div class="ligature"><img src="less_equal_equal.png"/><div>less_equal_equal</div></div><div class="ligature"><img src="less_equal_greater.png"/><div>less_equal_greater</div></div><div class="ligature"><img src="less_equal_less.png"/><div>less_equal_less</div></div><div class="ligature"><img src="less_exclam_hyphen_hyphen.png"/><div>less_exclam_hyphen_hyphen</div></div><div class="ligature"><img src="less_hyphen.png"/><div>less_hyphen</div></div><div class="ligature"><img src="less_hyphen_greater.png"/><div>less_hyphen_greater</div></div><div class="ligature"><img src="less_hyphen_hyphen.png"/><div>less_hyphen_hyphen</div></div><div class="ligature"><img src="less_less.png"/><div>less_less</div></div><div class="ligature"><img src="less_less_equal.png"/><div>less_less_equal</div></div><div class="ligature"><img src="less_slash.png"/><div>less_slash</div></div><div class="ligature"><img src="less_slash_greater.png"/><div>less_slash_greater</div></div><div class="ligature"><img src="plus_equal.png"/><div>plus_equal</div></div><div class="ligature"><img src="plus_plus.png"/><div>plus_plus</div></div><div class="ligature"><img src="question_question.png"/><div>question_question</div></div><div class="ligature"><img src="quotedbl_quotedbl_quotedbl.png"/><div>quotedbl_quotedbl_quotedbl</div></div><div class="ligature"><img src="quotesingle_quotesingle_quotesingle.png"/><div>quotesingle_quotesingle_quotesingle</div></div><div class="ligature"><img src="semicolon_semicolon.png"/><div>semicolon_semicolon</div></div><div class="ligature"><img src="slash_equal.png"/><div>slash_equal</div></div><div class="ligature"><img src="slash_greater.png"/><div>slash_greater</div></div><div class="ligature"><img src="underscore_underscore.png"/><div>underscore_underscore</div></div><div class="ligature"><img src="w_w_w.png"/><div>w_w_w</div></div></div></body></html>
|
||||
|
After Width: | Height: | Size: 799 B |
|
After Width: | Height: | Size: 775 B |
|
After Width: | Height: | Size: 571 B |
|
After Width: | Height: | Size: 798 B |
|
After Width: | Height: | Size: 692 B |
|
After Width: | Height: | Size: 737 B |
|
After Width: | Height: | Size: 529 B |
|
After Width: | Height: | Size: 754 B |
|
After Width: | Height: | Size: 527 B |
|
After Width: | Height: | Size: 714 B |
|
After Width: | Height: | Size: 861 B |
|
After Width: | Height: | Size: 795 B |
|
After Width: | Height: | Size: 998 B |
|
After Width: | Height: | Size: 484 B |
|
After Width: | Height: | Size: 497 B |
|
After Width: | Height: | Size: 760 B |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 633 B |
|
After Width: | Height: | Size: 791 B |
|
After Width: | Height: | Size: 245 B |
|
After Width: | Height: | Size: 678 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 283 B |
|
After Width: | Height: | Size: 646 B |
|
After Width: | Height: | Size: 408 B |
|
After Width: | Height: | Size: 374 B |
|
After Width: | Height: | Size: 281 B |
|
After Width: | Height: | Size: 320 B |
|
After Width: | Height: | Size: 571 B |
|
After Width: | Height: | Size: 579 B |
|
After Width: | Height: | Size: 867 B |
|
After Width: | Height: | Size: 656 B |
|
After Width: | Height: | Size: 733 B |
|
After Width: | Height: | Size: 367 B |
|
After Width: | Height: | Size: 712 B |
|
After Width: | Height: | Size: 690 B |
|
After Width: | Height: | Size: 725 B |
|
After Width: | Height: | Size: 865 B |
|
After Width: | Height: | Size: 314 B |
|
After Width: | Height: | Size: 527 B |
|
After Width: | Height: | Size: 277 B |
|
After Width: | Height: | Size: 523 B |
@@ -0,0 +1,15 @@
|
||||
<html><head>
|
||||
<style>
|
||||
body { background-color: #000; color: #fff; font-family: sans-serif; margin: 16px;}
|
||||
a { color: #fff; text-decoration: none; padding: 4px;}
|
||||
a.active {color: #000; background-color: #fff;}
|
||||
.container { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
|
||||
.ligature { display: flex; flex-direction: column; align-items: center; margin: 8px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Operator Mono Ligatures</h1>
|
||||
<a href="https://htmlpreview.github.io/?https://github.com/kiliman/operator-mono-lig/blob/master/images/preview/normal/index.html" class="active">Normal</a> |
|
||||
<a href="https://htmlpreview.github.io/?https://github.com/kiliman/operator-mono-lig/blob/master/images/preview/italic/index.html" class="">Italic</a>
|
||||
<div class="container">
|
||||
<div class="ligature"><img src="ampersand_ampersand.png"/><div>ampersand_ampersand</div></div><div class="ligature"><img src="asterisk_equal.png"/><div>asterisk_equal</div></div><div class="ligature"><img src="bar_bar.png"/><div>bar_bar</div></div><div class="ligature"><img src="bar_greater.png"/><div>bar_greater</div></div><div class="ligature"><img src="colon_colon.png"/><div>colon_colon</div></div><div class="ligature"><img src="colon_equal.png"/><div>colon_equal</div></div><div class="ligature"><img src="equal_equal.png"/><div>equal_equal</div></div><div class="ligature"><img src="equal_equal_equal.png"/><div>equal_equal_equal</div></div><div class="ligature"><img src="equal_equal_greater.png"/><div>equal_equal_greater</div></div><div class="ligature"><img src="equal_greater.png"/><div>equal_greater</div></div><div class="ligature"><img src="equal_less_less.png"/><div>equal_less_less</div></div><div class="ligature"><img src="exclam_equal.png"/><div>exclam_equal</div></div><div class="ligature"><img src="exclam_equal_equal.png"/><div>exclam_equal_equal</div></div><div class="ligature"><img src="exclam_exclam.png"/><div>exclam_exclam</div></div><div class="ligature"><img src="greater_equal.png"/><div>greater_equal</div></div><div class="ligature"><img src="greater_equal_greater.png"/><div>greater_equal_greater</div></div><div class="ligature"><img src="greater_greater.png"/><div>greater_greater</div></div><div class="ligature"><img src="greater_greater_equal.png"/><div>greater_greater_equal</div></div><div class="ligature"><img src="hyphen_equal.png"/><div>hyphen_equal</div></div><div class="ligature"><img src="hyphen_greater.png"/><div>hyphen_greater</div></div><div class="ligature"><img src="hyphen_hyphen.png"/><div>hyphen_hyphen</div></div><div class="ligature"><img src="hyphen_hyphen_greater.png"/><div>hyphen_hyphen_greater</div></div><div class="ligature"><img src="less_bar.png"/><div>less_bar</div></div><div class="ligature"><img src="less_equal.png"/><div>less_equal</div></div><div class="ligature"><img src="less_equal_equal.png"/><div>less_equal_equal</div></div><div class="ligature"><img src="less_equal_greater.png"/><div>less_equal_greater</div></div><div class="ligature"><img src="less_equal_less.png"/><div>less_equal_less</div></div><div class="ligature"><img src="less_exclam_hyphen_hyphen.png"/><div>less_exclam_hyphen_hyphen</div></div><div class="ligature"><img src="less_hyphen.png"/><div>less_hyphen</div></div><div class="ligature"><img src="less_hyphen_greater.png"/><div>less_hyphen_greater</div></div><div class="ligature"><img src="less_hyphen_hyphen.png"/><div>less_hyphen_hyphen</div></div><div class="ligature"><img src="less_less.png"/><div>less_less</div></div><div class="ligature"><img src="less_less_equal.png"/><div>less_less_equal</div></div><div class="ligature"><img src="less_slash.png"/><div>less_slash</div></div><div class="ligature"><img src="less_slash_greater.png"/><div>less_slash_greater</div></div><div class="ligature"><img src="plus_equal.png"/><div>plus_equal</div></div><div class="ligature"><img src="plus_plus.png"/><div>plus_plus</div></div><div class="ligature"><img src="question_question.png"/><div>question_question</div></div><div class="ligature"><img src="quotedbl_quotedbl_quotedbl.png"/><div>quotedbl_quotedbl_quotedbl</div></div><div class="ligature"><img src="quotesingle_quotesingle_quotesingle.png"/><div>quotesingle_quotesingle_quotesingle</div></div><div class="ligature"><img src="semicolon_semicolon.png"/><div>semicolon_semicolon</div></div><div class="ligature"><img src="slash_equal.png"/><div>slash_equal</div></div><div class="ligature"><img src="slash_greater.png"/><div>slash_greater</div></div><div class="ligature"><img src="underscore_underscore.png"/><div>underscore_underscore</div></div><div class="ligature"><img src="w_w_w.png"/><div>w_w_w</div></div></div></body></html>
|
||||
|
After Width: | Height: | Size: 637 B |
|
After Width: | Height: | Size: 745 B |
|
After Width: | Height: | Size: 584 B |
|
After Width: | Height: | Size: 812 B |
|
After Width: | Height: | Size: 696 B |
|
After Width: | Height: | Size: 722 B |
|
After Width: | Height: | Size: 509 B |
|
After Width: | Height: | Size: 755 B |
|
After Width: | Height: | Size: 510 B |
|
After Width: | Height: | Size: 722 B |
|
After Width: | Height: | Size: 869 B |
|
After Width: | Height: | Size: 779 B |
|
After Width: | Height: | Size: 1010 B |
|
After Width: | Height: | Size: 382 B |
|
After Width: | Height: | Size: 348 B |
|
After Width: | Height: | Size: 763 B |