35 Commits

Author SHA1 Message Date
Kiliman 7a86cd065f 🚀 Deploy v2.4.2
Bumped version due to package.lock.json issue
2022-02-18 09:49:32 -05:00
kiliman 834a086e09 📦 Update xml-formatter package and refresh package lock
Fixes #178
2022-02-13 16:38:04 -05:00
kiliman 298723b87e 🐛 Fix typo in all-contributors for @killua 2021-10-18 10:19:10 -04:00
kiliman 0956c0e569 😍 Add @killua99 as a contributor 2021-10-18 10:19:10 -04:00
kiliman 30ef51ace3 😍 Add @GlorifiedBicycle as a contributor 2021-10-18 10:13:26 -04:00
kiliman 8aa2677ffc 😍 Add @kilua99 as a contributor 2021-10-18 10:12:34 -04:00
Reland Boyle 5c25311fdf Added note regardign installing FontTools under WSL/WSL2 (#174) 2021-10-18 10:12:07 -04:00
Luigi a55ef07837 📝 Improve readme installation for Windows (#167) 2021-05-25 14:56:08 -04:00
dependabot[bot] 09bbb2bb76 Bump xmldom from 0.1.27 to 0.5.0 (#163)
Bumps [xmldom](https://github.com/xmldom/xmldom) from 0.1.27 to 0.5.0.
- [Release notes](https://github.com/xmldom/xmldom/releases)
- [Changelog](https://github.com/xmldom/xmldom/blob/master/CHANGELOG.md)
- [Commits](https://github.com/xmldom/xmldom/compare/v0.1.27...0.5.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-13 17:23:50 -06:00
kiliman 4ff7dbde28 🚀 Deploy v2.4.1 2020-12-18 09:35:06 -05:00
kiliman 0d7089f840 💄 Reformat with prettier 2020-12-18 09:33:55 -05:00
kiliman 8a32259fdc 🐛 Fix italic ligatures slanting wrong direction #160 2020-12-18 09:33:34 -05:00
kiliman ee481cc744 🐛 Fix links in generated preview file 2020-12-13 14:42:12 -05:00
kiliman 196e13856c 🔨 Add link to preview HTML using htmlpreview.github.io 2020-12-13 14:39:14 -05:00
kiliman 2029e07965 🔥 Remove link to preview in README due to broken display on GitHub 2020-12-13 13:08:41 -05:00
kiliman 4955c58098 Add preview images and update README 2020-12-13 13:05:08 -05:00
kiliman c63a5b0abb Add script to generate preview images of ligatures (normal and italic) 2020-12-13 13:04:42 -05:00
kiliman 8f7db7bc4c 📦 Add prettier and update eslint config 2020-12-13 13:03:12 -05:00
kiliman 3813319b42 🚀 Deploy v2.4.0 2020-12-13 10:16:02 -05:00
kiliman f2a61c74ad 🔀 Merge branch 'feature/use-fea-files' 2020-12-13 10:13:23 -05:00
kiliman 1fce61fe50 🔨 Update build to call fonttools feaLib 2020-12-13 10:11:28 -05:00
kiliman 1028c96291 🔥 Delete gsub.js and replace with calt feature 2020-12-13 10:07:52 -05:00
kiliman 043c160546 Add default feature file since feaLib replaces existing features 2020-12-13 10:06:11 -05:00
kiliman 445828c8bf Add function to generate calt feature file 2020-12-13 10:05:41 -05:00
kiliman 66fd3f94a1 🙈 Ignore all files in .vscode 2020-12-13 10:04:27 -05:00
kiliman 9bf5f6197c Add new spacer glyphs to replace LIG placeholder 2020-12-12 17:50:16 -05:00
Mark Skelton bd48389313 Update deps (#159)
* Fix eslint error

* Add repository to package.json

* Remove unused dependencies

* Update dev eslint deps
2020-12-09 14:21:23 -06:00
kiliman 30a6c098e7 🚀 Deploy v2.3.0 2020-05-13 08:41:16 -04:00
kiliman 42e64f84b8 🔀 Merge branch 'feature/italics-hack'
Fix #104
2020-05-13 08:40:43 -04:00
kiliman 124d893fe5 Add plus_equal.liga and update colon_equal.liga 2020-05-13 08:25:53 -04:00
kiliman e692fcfbf8 🔨 Make italics-hack the default option with ability to turn it off 2020-05-13 08:23:09 -04:00
kiliman 321486d19e 🐛 Add init function to only apply the hack once instead of per ligature 2020-05-12 12:05:21 -04:00
kiliman 6f3d00ae6d 🪓 Add hack for italics by removing existing GSUB tables 2020-05-12 09:36:58 -04:00
Mark Skelton 420eeefe59 Merge pull request #131 from kiliman/dependabot/npm_and_yarn/acorn-6.4.1
Bump acorn from 6.2.1 to 6.4.1
2020-04-14 13:30:53 -05:00
dependabot[bot] a5c360bf30 Bump acorn from 6.2.1 to 6.4.1
Bumps [acorn](https://github.com/acornjs/acorn) from 6.2.1 to 6.4.1.
- [Release notes](https://github.com/acornjs/acorn/releases)
- [Commits](https://github.com/acornjs/acorn/compare/6.2.1...6.4.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-04-04 21:23:15 +00:00
660 changed files with 4876 additions and 16301 deletions
+27
View File
@@ -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
+6 -9
View File
@@ -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 -1
View File
@@ -1,5 +1,5 @@
build
node_modules
.idea
.vscode/launch.json
.vscode
.DS_Store
+4 -2
View File
@@ -1,4 +1,6 @@
{
"semi": true,
"singleQuote": true
"semi": false,
"singleQuote": true,
"trailingComma": "all",
"arrowParens": "avoid"
}
+16 -7
View File
@@ -20,6 +20,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.
@@ -57,6 +59,8 @@ Which font weight of Operator Mono do you use? Also note difference between Scre
- Node.js
- Install _fonttools_ from https://github.com/fonttools/fonttools
- Windows/Linux: `pip 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`
## Installation
@@ -152,17 +156,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!
+13 -5
View File
@@ -3,19 +3,25 @@ setlocal
if not exist .\build\* mkdir build
set flags=
if "%1"=="--italics-hack-off" (
set flags=%1
shift
)
rem only build passed in font
if not "%1%"=="" (
call :build_font %1
if not "%1"=="" (
call :build_font %1 %flags%
exit /b
)
rem build all fonts
for /d %%d in (.\ligature\*) do call :build_font %%~nd
for /d %%d in (.\ligature\*) do call :build_font %%~nd %flags%
exit /b
:build_font
set lig=%1
set flags=%2
set otf=%lig:Lig-=-%
if not exist .\original\%otf%.otf exit /b
@@ -23,6 +29,8 @@ if not exist .\ligature\%lig%\glyphs\* exit /b
@echo Building %lig%
ttx -f .\original\%otf%.otf
node index.js %otf%
for %%f in (.\build\%lig%*.ttx) do ttx -f %%f
node index.js %otf% %flags%
ttx -f .\build\%lig%.ttx
fonttools feaLib -v -o ".\build\%lig%.otf" .\features\default.fea ".\build\%lig%.otf"
exit /b
+14 -7
View File
@@ -4,6 +4,7 @@ mkdir -p build
build_font() {
lig="$1"
flags="$2"
otf=${lig/Lig-/-}
if [ ! -e "./original/$otf.otf" ]
@@ -15,22 +16,28 @@ build_font() {
return
fi
echo Building $1
echo Building "$1"
ttx -f "./original/$otf.otf"
node index.js $otf
node index.js "$otf" "$flags"
for f in ./build/$1*.ttx ; do
ttx -f $f
done
ttx -f "./build/$1.ttx"
fonttools feaLib -v -o "./build/$1.otf" ./features/default.fea "./build/$1.otf"
}
flags=
if [ "$1" = "--italics-hack-off" ]
then
flags=$1
shift
fi
if [ -n "$1" ]
then
# build specified font
build_font $1
build_font "$1" "$flags"
else
# build all available fonts
for d in ./ligature/*/ ; do
build_font $(basename $d)
build_font "$(basename "$d")" "$flags"
done
fi
+65
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
calt.fea
+212
View File
@@ -0,0 +1,212 @@
languagesystem DFLT dflt;
languagesystem latn dflt;
lookup lookup_0 {
sub zero by zero.num;
sub one by one.num;
sub two by two.num;
sub three by three.num;
sub four by four.num;
sub five by five.num;
sub six by six.num;
sub seven by seven.num;
sub eight by eight.num;
sub nine by nine.num;
sub slash by fraction;
sub fraction by fraction.afrc;
} lookup_0;
lookup lookup_1 {
sub zero by zero.den;
sub one by one.den;
sub two by two.den;
sub three by three.den;
sub four by four.den;
sub five by five.den;
sub six by six.den;
sub seven by seven.den;
sub eight by eight.den;
sub nine by nine.den;
sub slash by fraction;
} lookup_1;
lookup lookup_2 {
sub L periodcentered by Ldot;
sub l periodcentered by ldot;
} lookup_2;
feature case {
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;
feature dnom {
sub zero by zero.den;
sub one by one.den;
sub two by two.den;
sub three by three.den;
sub four by four.den;
sub five by five.den;
sub six by six.den;
sub seven by seven.den;
sub eight by eight.den;
sub nine by nine.den;
} dnom;
feature frac {
lookup frac0 {
sub [zero one two three four five six seven eight nine] slash' lookup lookup_0 [zero one two three four five six seven eight nine] ;
} frac0;
lookup frac1 {
ignore sub [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] [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] fraction' ;
ignore sub fraction' [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] [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] ;
sub [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] fraction' lookup lookup_0 [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] ;
} frac1;
lookup frac2 {
sub [zero one two three four five six seven eight nine]' lookup lookup_0 fraction.afrc ;
sub fraction.afrc [zero one two three four five six seven eight nine]' lookup lookup_1 ;
} 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 locl {
script latn;
language CAT ;
sub l' lookup lookup_2 periodcentered' lookup lookup_2 l ;
sub L' lookup lookup_2 periodcentered' lookup lookup_2 L ;
} locl;
feature numr {
sub zero by zero.num;
sub one by one.num;
sub two by two.num;
sub three by three.num;
sub four by four.num;
sub five by five.num;
sub six by six.num;
sub seven by seven.num;
sub eight by eight.num;
sub nine by nine.num;
} numr;
feature rupa {
sub R p by R_p;
} rupa;
feature ss01 {
sub registered by registered.alt;
} ss01;
feature salt {
lookup salt0 {
sub registered by registered.alt;
} salt0;
lookup salt1 {
sub colon by colon.alt;
} salt1;
lookup salt2 {
sub bullet by bullet.alt;
} salt2;
lookup salt3 {
sub asterisk by asterisk.alt;
} salt3;
lookup salt4 {
sub zero by zero.alt;
} salt4;
lookup salt5 {
sub underscore by underscore.alt;
} salt5;
lookup salt6 {
sub [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] slash' lookup lookup_1 [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] ;
} salt6;
} salt;
feature sinf {
sub zero by zero.inf;
sub one by one.inf;
sub two by two.inf;
sub three by three.inf;
sub four by four.inf;
sub five by five.inf;
sub six by six.inf;
sub seven by seven.inf;
sub eight by eight.inf;
sub nine by nine.inf;
} sinf;
feature ss03 {
sub colon by colon.alt;
} ss03;
feature ss04 {
sub bullet by bullet.alt;
} ss04;
feature ss05 {
sub asterisk by asterisk.alt;
} ss05;
feature ss07 {
sub zero by zero.alt;
} ss07;
feature ss08 {
sub underscore by underscore.alt;
} ss08;
feature ss09 {
sub [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] slash' lookup lookup_1 [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] ;
} ss09;
feature subs {
sub zero by zero.inf;
sub one by one.inf;
sub two by two.inf;
sub three by three.inf;
sub four by four.inf;
sub five by five.inf;
sub six by six.inf;
sub seven by seven.inf;
sub eight by eight.inf;
sub nine by nine.inf;
} subs;
feature subs {
sub zero by zero.sup;
sub one by one.sup;
sub two by two.sup;
sub three by three.sup;
sub four by four.sup;
sub five by five.sup;
sub six by six.sup;
sub seven by seven.sup;
sub eight by eight.sup;
sub nine by nine.sup;
} subs;
include(calt.fea);
+85
View File
@@ -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)
+36
View File
@@ -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);
});
});
});
});
-288
View File
@@ -1,288 +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 buildGsubTables = (_dom, ligature) => {
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);
lookupListDom = xpath.select('LookupList', gsubDom, true);
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);
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.buildGsubTables = buildGsubTables;
exports.finalizeGsubTables = finalizeGsubTables;
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 776 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 566 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 828 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 678 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 724 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 808 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 691 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 853 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 B

+15
View File
@@ -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="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_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="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_equal.png"/><div>greater_greater_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_slash.png"/><div>less_slash</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="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>
Binary file not shown.

After

Width:  |  Height:  |  Size: 809 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 779 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 571 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 798 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 692 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 730 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 529 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 754 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 795 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 519 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 782 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 791 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 678 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 369 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 571 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 579 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 720 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 690 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 855 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 523 B

+15
View File
@@ -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="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_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="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_equal.png"/><div>greater_greater_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_slash.png"/><div>less_slash</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="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>
Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 724 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 584 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 812 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 710 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 755 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 510 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 779 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 748 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 783 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 609 B

+50 -42
View File
@@ -1,10 +1,11 @@
// @ts-nocheck
const fs = require('fs');
const os = require('os');
if (!os.EOL) {
os.EOL = process.platform === 'win32' ? '\r\n' : '\n';
}
const gsub = require('./gsub');
const calt = require('./calt');
const xpath = require('xpath');
const { DOMParser, XMLSerializer } = require('xmldom');
@@ -17,8 +18,12 @@ const NodeType = {};
NodeType.TEXT_NODE = 3;
let dom;
let italicsHack = false;
function main() {
fontName = process.argv[2];
italicsHack =
fontName.includes('Italic') && process.argv[3] !== '--italics-hack-off';
ligFontName = fontName.split('-').join('Lig-');
const srcFileName = `./original/${fontName}.ttx`;
@@ -29,12 +34,12 @@ function main() {
const profiles = getProfiles();
// process settings (there may be more than one font to build)
profiles.forEach(profile => buildFont(profile));
profiles.forEach((profile) => buildFont(profile, { italicsHack }));
console.log('Done');
}
const buildFont = profile => {
const buildFont = (profile, options) => {
// add suffix to dstFileName if present
const dstFileName = `./build/${ligFontName}${profile.suffixWithLeadingHyphen}.ttx`;
console.log(
@@ -44,23 +49,25 @@ const buildFont = profile => {
const ligatures = sortLigatures(
fs
.readdirSync(`./ligature/${ligFontName}/glyphs`)
.filter(file => /\.xml$/.test(file))
.map(file => file.replace('.xml', ''))
.filter((file) => /\.xml$/.test(file))
.map((file) => file.replace('.xml', ''))
)
.filter(name => !/\d+\.liga$/.test(name)) // skip alternates (ends with .#)
.filter(name => filterLigatures(name, profile.ligatures))
.map(name => mapLigatures(name, profile.ligatures))
.filter(entry => filterGlyphsExists(entry));
.filter((name) => !/\d+\.liga$/.test(name)) // skip alternates (ends with .#)
.filter((name) => filterLigatures(name, profile.ligatures))
.map((name) => mapLigatures(name, profile.ligatures))
.filter((entry) => filterGlyphsExists(entry));
const ligaturesWithLIG = ligatures;
//[...ligatures, { name: 'LIG', glyph: 'LIG' }];
processPatch('names', patchNames, dom, ligatures, profile);
processPatch('gsub', patchGsub, dom, ligatures);
processPatch('charstrings', patchCharStrings, dom, ligaturesWithLIG);
processPatch('glyphs', patchGlyphs, dom, ligaturesWithLIG);
processPatch('hmtx', patchHmtx, dom);
const feature = calt.gencalt(ligatures);
fs.writeFileSync('./features/calt.fea', feature);
console.log(`Writing ligature font file ${dstFileName}`);
fs.writeFileSync(dstFileName, format(serialize(dom)));
};
@@ -75,8 +82,8 @@ const getProfiles = () => {
suffix: '',
suffixWithLeadingSpace: '',
suffixWithLeadingHyphen: '',
ligatures: []
}
ligatures: [],
},
];
}
@@ -86,8 +93,8 @@ const getProfiles = () => {
const content = fs.readFileSync(profilePath, 'utf-8');
content
.split(/\r|\r\n|\n/g)
.filter(line => /^[#]/.test(line) === false && line.length > 0)
.forEach(line => {
.filter((line) => /^[#]/.test(line) === false && line.length > 0)
.forEach((line) => {
const ch = line.trim()[0];
if (ch === '[') {
let name = line.substr(1, line.indexOf(']') - 1);
@@ -96,7 +103,7 @@ const getProfiles = () => {
suffix: name === 'default' ? '' : name,
suffixWithLeadingSpace: name === 'default' ? '' : ' ' + name,
suffixWithLeadingHyphen: name === 'default' ? '' : '-' + name,
ligatures: []
ligatures: [],
};
profiles.push(profile);
} else {
@@ -113,12 +120,12 @@ const getProfiles = () => {
const filterLigatures = (name, mappings) => {
// loop through mappings and return if name applies or not
// skip if setting is !name
return mappings.filter(entry => entry === '!' + name).length === 0;
return mappings.filter((entry) => entry === '!' + name).length === 0;
};
const mapLigatures = (name, mappings) => {
let mapping = { name, glyph: name };
mappings.forEach(entry => {
mappings.forEach((entry) => {
const [val1, val2] = entry.split('=');
// handle lig=altliga
if (val1 === name) {
@@ -135,10 +142,10 @@ const filterGlyphsExists = ({ glyph }) => {
return exists;
};
const sortLigatures = ligatures => {
const sortLigatures = (ligatures) => {
// sort by most glyphs then alphabetically
const sorted = ligatures
.map(ligature => {
.map((ligature) => {
return { count: ligature.split('_').length + 1, ligature: ligature };
})
.sort(
@@ -146,7 +153,7 @@ const sortLigatures = ligatures => {
-compareProperty(a.count, b.count) || // sort by count descending
compareProperty(a.ligature, b.ligature) // then by ligature alphabetically
)
.map(entry => entry.ligature);
.map((entry) => entry.ligature);
return sorted;
};
@@ -158,20 +165,20 @@ const compareProperty = (a, b) => {
}
};
const loadXml = name => {
const loadXml = (name) => {
const fileName = `./ligature/${ligFontName}/${name}.xml`;
const xml = fs.readFileSync(fileName, 'utf-8');
return new DOMParser().parseFromString(xml);
};
const processPatch = (name, patchFunc, dom, ligatures, profile) => {
const processPatch = (name, patchFunc, dom, ligatures, profile, options) => {
console.log(`Patching ${name}`);
patchFunc(dom, ligatures, profile);
patchFunc(dom, ligatures, profile, options);
};
const PlatformId = {
mac: 1,
win: 3
win: 3,
};
const NameId = {
@@ -182,7 +189,7 @@ const NameId = {
version: 5,
postscriptName: 6,
windowsFamilyName: 16,
fontStyleName: 17
fontStyleName: 17,
};
const patchNames = (dom, ligatures, profile) => {
@@ -253,7 +260,7 @@ const patchGlyphs = (dom, ligatures) => {
// only import glyphs specified
let n = glyphsCount;
// get ligature glyphs
ligatures.forEach(ligature => {
ligatures.forEach((ligature) => {
targetGlyphs.appendChild(
createElementWithAttributes('GlyphID', { id: n++, name: ligature.glyph })
);
@@ -262,18 +269,19 @@ const patchGlyphs = (dom, ligatures) => {
setAttribute(dom, '/ttFont/maxp/numGlyphs', 'value', n);
};
const patchGsub = (dom, ligatures) => {
const patchGsub = (dom, ligatures, options) => {
// don't patch if no ligatures other than LIG
if (ligatures.length <= 1) return;
gsub.initGsubTables(dom, options);
ligatures.forEach(ligature => {
ligatures.forEach((ligature) => {
// build gsub tables
gsub.buildGsubTables(dom, ligature);
gsub.buildGsubTables(dom, ligature, options);
});
gsub.finalizeGsubTables();
};
const patchHmtx = dom => {
const patchHmtx = (dom) => {
const mtxCount = xpath.select('count(/ttFont/hmtx/mtx)', dom, true);
setAttribute(dom, '/ttFont/hhea/numberOfHMetrics', 'value', mtxCount);
@@ -306,7 +314,7 @@ const patchCharStrings = (dom, ligatures) => {
);
const targetGsubrs = xpath.select('/ttFont/CFF/GlobalSubrs', dom, true);
const fingerprints = {};
ligatures.forEach(ligature => {
ligatures.forEach((ligature) => {
console.log(
`* ${ligature.name}${
ligature.name === ligature.glyph ? '' : ' => ' + ligature.glyph
@@ -318,11 +326,11 @@ const patchCharStrings = (dom, ligatures) => {
const subrs = {
sourcePath: '/Glyph/Subrs',
target: targetSubrs
target: targetSubrs,
};
const gsubrs = {
sourcePath: '/Glyph/GlobalSubrs',
target: targetGsubrs
target: targetGsubrs,
};
patchCharStringSubrs(glyphDom, node, fingerprints, subrs, gsubrs);
@@ -332,16 +340,16 @@ const patchCharStrings = (dom, ligatures) => {
createElementWithAttributes('mtx', {
name: ligature.glyph,
width: glyphDom.getAttribute('width'),
lsb: glyphDom.getAttribute('lsb')
lsb: glyphDom.getAttribute('lsb'),
})
);
const code = glyphDom.getAttribute('code');
if (code) {
Array.from(targetCmaps).forEach(node => {
Array.from(targetCmaps).forEach((node) => {
node.appendChild(
createElementWithAttributes('map', {
code,
name: ligature.glyph
name: ligature.glyph,
})
);
});
@@ -354,7 +362,7 @@ const patchCharStringSubrs = (glyphDom, node, fingerprints, subrs, gsubrs) => {
const lines = node.childNodes[0].textContent.split(/\r|\r\n|\n/g);
const newLines = [];
lines.forEach(line => {
lines.forEach((line) => {
if (line.trim().length === 0) return;
const matches = line.match(/(.*?)\{([0-9a-z]+)\} (callsubr|callgsubr)$/);
if (matches != null) {
@@ -403,21 +411,21 @@ const copyConfigAttribute = (dom, configDom, path, name) => {
const createElementWithAttributes = (tagName, attributes) => {
const element = dom.createElement(tagName);
Object.entries(attributes).forEach(attribute => {
Object.entries(attributes).forEach((attribute) => {
element.setAttribute(attribute[0], attribute[1]);
});
return element;
};
//const dump = dom => console.log(serialize(dom));
const serialize = dom =>
new XMLSerializer().serializeToString(dom, false, node => {
const serialize = (dom) =>
new XMLSerializer().serializeToString(dom, false, (node) => {
if (node.nodeType === NodeType.TEXT_NODE) {
if (regExWhitespace.test(node.data)) return null;
const data = node.data
.split(/\r|\r\n|\n/g)
.filter(s => /\S+/.test(s))
.map(s => s.replace(/^\s+/g, ''))
.filter((s) => /\S+/.test(s))
.map((s) => s.replace(/^\s+/g, ''))
.join(os.EOL);
return node.ownerDocument.createTextNode(data);
@@ -0,0 +1,7 @@
<Glyph name="ampersand.spacer" lsb="0" width="600">
<CharString>
endchar
</CharString>
<Subrs/>
<GlobalSubrs/>
</Glyph>
@@ -0,0 +1,7 @@
<Glyph name="bar.spacer" lsb="0" width="600">
<CharString>
endchar
</CharString>
<Subrs/>
<GlobalSubrs/>
</Glyph>
@@ -1,12 +1,10 @@
<Glyph name="bar_bar.liga" lsb="-211" width="550">
<CharString>
-211 75 275 75 vstem
-136 710 rmoveto
-75 -6 rlineto
-886 75 vlineto
350 892 rmoveto
-75 -6 rlineto
-886 75 vlineto
-211 704 rmoveto
-886 75 892 vlineto
275 -6 rmoveto
-886 75 892 vlineto
endchar
</CharString>
<Subrs/>
@@ -1,15 +1,15 @@
<Glyph name="bar_greater.liga" lsb="-261" width="550">
<CharString>
-261 75 468 74 vstem
-186 710 rmoveto
-75 -6 rlineto
-261 704 rmoveto
-886 75 vlineto
541 440 rlineto
69 vlineto
-74 -40 rmoveto
-467 -376 rlineto
-541 383 rlineto
-799 vmoveto
709 vlineto
467 -323 rlineto
-10 vlineto
endchar
</CharString>
<Subrs/>
@@ -0,0 +1,7 @@
<Glyph name="colon.spacer" lsb="0" width="600">
<CharString>
endchar
</CharString>
<Subrs/>
<GlobalSubrs/>
</Glyph>
@@ -2,20 +2,18 @@
<CharString>
151 69 153 69 hstem
-297 658 vstem
-297 354 rmoveto
118 hlineto
-179 354 rmoveto
2 117 rlineto
-119 hlineto
657 -98 rmoveto
1 69 rlineto
-424 -69 hlineto
-235 -245 rmoveto
118 hlineto
-1 -117 rlineto
659 88 rmoveto
-424 -69 423 hlineto
-540 -245 rmoveto
2 117 rlineto
-119 hlineto
657 -94 rmoveto
1 69 rlineto
-424 -69 hlineto
-1 -117 rlineto
659 92 rmoveto
-424 -69 423 hlineto
endchar
</CharString>
<Subrs/>
@@ -0,0 +1,7 @@
<Glyph name="equal.spacer" lsb="0" width="600">
<CharString>
endchar
</CharString>
<Subrs/>
<GlobalSubrs/>
</Glyph>
@@ -2,18 +2,14 @@
<CharString>
151 69 153 69 hstem
-472 944 vstem
-49 373 rmoveto
1 69 rlineto
-424 -69 hlineto
943 hmoveto
1 69 rlineto
-414 -69 hlineto
-107 -222 rmoveto
1 69 rlineto
-424 -69 hlineto
943 hmoveto
1 69 rlineto
-414 -69 hlineto
-48 442 rmoveto
-424 -69 423 hlineto
521 69 rmoveto
-414 -69 413 hlineto
-519 -153 rmoveto
-424 -69 423 hlineto
521 69 rmoveto
-414 -69 413 hlineto
endchar
</CharString>
<Subrs/>
@@ -2,12 +2,10 @@
<CharString>
151 69 153 69 hstem
-472 944 vstem
471 373 rmoveto
1 69 rlineto
-944 -69 hlineto
943 -222 rmoveto
1 69 rlineto
-944 -69 hlineto
472 442 rmoveto
-944 -69 943 hlineto
1 -153 rmoveto
-944 -69 943 hlineto
endchar
</CharString>
<Subrs/>
@@ -2,24 +2,18 @@
<CharString>
151 69 153 69 hstem
-1022 1494 vstem
-579 373 rmoveto
1 69 rlineto
-444 -69 hlineto
968 hmoveto
1 69 rlineto
-444 -69 hlineto
968 hmoveto
1 69 rlineto
-444 -69 hlineto
-607 -222 rmoveto
1 69 rlineto
-444 -69 hlineto
968 hmoveto
1 69 rlineto
-444 -69 hlineto
968 hmoveto
1 69 rlineto
-444 -69 hlineto
-578 442 rmoveto
-444 -69 443 hlineto
526 69 rmoveto
-444 -69 443 hlineto
526 69 rmoveto
-444 -69 443 hlineto
-1049 -153 rmoveto
-444 -69 443 hlineto
526 69 rmoveto
-444 -69 443 hlineto
526 69 rmoveto
-444 -69 443 hlineto
endchar
</CharString>
<Subrs/>
@@ -1,16 +1,13 @@
<Glyph name="equal_equal_equal.liga" lsb="-1022" width="550">
<CharString>
40 69 153 69 153 69 hstem
-1022 1494 cntrmask 11100000
471 484 rmoveto
1 69 rlineto
-1494 -69 hlineto
1493 -222 rmoveto
1 69 rlineto
-1494 -69 hlineto
1493 -222 rmoveto
1 69 rlineto
-1494 -69 hlineto
-1022 1494 vstem
472 553 rmoveto
-1494 -69 1493 hlineto
1 -153 rmoveto
-1494 -69 1493 hlineto
1 -153 rmoveto
-1494 -69 1493 hlineto
endchar
</CharString>
<Subrs/>
@@ -2,8 +2,8 @@
<CharString>
151 69 153 69 hstem
-1022 394 1019 74 vstem
138 602 rmoveto
-47 -58 124 -102 rlineto
91 544 rmoveto
124 -102 rlineto
-1237 -69 1321 hlineto
92 -76 rlineto
-10 vlineto
@@ -11,6 +11,7 @@
-1332 -69 1249 hlineto
-140 -116 45 -57 333 280 rlineto
69 vlineto
-327 275 rlineto
endchar
</CharString>
<Subrs/>
@@ -2,8 +2,8 @@
<CharString>
151 69 153 69 hstemhm
-472 937 -74 74 hintmask 11100000
138 602 rmoveto
-47 -58 124 -102 rlineto
91 544 rmoveto
124 -102 rlineto
-687 -69 771 hlineto
hintmask 11010000
92 -76 rlineto
@@ -13,6 +13,7 @@
-782 -69 699 hlineto
-140 -116 45 -57 333 280 rlineto
69 vlineto
-327 275 rlineto
endchar
</CharString>
<Subrs/>
@@ -2,8 +2,8 @@
<CharString>
151 69 153 69 hstemhm
-1022 1486 -688 75 235 75 hintmask 11011000
-149 297 rmoveto
299 248 -45 58 -191 -161 rlineto
150 545 rmoveto
-45 58 -191 -161 rlineto
hintmask 11100000
-936 -69 854 hlineto
hintmask 11011000
@@ -15,13 +15,15 @@
206 -173 46 57 rlineto
hintmask 11011000
-303 252 rlineto
310 hmoveto
10 vlineto
310 hmoveto
299 248 -45 58 -329 -277 rlineto
-69 vlineto
332 -279 rlineto
hintmask 11100000
46 57 rlineto
hintmask 11011000
-303 252 rlineto
endchar
</CharString>
<Subrs/>
@@ -0,0 +1,7 @@
<Glyph name="exclam.spacer" lsb="0" width="600">
<CharString>
endchar
</CharString>
<Subrs/>
<GlobalSubrs/>
</Glyph>
@@ -2,8 +2,7 @@
<CharString>
-189 915 -575 69 153 69 hstemhm
-472 944 -762 534 hintmask 00110000
76 373 rmoveto
395 hlineto
471 373 rmoveto
1 69 rlineto
-360 hlineto
hintmask 00101000
@@ -24,6 +23,7 @@
512 hlineto
1 69 rlineto
-477 hlineto
81 153 rlineto
endchar
</CharString>
<Subrs/>
@@ -1,24 +1,23 @@
<Glyph name="exclam_equal_equal.liga" lsb="-1022" width="550">
<CharString>
-189 915 -686 69 153 69 153 69 hstemhm
-1022 1494 -1012 534 cntrmask 01110000
hintmask 01111000
471 262 rmoveto
1 69 rlineto
-1022 1494 -1012 534 hintmask 00111000
472 331 rmoveto
-668 hlineto
80 153 rlineto
587 hlineto
1 69 rlineto
-552 hlineto
hintmask 01110100
hintmask 00110100
74 141 rlineto
hintmask 10000100
-69 32 rlineto
hintmask 01110100
hintmask 00110100
-91 -173 rlineto
-856 -69 820 hlineto
-80 -153 rlineto
-740 -69 703 hlineto
hintmask 01110100
-80 -153 rlineto
-623 -69 587 hlineto
-105 -200 rlineto
@@ -30,6 +29,7 @@
1 69 rlineto
-785 hlineto
80 153 rlineto
704 hlineto
endchar
</CharString>
<Subrs/>
@@ -0,0 +1,7 @@
<Glyph name="greater.spacer" lsb="0" width="600">
<CharString>
endchar
</CharString>
<Subrs/>
<GlobalSubrs/>
</Glyph>

Some files were not shown because too many files have changed in this diff Show More