From 28eb8b58e5828bc328ff7dd57701d1f4501f03c9 Mon Sep 17 00:00:00 2001 From: Kiliman Date: Wed, 17 Apr 2019 14:58:08 -0400 Subject: [PATCH] Add support for non-ligature glyphs --- extract.js | 13 ++++++++++--- gsub.js | 2 +- index.js | 44 ++++++++++++++++++++++++++++---------------- 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/extract.js b/extract.js index f57fb39..d3fd211 100644 --- a/extract.js +++ b/extract.js @@ -10,7 +10,7 @@ const hash = require('hash.js'); let fontName; -const regEx = /^LIG$|\.liga$/; +const regEx = /^LIG$|uni(E0A0|E0B0|E0B2)|\.liga$/; const NodeType = {}; NodeType.TEXT_NODE = 3; @@ -87,6 +87,7 @@ const extractFromPath = (path, dom) => { }; const extractCharStrings = dom => { + const cmap = xpath.select('/ttfont/cmap/cmap_format_4', dom); const charStrings = xpath.select( '/ttFont/CFF/CFFFont/CharStrings/CharString', dom @@ -94,15 +95,21 @@ const extractCharStrings = dom => { charStrings .filter(node => regEx.test(node.getAttribute('name'))) - .forEach(node => writeGlyphData(dom, node)); + .forEach(node => writeGlyphData(dom, node, cmap)); console.log('Finished writing charstrings'); }; -const writeGlyphData = (dom, node) => { +const writeGlyphData = (dom, node, cmap) => { const newDom = new DOMParser().parseFromString('').documentElement; const name = node.getAttribute('name'); newDom.setAttribute('name', name); + // get map and set code + const map = xpath.select(`/ttFont/cmap/cmap_format_4/map[@name="${name}"]`, dom, true); + if (map) { + newDom.setAttribute('code', map.getAttribute('code')); + } + // get mtx const mtx = xpath.select(`/ttFont/hmtx/mtx[@name="${name}"]`, dom, true); newDom.setAttribute('lsb', mtx.getAttribute('lsb')); diff --git a/gsub.js b/gsub.js index d8a0c78..a97c3aa 100644 --- a/gsub.js +++ b/gsub.js @@ -15,7 +15,7 @@ let chainIndex = 0; const substLookupMap = {}; const buildGsubTables = (_dom, ligature) => { - const glyphs = ligature.name.split('_'); + const glyphs = ligature.name.replace(/\.liga$/, '').split('_'); dom = _dom; gsubDom = xpath.select('ttFont/GSUB', dom, true); diff --git a/index.js b/index.js index ba79345..249c618 100644 --- a/index.js +++ b/index.js @@ -46,14 +46,15 @@ const buildFont = profile => { const ligatures = sortLigatures( fs .readdirSync(`./ligature/${ligFontName}/glyphs`) - .filter(file => file != 'LIG.xml') - .map(file => file.replace('.liga.xml', '')) + .filter(file => /\.xml$/.test(file)) + .map(file => file.replace('.xml', '')) ) - .filter(name => !/\d+$/.test(name)) // skip alternates (ends with .#) + .filter(name => !/\d+\.liga$/.test(name)) // skip alternates (ends with .#) .filter(name => filterLigatures(name, profile.ligatures)) .map(name => mapLigatures(name, profile.ligatures)); - const ligaturesWithLIG = [...ligatures, { name: 'LIG', glyph: 'LIG' }]; + const ligaturesWithLIG = ligatures; + //[...ligatures, { name: 'LIG', glyph: 'LIG' }]; processPatch('names', patchNames, dom, ligatures, profile); processPatch('glyphs', patchGlyphs, dom, ligaturesWithLIG); @@ -118,7 +119,7 @@ const filterLigatures = (name, ligatures) => { const mapLigatures = (name, ligatures) => { // return { ligature, glyph } - let entry = { name, glyph: name + '.liga' }; + let entry = { name, glyph: name }; ligatures.forEach(ligature => { const n = ligature.indexOf('='); if (n > 0 && ligature.substr(0, n) === name) { @@ -186,13 +187,13 @@ const patchNames = (dom, ligatures, profile) => { const [name, style] = names.fontName.split('-'); const [familyStyle, fullNameStyleTry] = names.fontStyle.split(' '); - let fullNameStyleTemp + let fullNameStyleTemp; if (fullNameStyleTry) { fullNameStyleTemp = fullNameStyleTry; } else { - fullNameStyleTemp = ""; + fullNameStyleTemp = ''; } - + const fullNameStyle = fullNameStyleTemp; const fontName = `${name}${profile.suffixWithLeadingHyphen}-${style}`; const familyNamePlat = `${names.familyName}${profile.suffixWithLeadingSpace}`; @@ -254,10 +255,12 @@ const patchGlyphs = (dom, ligatures) => { }; const patchGsub = (dom, ligatures) => { - ligatures.forEach(ligature => { - // build gsub tables - gsub.buildGsubTables(dom, ligature); - }); + ligatures + .filter(ligature => /_/.test(ligature.glyph)) + .forEach(ligature => { + // build gsub tables + gsub.buildGsubTables(dom, ligature); + }); gsub.finalizeGsubTables(); }; @@ -285,7 +288,7 @@ const patchCharStrings = (dom, ligatures) => { // patch CFFFont const cffFont = xpath.select('/ttFont/CFF/CFFFont', dom, true); const targetHmtx = xpath.select('/ttFont/hmtx', dom, true); - + const targetCmaps = xpath.select('/ttFont/cmap/cmap_format_4', dom); const targetCharStrings = xpath.select('CharStrings', cffFont, true); const targetSubrs = xpath.select( '/ttFont/CFF/CFFFont/Private/Subrs', @@ -297,9 +300,7 @@ const patchCharStrings = (dom, ligatures) => { ligatures.forEach(ligature => { console.log( `* ${ligature.name}${ - ligature.name + '.liga' === ligature.glyph || ligature.name === 'LIG' - ? '' - : ' => ' + ligature.glyph + ligature.name === ligature.glyph ? '' : ' => ' + ligature.glyph }` ); const glyphDom = loadXml(`glyphs/${ligature.glyph}`).documentElement; @@ -325,6 +326,17 @@ const patchCharStrings = (dom, ligatures) => { lsb: glyphDom.getAttribute('lsb') }) ); + const code = glyphDom.getAttribute('code'); + if (code) { + Array.from(targetCmaps).forEach(node => { + node.appendChild( + createElementWithAttributes('map', { + code, + name: ligature.glyph + }) + ); + }); + } }); };