commit a330e899b3be43466c7c052bb7c69020d097dbfc Author: kiliman Date: Sun Aug 13 19:23:23 2017 -0400 Initial import diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..57798ba --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3e2e84b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +node_modules/ diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..c0704c3 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible Node.js debug attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "program": "${workspaceRoot}\\index.js" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e0c790c --- /dev/null +++ b/README.md @@ -0,0 +1,44 @@ +# Operator Mono Ligatures + +This project will generate new OpenType fonts for *Operator Mono* that includes ligatures similar to +those found in the popular Fira Code font. + +![Ligature Sample](image/sample.js.png) + +![Ligature Sample](image/sample.html.png) + + +NOTE: Because *Operator Mono* is not a free font, you must have the original font files. This utility +will merge the ligature definitions into a copy of the original font. The new font family is named *Operator Mono Lig* so you can install it side-by-side with the original font. + +## Prerequisites +* The original *Operator Mono* font... of course. +* Install *fonttools* from https://github.com/fonttools/fonttools + * Install Python + * Run: `pip install fonttools` +* Node.js + +## How to Install + +Once all the prerequisites have been installed, clone this repo. + +From the command line, run: + +``` +npm install +``` + +Copy your *Operator Mono* OpenType files into the `original` folder. + +From the command line, run: + +``` +build +``` + +This will generate the new font files int the `build` folder. You can now install these fonts on your system. + + + + + diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..ddfa804 --- /dev/null +++ b/build.bat @@ -0,0 +1,15 @@ +@echo off + +del .\original\*.ttx +ttx .\original\OperatorMono-Medium.otf +ttx .\original\OperatorMono-MediumItalic.otf + +if not exist build\* mkdir build + +node index.js OperatorMono-Medium +node index.js OperatorMono-MediumItalic + +del /q .\build\*.otf + +ttx .\build\OperatorMonoLig-Medium.ttx +ttx .\build\OperatorMonoLig-MediumItalic.ttx \ No newline at end of file diff --git a/extract.bat b/extract.bat new file mode 100644 index 0000000..28ea853 --- /dev/null +++ b/extract.bat @@ -0,0 +1,4 @@ +@echo off + +node extract.js OperatorMonoLig-Medium +node extract.js OperatorMonoLig-MediumItalic diff --git a/extract.js b/extract.js new file mode 100644 index 0000000..68ce5f2 --- /dev/null +++ b/extract.js @@ -0,0 +1,136 @@ +const Promise = require('bluebird'); +const fs = Promise.promisifyAll(require('fs')); + +const xpath = require('xpath'); +const { DOMParser, XMLSerializer } = require('xmldom'); +const format = require('xml-formatter'); +let fontName; + +const regEx = /\.liga$/; +const regExBlankLines = /^(?=\n)$|^\s*/gm; +const regExWhitespace = /^\s+$/; +const NodeType = {}; +NodeType.TEXT_NODE = 3; + +async function main() { + fontName = process.argv[2]; + + const srcFileName = `./ligature_source/${fontName}.ttx`; + + console.log(`Reading file ${srcFileName}`); + const xml = await fs.readFileAsync(srcFileName, 'utf-8'); + const dom = new DOMParser().parseFromString(xml); + + await extractAndWrite('glyphs', extractGlyphs, dom); + await extractAndWrite('cmap', extractCmap, dom); + await extractAndWrite('classdef', extractClassDef, dom); + await extractAndWrite('hmtx', extractHmtx, dom); + await extractAndWrite('lookup', extractLookup, dom); + await extractAndWrite('charstrings', extractCharStrings, dom); + + console.log('Done'); +} + +async function extractAndWrite(name, func, dom) { + const newDom = func(dom); + console.log('Finished extracting ' + name); + + const fileName = `./ligature/${fontName}_${name}.xml`; + await fs.writeFileAsync(fileName, format(serialize(newDom))); + console.log('Finished writing ' + name); +} + +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\n') + .filter(s => /\S+/.test(s)) + .map(s => s.replace(/^\s+/g, '')) + .join('\n'); + + return node.ownerDocument.createTextNode(data); + } + return node; + }); + +const extractGlyphs = dom => { + const newDom = new DOMParser().parseFromString(''); + const glyphIds = xpath.select('/ttFont/GlyphOrder/GlyphID', dom); + + glyphIds + .filter(node => regEx.test(node.getAttribute('name'))) + .forEach(node => newDom.documentElement.appendChild(node)); + + return newDom; +}; + +const extractCmap = dom => { + const newDom = new DOMParser().parseFromString(''); + const cmap = xpath.select('/ttFont/cmap/cmap_format_4', dom); + + cmap.forEach(node => { + // for each cmap_format_4 node, need to copy map elements + // create and append cmap_format_4 node + const cmap4 = node.cloneNode(false); + newDom.documentElement.appendChild(cmap4); + + xpath + .select('map', node) + .filter(child => regEx.test(child.getAttribute('name'))) + .forEach(child => cmap4.appendChild(child)); + }); + return newDom; +}; + +const extractClassDef = dom => { + const newDom = new DOMParser().parseFromString(''); + const classDefs = xpath.select('/ttFont/GDEF/GlyphClassDef/ClassDef', dom); + + classDefs + .filter(node => regEx.test(node.getAttribute('glyph'))) + .forEach(node => newDom.documentElement.appendChild(node)); + + return newDom; +}; + +const extractHmtx = dom => { + const newDom = new DOMParser().parseFromString(''); + const mtx = xpath.select('/ttFont/hmtx/mtx', dom); + + mtx + .filter(node => regEx.test(node.getAttribute('name'))) + .forEach(node => newDom.documentElement.appendChild(node)); + + return newDom; +}; + +const extractLookup = dom => { + const newDom = new DOMParser().parseFromString(''); + const lookup = xpath.select( + '/ttFont/GSUB/LookupList/Lookup[@index="20"]', + dom, + true + ); + + newDom.documentElement.appendChild(lookup); + + return newDom; +}; + +const extractCharStrings = dom => { + const newDom = new DOMParser().parseFromString(''); + const charStrings = xpath.select( + '/ttFont/CFF/CFFFont/CharStrings/CharString', + dom + ); + + charStrings + .filter(node => regEx.test(node.getAttribute('name'))) + .forEach(node => newDom.documentElement.appendChild(node)); + + return newDom; +}; + +main(); diff --git a/images/sample.html.png b/images/sample.html.png new file mode 100644 index 0000000..921c217 Binary files /dev/null and b/images/sample.html.png differ diff --git a/images/sample.js.png b/images/sample.js.png new file mode 100644 index 0000000..aa0cbe1 Binary files /dev/null and b/images/sample.js.png differ diff --git a/index.js b/index.js new file mode 100644 index 0000000..38cb98b --- /dev/null +++ b/index.js @@ -0,0 +1,285 @@ +const Promise = require('bluebird'); +const fs = Promise.promisifyAll(require('fs')); + +const xpath = require('xpath'); +const { DOMParser, XMLSerializer } = require('xmldom'); +const format = require('xml-formatter'); +let fontName; +let ligFontName; + +const regEx = /\.liga$/; +const regExBlankLines = /^(?=\n)$|^\s*/gm; +const regExWhitespace = /^\s+$/; +const NodeType = {}; +NodeType.TEXT_NODE = 3; + +async function main() { + fontName = process.argv[2] || 'OperatorMono-MediumItalic'; + ligFontName = fontName.split('-').join('Lig-'); + + const srcFileName = `./original/${fontName}.ttx`; + const dstFileName = `./build/${ligFontName}.ttx`; + console.log(`Reading original font file ${srcFileName}`); + const xml = await fs.readFileAsync(srcFileName, 'utf-8'); + const dom = new DOMParser().parseFromString(xml); + + await processPatch('names', patchNames, dom); + await processPatch('glyphs', patchGlyphs, dom); + await processPatch('cmap', patchCmap, dom); + await processPatch('classdef', patchClassDef, dom); + await processPatch('hmtx', patchHmtx, dom); + await processPatch('lookup', patchLookup, dom); + await processPatch('charstrings', patchCharStrings, dom); + + //return; + console.log(`Writing ligature font file ${dstFileName}`); + await fs.writeFileAsync(dstFileName, format(serialize(dom))); + console.log('Done'); +} + +async function loadConfigAsync(name) { + const fileName = `./ligature/${ligFontName}_${name}.xml`; + const xml = await fs.readFileAsync(fileName, 'utf-8'); + return new DOMParser().parseFromString(xml); +} + +async function processPatch(name, patchFunc, dom) { + console.log(`Patching ${name}`); + await patchFunc(dom); +} + +async function patchNames(dom) { + const configDom = await loadConfigAsync('names'); + + const names = xpath.select('/name/namerecord', configDom); + const targetName = xpath.select('/ttFont/name', dom, true); + + names.forEach(node => { + const nameId = node.getAttribute('nameID'); + const platformId = node.getAttribute('platformID'); + + // search for namerecord in target dom and replace with this one or append node + const target = xpath.select( + `/ttFont/name/namerecord[@nameID="${nameId}" and @platformID="${platformId}"]`, + dom, + true + ); + if (target) { + target.parentNode.replaceChild(node, target); + } else { + targetName.appendChild(node); + } + }); +} + +async function patchGlyphs(dom) { + const configDom = await loadConfigAsync('glyphs'); + // get number of glyphs in target dom + const targetGlyphs = xpath.select('/ttFont/GlyphOrder', dom, true); + const glyphsCount = xpath.select('count(GlyphID)', targetGlyphs, true); + + let n = glyphsCount; + // get ligature glyphs + const glyphs = xpath.select('/GlyphOrder/GlyphID', configDom); + glyphs.forEach(node => { + node.setAttribute('id', n++); + targetGlyphs.appendChild(node); + }); + + // update glyph count + setAttribute(dom, '/ttFont/maxp/numGlyphs', 'value', n); +} + +async function patchCmap(dom) { + const configDom = await loadConfigAsync('cmap'); + const cmaps = xpath.select('/cmap/cmap_format_4', configDom); + + cmaps.forEach(node => { + const platformId = node.getAttribute('platformID'); + const platEncId = node.getAttribute('platEncID'); + + // search for cmap_format_4 in target dom + const target = xpath.select( + `/ttFont/cmap/cmap_format_4[@platformID="${platformId}" and @platEncID="${platEncId}"]`, + dom, + true + ); + if (target) { + // append all map elements to target cmap_format_4 + const maps = xpath.select('map', node); + maps.forEach(child => target.appendChild(child)); + } + }); +} + +async function patchClassDef(dom) { + const configDom = await loadConfigAsync('classdef'); + const glyphClassDef = xpath.select('/ttFont/GDEF/GlyphClassDef', dom, true); + + const classDefs = xpath.select('/GlyphClassDef/ClassDefs', configDom); + classDefs.forEach(node => glyphClassDef.appendChild(node)); +} + +async function patchHmtx(dom) { + const hmtxDom = await loadConfigAsync('hmtx'); + const targetHmtx = xpath.select('/ttFont/hmtx', dom, true); + + const mtx = xpath.select('/hmtx/mtx', hmtxDom); + mtx.forEach(node => targetHmtx.appendChild(node)); + + const mtxCount = xpath.select('count(/ttFont/hmtx/mtx)', dom, true); + setAttribute(dom, '/ttFont/hhea/numberOfHMetrics', 'value', mtxCount); + + const configDom = await loadConfigAsync('config'); + copyConfigAttribute(dom, configDom, '/ttFont/head/xMin', 'value'); + copyConfigAttribute(dom, configDom, '/ttFont/head/yMin', 'value'); + copyConfigAttribute(dom, configDom, '/ttFont/head/xMax', 'value'); + copyConfigAttribute(dom, configDom, '/ttFont/head/yMax', 'value'); + copyConfigAttribute(dom, configDom, '/ttFont/hhea/advanceWidthMax', 'value'); + copyConfigAttribute(dom, configDom, '/ttFont/hhea/xMaxExtent', 'value'); + copyConfigAttribute(dom, configDom, '/ttFont/CFF/CFFFont/FontBBox', 'value'); + copyConfigAttribute( + dom, + configDom, + '/ttFont/CFF/CFFFont/Private/nominalWidthX', + 'value' + ); +} + +async function patchLookup(dom) { + const configDom = await loadConfigAsync('lookup'); + const featureList = xpath.select('/ttFont/GSUB/FeatureList', dom, true); + + // look for feature with FeatureTag liga + let featureRecord; + let featureTag; + let feature; + let featureTags = xpath.select( + '/ttFont/GSUB/FeatureList/FeatureRecord/FeatureTag[@value="liga"]', + dom + ); + + if (featureTags.length) { + featureTag = featureTags[0]; + featureRecord = featureTag.parentNode; + feature = xpath.select('Feature', featureRecord, true); + } else { + // need to add feature to FeatureList + const featuresCount = xpath.select( + 'count(/ttFont/GSUB/FeatureList/FeatureRecord)', + dom, + true + ); + + featureRecord = dom.createElement('FeatureRecord'); + featureRecord.setAttribute('index', featuresCount); + featureTag = dom.createElement('FeatureTag'); + featureTag.setAttribute('value', 'liga'); + feature = dom.createElement('Feature'); + featureRecord.appendChild(featureTag); + featureRecord.appendChild(feature); + featureList.appendChild(featureRecord); + } + let lookupListIndex = xpath.select( + 'LookupListIndex[@value="20"]', + feature, + true + ); + if (!lookupListIndex) { + const count = xpath.select('count(LookupListIndex)', feature, true); + lookupListIndex = dom.createElement('LookupListIndex'); + lookupListIndex.setAttribute('index', count); + lookupListIndex.setAttribute('value', '20'); + feature.appendChild(lookupListIndex); + } + + // helper function for adding feature to ScriptRecord + const addFeature = (scriptRecord, featureRecord, lang) => { + if (!lang) return; + const index = featureRecord.getAttribute('index'); + if (xpath.select(`FeatureIndex[@value="${index}"]`, lang, true)) return; + + const count = xpath.select('count(FeatureIndex)', lang, true); + const featureIndex = dom.createElement('FeatureIndex'); + featureIndex.setAttribute('index', count); + featureIndex.setAttribute('value', index); + lang.appendChild(featureIndex); + }; + + // nead to add feature to ScriptList + const scriptList = xpath.select('/ttFont/GSUB/ScriptList', dom, true); + const scriptRecords = xpath.select('ScriptRecord', scriptList); + scriptRecords.forEach(node => { + // check for feature in DefaultLangSys + addFeature( + node, + featureRecord, + xpath.select('Script/DefaultLangSys', node, true) + ); + // add features to any other languages + xpath + .select('Script/LangSysRecord/LangSys', node) + .forEach(lang => addFeature(node, featureRecord, lang)); + }); + + // finally add LigatureSubst to Lookup index=20 + const lookupList = xpath.select('/ttFont/GSUB/LookupList', dom, true); + const newLookup = xpath.select('/LookupList/Lookup', configDom, true); + + let lookup = xpath.select( + '/ttFont/GSUB/LookupList/Lookup[@index="20"]', + dom, + true + ); + if (!lookup) { + lookupList.appendChild(newLookup); + } else { + lookupList.replaceChild(newLookup, lookup); + } +} + +async function patchCharStrings(dom) { + const configDom = await loadConfigAsync('charstrings'); + const nameDom = await loadConfigAsync('names'); + + const cffFont = xpath.select('/ttFont/CFF/CFFFont', dom, true); + + cffFont.setAttribute('name', ligFontName); + // get names from name config + const fullName = nameDom.documentElement.getAttribute('fullName'); + const familyName = nameDom.documentElement.getAttribute('familyName'); + setAttribute(cffFont, 'FullName', 'value', fullName); + setAttribute(cffFont, 'FamilyName', 'value', familyName); + + const targetCharStrings = xpath.select('CharStrings', cffFont, true); + + const charStrings = xpath.select('/CharStrings/CharString', configDom); + charStrings.forEach(node => targetCharStrings.appendChild(node)); +} + +const setAttribute = (parent, path, name, value) => { + var node = xpath.select(path, parent, true); + node.setAttribute(name, value); +}; + +const copyConfigAttribute = (dom, configDom, path, name) => { + const value = xpath.select(path, configDom, true).getAttribute(name); + setAttribute(dom, path, name, value); +}; + +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\n') + .filter(s => /\S+/.test(s)) + .map(s => s.replace(/^\s+/g, '')) + .join('\n'); + + return node.ownerDocument.createTextNode(data); + } + return node; + }); + +main(); diff --git a/ligature/OperatorMonoLig-MediumItalic_charstrings.xml b/ligature/OperatorMonoLig-MediumItalic_charstrings.xml new file mode 100644 index 0000000..26b9646 --- /dev/null +++ b/ligature/OperatorMonoLig-MediumItalic_charstrings.xml @@ -0,0 +1,130 @@ + + + 107 385.31746 184.40079 rmoveto +4.36612 -7.70291 4.56085 -7.80026 4.75555 -7.89761 -49.33333 -50 -44 -25 -38.66667 0 -34.66667 0 -17.33333 19.66667 0 39.33333 0 52 36 61.33333 72 70.66667 11.63492 -43.63095 20.77249 -48.19974 29.91005 -52.76852 rrcurveto +358.73317 -8.25699 rmoveto +2.9023 -5.00752 2.98312 -5.04793 3.06395 -5.08835 -49.33333 -50 -44 -25 -38.66667 0 -34.66667 0 -17.33333 19.66667 0 39.33333 0 52 36 61.33333 72 70.66667 12.23906 -45.8965 22.35022 -50.95206 32.46135 -56.00764 rrcurveto +143.94937 -196.1438 rmoveto +89 65 rlineto +-42 46 -35.66667 44 -29.33333 42 38 46.66667 39.33333 58 40.66667 69.33333 rrcurveto +-88 31 rlineto +-24.66667 -48.66667 -25.66666 -44 -26.66667 -39.33333 -28.66667 52 -19.33333 51.33333 -10 50.66667 31.33333 29.33333 24.33334 30 17.33333 30.66667 17.33333 30.66667 8.66667 26.33333 0 22 0 22 -6.83333 16.66667 -13.66667 11.33333 -13.66667 11.33333 -17.83333 5.66667 -22 0 rrcurveto +-32.66667 0 -30.16666 -18.16667 -27.66667 -36.33333 -27.66667 -36.33333 -13.83333 -45.5 0 -54.66667 0 -12 0.33333 -9.33333 0.66667 -6.66667 -85.33333 -68.66667 -57.29137 -67.4156 -29.24939 -66.16457 -42.08394 74.16457 -25.3753 61.74895 -8.66667 49.33333 31.33333 29.33333 24.33334 30 17.33333 30.66667 rrcurveto +17.33333 30.66667 8.66667 26.33333 0 22 0 22 -6.83333 16.66667 -13.66667 11.33333 -13.66667 11.33333 -17.83333 5.66667 -22 0 -32.66667 0 -30.16666 -18.16667 -27.66667 -36.33333 -27.66667 -36.33333 -13.83333 -45.5 0 -54.66667 0 -12 0.33333 -9.33333 0.66667 -6.66667 rrcurveto +-129.33333 -104 -64.66667 -100.66667 0 -97.33333 0 -39.33333 10.66667 -31.16667 21.33333 -23 21.33333 -23 30.33334 -11.5 39.33333 0 65.33333 0 69.33334 34.66667 73.33333 69.33333 rrcurveto +33 -47 rlineto +30.66667 -38.66667 37.33333 -19.33333 44 0 64.6701 0 69.66667 35 74.66322 70 28 -39.33333 30.66667 -38.33334 33.33333 -37.33333 rrcurveto +endchar + + + 107 442.49721 378 rmoveto +65.50279 335 -102 -3 -174 -892 101 0 rlineto +433 892 rmoveto +-64.76233 -332 -109.23767 -560 101 0 175 895 rlineto +endchar + + + 107 1051 456 rmoveto +-940 0 -19 -91 941 0 rlineto +-24 -129 rmoveto +-941 0 -19 -91 941 0 rlineto +endchar + + + 657 1601 527 rmoveto +-1450 0 -19 -91 1451 0 rlineto +-64 -240 rmoveto +-1451 0 -19 -91 1451 0 rlineto +-1408 163 rmoveto +1451 0 18 91 -1450 0 rlineto +endchar + + + 657 1188 -22 rmoveto +373 251 17 91 -281 291 -74 -72 83.33333 -83 -1195.33333 0 -19 -91 1305.69879 0 75.30121 -75 -2 -11 -65.2963 -43 -1337.7037 0 -19 -91 1218.51852 0 -124.51852 -82 rlineto +endchar + + + 107 652 -22 rmoveto +373 251 17 91 -281 291 -74 -72 83.33333 -83 -659.33333 0 -19 -91 769.69879 0 75.30121 -75 -2 -11 -65.2963 -43 -801.7037 0 -19 -91 682.51852 0 -124.51852 -82 rlineto +endchar + + + 107 1009 236 rmoveto +-428 0 88 129 364 0 18 91 -320 0 159 234 -89 36 -184 -270 -506 0 -19 -91 462 0 -88 -129 -398 0 -19 -91 355 0 rlineto +-208 -305 96 -28 227 333 471 0 rlineto +endchar + + + 657 1022 726 rmoveto +-135.886 -199 -735.114 0 -19 -91 691.97517 0 -52.57901 -77 -660.39616 0 -19 -91 617.25734 0 -49.16478 -72 -592.09254 0 -19 -91 548.95372 0 -180.95372 -265 96 -28 199.56036 293 rlineto +787.43964 0 19 91 -744.46014 0 49.03873 72 719.42142 0 18 91 -675.44191 0 52.4442 77 644.99773 0 18 91 -601.01822 0 111.01822 163 rlineto +endchar + + + 107 247 -32 rmoveto +30 -84 562 271 18 103 rlineto +-569 -161 rmoveto +553 261 17 91 -461 291 -74 -72 430 -249 -2 -11 -508 -226 rlineto +endchar + + + 107 628 -22 rmoveto +373 251 17 91 -281 291 -74 -72 195.78313 -195 -758.78313 0 -18 -93 786.48148 0 -285.48148 -188 rlineto +endchar + + + 107 497 251 rmoveto +17 93 -301 0 -18 -93 rlineto +409 93 rmoveto +-18 -93 302 0 17 93 rlineto +endchar + + + 657 1178 -22 rmoveto +373 251 17 91 -281 291 -74 -72 196 -195 -1309 0 -18 -93 1336 0 -285 -188 rlineto +endchar + + + 107 256 171 rmoveto +481 -299 66 67 -527 329 rlineto +563 467 rmoveto +-534 -295 -16 -91 440 -249 74 72 -409 208 2 10 488 261 rlineto +endchar + + + 657 1592 456 rmoveto +-1183.31798 0 107.31798 71 -45 84 -374 -251 -16 -91 280 -291 74 72 -94.62 95 1190.62 0 19 91 -1300.256 0 -63.744 64 2 10 83.13364 55 1302.86636 0 rlineto +endchar + + + 1207 2119 344 rmoveto +-1169 0 -18 -93 1170 0 rlineto +-1631 360 rmoveto +-374 -251 -16 -91 280 -291 74 72 -200 201 369 0 17 93 -382 0 277 183 rlineto +213 -282 rmoveto +72 hlineto +4 17.33333 20.16667 73.16667 36.33333 129 36.33333 129 19.83334 70.83333 3.33333 12.66667 rrcurveto +-140 hlineto +-2.66667 -14 -8.5 -71.33333 -14.33333 -128.66667 -14.33333 -128.66667 -8.83334 -72.66666 -3.33333 -16.66667 rrcurveto +77 -114 rmoveto +-135 0 -26 -131 135 0 rlineto +endchar + + + 107 472 611 rmoveto +-374 -251 -16 -91 280 -291 74 72 -200.196 201 765.196 0 17 93 -777.60829 0 276.60829 183 rlineto +endchar + + + 657 472 611 rmoveto +-374 -251 -16 -91 280 -291 74 72 -200.196 201 1315.196 0 17 93 -1327.60829 0 276.60829 183 rlineto +endchar + + + 107 981 252 rmoveto +19 91 -173 0 35 179 -97 0 -35 -179 -170 0 -1 0 -172 0 35 179 -97 0 -35 -179 -171 0 -19 -91 173 0 -35 -179 rlineto +97 0 35 179 170 0 1 0 172 0 -35 -179 97 0 35 179 rlineto +endchar + + \ No newline at end of file diff --git a/ligature/OperatorMonoLig-MediumItalic_classdef.xml b/ligature/OperatorMonoLig-MediumItalic_classdef.xml new file mode 100644 index 0000000..1fbbfbe --- /dev/null +++ b/ligature/OperatorMonoLig-MediumItalic_classdef.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ligature/OperatorMonoLig-MediumItalic_cmap.xml b/ligature/OperatorMonoLig-MediumItalic_cmap.xml new file mode 100644 index 0000000..3941959 --- /dev/null +++ b/ligature/OperatorMonoLig-MediumItalic_cmap.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ligature/OperatorMonoLig-MediumItalic_config.xml b/ligature/OperatorMonoLig-MediumItalic_config.xml new file mode 100644 index 0000000..7ac5475 --- /dev/null +++ b/ligature/OperatorMonoLig-MediumItalic_config.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ligature/OperatorMonoLig-MediumItalic_glyphs.xml b/ligature/OperatorMonoLig-MediumItalic_glyphs.xml new file mode 100644 index 0000000..6dee8e6 --- /dev/null +++ b/ligature/OperatorMonoLig-MediumItalic_glyphs.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ligature/OperatorMonoLig-MediumItalic_hmtx.xml b/ligature/OperatorMonoLig-MediumItalic_hmtx.xml new file mode 100644 index 0000000..36b4c36 --- /dev/null +++ b/ligature/OperatorMonoLig-MediumItalic_hmtx.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ligature/OperatorMonoLig-MediumItalic_lookup.xml b/ligature/OperatorMonoLig-MediumItalic_lookup.xml new file mode 100644 index 0000000..e862fc7 --- /dev/null +++ b/ligature/OperatorMonoLig-MediumItalic_lookup.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ligature/OperatorMonoLig-MediumItalic_names.xml b/ligature/OperatorMonoLig-MediumItalic_names.xml new file mode 100644 index 0000000..e95a238 --- /dev/null +++ b/ligature/OperatorMonoLig-MediumItalic_names.xml @@ -0,0 +1,45 @@ + + + + Operator Mono Lig + + + Medium Italic + + + H&Co: Operator Mono Lig Medium Italic: 1.200 + + + Operator Mono Lig Medium Italic + + + OperatorMonoLig-MediumItalic + + + Operator Mono Lig + + + Medium Italic + + + Operator Mono Lig Medium + + + Italic + + + H&Co: Operator Mono Lig Medium Italic: 1.200 + + + Operator Mono Lig Medium Italic + + + OperatorMonoLig-MediumItalic + + + Operator Mono Lig + + + Medium Italic + + \ No newline at end of file diff --git a/ligature/OperatorMonoLig-Medium_charstrings.xml b/ligature/OperatorMonoLig-Medium_charstrings.xml new file mode 100644 index 0000000..121fd1a --- /dev/null +++ b/ligature/OperatorMonoLig-Medium_charstrings.xml @@ -0,0 +1,139 @@ + + + 107 270.7619 245 rmoveto +21.46031 -26 57.77777 -70 rlineto +-30.66667 -48 -33.66666 -24 -36.66667 0 -22.66667 0 -17.5 7.5 -12.33333 15 -12.33333 15 -6.16667 19.16667 0 23.33333 0 43.33333 22.66667 39.33334 45.33333 35.33333 rrcurveto +494.49207 -43 rmoveto +20.63492 -25 47.87302 -58 rlineto +-30.66667 -48 -33.66666 -24 -36.66667 0 -22.66667 0 -17.5 7.5 -12.33333 15 -12.33333 15 -6.16667 19.16667 0 23.33333 0 43.33333 22.66667 39.33334 45.33333 35.33333 rrcurveto +191 256 rmoveto +-7 102 rlineto +-102.81816 1.3353 -73.66667 -18 -44.51517 -37.3353 -40 -33.54839 -20 -40.66667 0 -47.78494 0 -35.33333 18.66667 -43 37.33333 -50.66667 -88.66667 -55.33333 -44.33333 -65 0 -74.66667 0 -12 1 -11.66667 2 -11.33333 -18 22 -23.66667 29.33333 -29.33333 36.66667 rrcurveto +36 66.66667 27.66667 69.66666 19.33333 72.66667 rrcurveto +-94 11 rlineto +-9.33333 -47.33333 -15 -51.33334 -20.66667 -55.33333 -6.66667 8 -18.16666 21.16667 -29.66667 34.33333 -29.66667 34.33333 -22.66666 28.33334 -15.66667 22.33333 -15.66667 22.33333 -7.83333 19.5 0 16.66667 0 26.66667 12.66667 19.5 25.33333 12.33333 25.33333 12.33333 46 4.5 66.66667 -3.33333 rrcurveto +-7 102 rlineto +-102.81816 1.3353 -73.66667 -18 -44.51517 -37.3353 -40 -33.54839 -20 -40.66667 0 -47.78494 0 -35.33333 18.66667 -43 37.33333 -50.66667 -88.66667 -55.33333 -44.33333 -65 0 -74.66667 0 -43.33333 13.16667 -35.16667 26.33333 -27 26.33333 -27 37.83334 -13.5 49.33333 0 rrcurveto +69.33333 0 58.33334 33.33333 47.33333 66.66667 46.66667 -64.66667 94.66666 -33.33333 142.66667 -2 69.33333 0 58.33334 33.33333 47.33333 66.66667 19.33333 -24 26 -33.66667 32.66667 -43.33333 rrcurveto +91 69 rlineto +-12.66667 16 -35.33333 43.66667 -58 71.33333 36 66.66667 27.66667 69.66666 19.33333 72.66667 rrcurveto +-94 11 rlineto +-9.33333 -47.33333 -15 -51.33334 -20.66667 -55.33333 -6.66667 8 -18.16666 21.16667 -29.66667 34.33333 -29.66667 34.33333 -22.66666 28.33334 -15.66667 22.33333 -15.66667 22.33333 -7.83333 19.5 0 16.66667 0 26.66667 12.66667 19.5 25.33333 12.33333 25.33333 12.33333 46 4.5 66.66667 -3.33333 rrcurveto +endchar + + + 107 672 709 rmoveto +-892 105 901 vlineto +-454 -9 rmoveto +-892 105 901 vlineto +410 -1418 rmoveto +0 vmoveto +endchar + + + 107 1028 458 rmoveto +-956 -2 0 -94 956 2 rlineto +-126 vmoveto +-956 -2 0 -94 956 2 rlineto +endchar + + + 657 72 526 rmoveto +0 -94 1506 2 0 94 rlineto +-331 vmoveto +-1506 -2 0 -94 1506 2 rlineto +-1506 159 rmoveto +1506 2 0 94 -1506 -2 rlineto +endchar + + + 657 1245 -20 rmoveto +333 273 0 93 -328 271 -62 -80 99 -79 -1215 -2 0 -94 1332 2 74 -59 0 -11 -70 -56 -1336 -2 0 -94 1219 2 -106 -86 rlineto +endchar + + + 107 695 -20 rmoveto +333 273 0 93 -328 271 -62 -80 99 -79 -665 -2 0 -94 782 2 74 -59 0 -11 -70 -56 -786 -2 0 -94 669 2 -106 -86 rlineto +endchar + + + 107 1028 238 rmoveto +-457 -1 65 126 392 1 0 94 -344 -1 121 238 -96 46 -145 -284 -492 -1 0 -94 445 1 -65 -126 -380 -1 0 -94 333 1 rlineto +-153 -300 96 -43 175 343 505 1 rlineto +endchar + + + 657 969 741 rmoveto +-109 -214 -788 -1 0 -94 740 1 -38 -76 -702 -1 0 -94 654 1 -34 -67 -620 -1 0 -94 572 1 -132 -259 96 -43 154 302 rlineto +816 1 0 94 -768 -1 34 67 734 1 0 94 -686 -1 39 76 647 1 0 94 -599 -1 86 168 rlineto +endchar + + + 107 308 -101 rmoveto +534 262 -2 96 -583 -292 rlineto +60 131 rmoveto +523 257 0 126 -518 254 -62 -80 480 -232 0 -11 -483 -236 rlineto +endchar + + + 107 695 -24 rmoveto +333 273 0 93 -328 271 -62 -80 235 -188 -801 0 0 -95 806 0 -243 -196 rlineto +endchar + + + 107 910 345 rmoveto +-320 -95 312 hlineto +-392 95 rmoveto +-320 -95 312 hlineto +endchar + + + 657 1245 -24 rmoveto +333 273 0 93 -328 271 -62 -80 235 -188 -1351 0 0 -95 1356 0 -243 -196 rlineto +endchar + + + 107 791 -101 rmoveto +-534 262 2 96 583 -292 rlineto +-60 131 rmoveto +-523 257 0 126 518 254 62 -80 -480 -232 0 -11 483 -236 rlineto +endchar + + + 657 405 -20 rmoveto +-333 273 0 93 328 271 62 -80 -99 -79 1215 -2 0 -94 -1332 2 -74 -59 0 -11 70 -56 1336 -2 0 -94 -1219 2 106 -86 rlineto +endchar + + + 1207 -98 852 rmoveto +1025 -507 rmoveto +-9 -95 1194 0 8 95 rlineto +-1502 hmoveto +-383.28206 0 236.28206 190 -60 79 -331 -272 0 -93 329 -273 63 80 -242.08546 194 380.08546 0 rlineto +120 -5 rmoveto +74 hlineto +0.66667 15.33333 6.66666 72.33334 12.66667 129.33333 12.66667 129.33333 6.66666 71.66667 0.66667 14 rrcurveto +-142 hlineto +0 -14 4.66667 -71.5 9.33333 -129 9.33333 -129 4.66667 -72.5 0 -16 rrcurveto +105 -114 rmoveto +-144 0 -3 -131 143 0 rlineto +endchar + + + 107 405 -24 rmoveto +-333 273 0 93 328 271 62 -80 -235 -188 801 0 0 -95 -806 0 243 -196 rlineto +endchar + + + 657 405 -24 rmoveto +-333 273 0 93 328 271 62 -80 -235 -188 1351 0 0 -95 -1356 0 243 -196 rlineto +endchar + + + 107 983 251 rmoveto +93 -168 178 -99 -178 -163 vlineto +-6 0 -162 0 0 178 -99 0 0 -178 -169 0 0 -93 169 0 0 -178 99 0 0 178 162 0 6 0 163 0 0 -178 rlineto +99 178 hlineto +endchar + + \ No newline at end of file diff --git a/ligature/OperatorMonoLig-Medium_classdef.xml b/ligature/OperatorMonoLig-Medium_classdef.xml new file mode 100644 index 0000000..e882b44 --- /dev/null +++ b/ligature/OperatorMonoLig-Medium_classdef.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ligature/OperatorMonoLig-Medium_cmap.xml b/ligature/OperatorMonoLig-Medium_cmap.xml new file mode 100644 index 0000000..3941959 --- /dev/null +++ b/ligature/OperatorMonoLig-Medium_cmap.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ligature/OperatorMonoLig-Medium_config.xml b/ligature/OperatorMonoLig-Medium_config.xml new file mode 100644 index 0000000..9bc08fe --- /dev/null +++ b/ligature/OperatorMonoLig-Medium_config.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ligature/OperatorMonoLig-Medium_glyphs.xml b/ligature/OperatorMonoLig-Medium_glyphs.xml new file mode 100644 index 0000000..6dee8e6 --- /dev/null +++ b/ligature/OperatorMonoLig-Medium_glyphs.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ligature/OperatorMonoLig-Medium_hmtx.xml b/ligature/OperatorMonoLig-Medium_hmtx.xml new file mode 100644 index 0000000..3a50f38 --- /dev/null +++ b/ligature/OperatorMonoLig-Medium_hmtx.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ligature/OperatorMonoLig-Medium_lookup.xml b/ligature/OperatorMonoLig-Medium_lookup.xml new file mode 100644 index 0000000..32b33b1 --- /dev/null +++ b/ligature/OperatorMonoLig-Medium_lookup.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ligature/OperatorMonoLig-Medium_names.xml b/ligature/OperatorMonoLig-Medium_names.xml new file mode 100644 index 0000000..f98a22b --- /dev/null +++ b/ligature/OperatorMonoLig-Medium_names.xml @@ -0,0 +1,45 @@ + + + + Operator Mono Lig + + + Medium + + + H&Co: Operator Mono Lig Medium: 1.200 + + + Operator Mono Lig Medium + + + OperatorMonoLig-Medium + + + Operator Mono Lig + + + Medium + + + Operator Mono Lig Medium + + + Regular + + + H&Co: Operator Mono Lig Medium: 1.200 + + + Operator Mono Lig Medium + + + OperatorMonoLig-Medium + + + Operator Mono Lig + + + Medium + + \ No newline at end of file diff --git a/original/.gitignore b/original/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/original/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..16b30c5 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,52 @@ +{ + "name": "operator-mono-lig", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "bluebird": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", + "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=" + }, + "debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "xml-formatter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml-formatter/-/xml-formatter-1.0.1.tgz", + "integrity": "sha1-OAgz3dC86iwJht7+u6cfhDhPNT0=", + "requires": { + "xml-parser-xo": "2.1.3" + } + }, + "xml-parser-xo": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/xml-parser-xo/-/xml-parser-xo-2.1.3.tgz", + "integrity": "sha1-TqjrhW36TddcSrVLJRVY3grcHGE=", + "requires": { + "debug": "2.6.8" + } + }, + "xmldom": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", + "integrity": "sha1-1QH5ezvbQDr4757MIFcxh6rawOk=" + }, + "xpath": { + "version": "0.0.24", + "resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.24.tgz", + "integrity": "sha1-Gt4WLhzFI8jTn8fQavwW6iFvKfs=" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..75fe6bc --- /dev/null +++ b/package.json @@ -0,0 +1,17 @@ +{ + "name": "operator-mono-lig", + "version": "1.0.0", + "description": "Patch Operator Mono font to include ligatures", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "kiliman@gmail.com", + "license": "ISC", + "dependencies": { + "bluebird": "^3.5.0", + "xml-formatter": "^1.0.1", + "xmldom": "^0.1.27", + "xpath": "0.0.24" + } +}