mirror of
https://github.com/kiliman/operator-mono-lig.git
synced 2026-08-12 02:10:52 +02:00
🪓 Add hack for italics by removing existing GSUB tables
This commit is contained in:
@@ -3,19 +3,25 @@ setlocal
|
|||||||
|
|
||||||
if not exist .\build\* mkdir build
|
if not exist .\build\* mkdir build
|
||||||
|
|
||||||
|
set flags=
|
||||||
|
if "%1"=="--italics-hack" (
|
||||||
|
set flags=%1
|
||||||
|
shift
|
||||||
|
)
|
||||||
rem only build passed in font
|
rem only build passed in font
|
||||||
if not "%1%"=="" (
|
if not "%1"=="" (
|
||||||
call :build_font %1
|
call :build_font %1 %flags%
|
||||||
exit /b
|
exit /b
|
||||||
)
|
)
|
||||||
|
|
||||||
rem build all fonts
|
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
|
exit /b
|
||||||
|
|
||||||
|
|
||||||
:build_font
|
:build_font
|
||||||
set lig=%1
|
set lig=%1
|
||||||
|
set flags=%2
|
||||||
set otf=%lig:Lig-=-%
|
set otf=%lig:Lig-=-%
|
||||||
|
|
||||||
if not exist .\original\%otf%.otf exit /b
|
if not exist .\original\%otf%.otf exit /b
|
||||||
@@ -23,6 +29,6 @@ if not exist .\ligature\%lig%\glyphs\* exit /b
|
|||||||
|
|
||||||
@echo Building %lig%
|
@echo Building %lig%
|
||||||
ttx -f .\original\%otf%.otf
|
ttx -f .\original\%otf%.otf
|
||||||
node index.js %otf%
|
node index.js %otf% %flags%
|
||||||
for %%f in (.\build\%lig%*.ttx) do ttx -f %%f
|
ttx -f .\build\%lig%.ttx
|
||||||
exit /b
|
exit /b
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ mkdir -p build
|
|||||||
|
|
||||||
build_font() {
|
build_font() {
|
||||||
lig="$1"
|
lig="$1"
|
||||||
|
flags="$2"
|
||||||
otf=${lig/Lig-/-}
|
otf=${lig/Lig-/-}
|
||||||
|
|
||||||
if [ ! -e "./original/$otf.otf" ]
|
if [ ! -e "./original/$otf.otf" ]
|
||||||
@@ -17,20 +18,24 @@ build_font() {
|
|||||||
|
|
||||||
echo Building $1
|
echo Building $1
|
||||||
ttx -f "./original/$otf.otf"
|
ttx -f "./original/$otf.otf"
|
||||||
node index.js $otf
|
node index.js $otf $flags
|
||||||
|
|
||||||
for f in ./build/$1*.ttx ; do
|
ttx -f ./build/$1.ttx
|
||||||
ttx -f $f
|
|
||||||
done
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flags=
|
||||||
|
if [ "$1" = "--italics-hack" ]
|
||||||
|
then
|
||||||
|
flags=$1
|
||||||
|
shift
|
||||||
|
fi
|
||||||
if [ -n "$1" ]
|
if [ -n "$1" ]
|
||||||
then
|
then
|
||||||
# build specified font
|
# build specified font
|
||||||
build_font $1
|
build_font $1 $flags
|
||||||
else
|
else
|
||||||
# build all available fonts
|
# build all available fonts
|
||||||
for d in ./ligature/*/ ; do
|
for d in ./ligature/*/ ; do
|
||||||
build_font $(basename $d)
|
build_font $(basename $d) $flags
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ let lookupIndex = 0;
|
|||||||
let chainIndex = 0;
|
let chainIndex = 0;
|
||||||
const substLookupMap = {};
|
const substLookupMap = {};
|
||||||
|
|
||||||
const buildGsubTables = (_dom, ligature) => {
|
const buildGsubTables = (_dom, ligature, options) => {
|
||||||
dom = _dom;
|
dom = _dom;
|
||||||
|
|
||||||
if (/_/.test(ligature.glyph) === false) {
|
if (/_/.test(ligature.glyph) === false) {
|
||||||
@@ -35,6 +35,17 @@ const buildGsubTables = (_dom, ligature) => {
|
|||||||
// look for 'calt' feature
|
// look for 'calt' feature
|
||||||
featureListDom = xpath.select('FeatureList', gsubDom, true);
|
featureListDom = xpath.select('FeatureList', gsubDom, true);
|
||||||
|
|
||||||
|
if (options.italicsHack) {
|
||||||
|
// remove all features from FeatureList
|
||||||
|
Array.from(featureListDom.childNodes).forEach((c) =>
|
||||||
|
featureListDom.removeChild(c)
|
||||||
|
);
|
||||||
|
|
||||||
|
Array.from(xpath.select('ttFont/GSUB//FeatureIndex', dom)).forEach((c) =>
|
||||||
|
c.parentNode.removeChild(c);
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let featureRecord;
|
let featureRecord;
|
||||||
const featureTag = xpath.select(
|
const featureTag = xpath.select(
|
||||||
'FeatureRecord/FeatureTag[@value="calt"]',
|
'FeatureRecord/FeatureTag[@value="calt"]',
|
||||||
@@ -48,7 +59,7 @@ const buildGsubTables = (_dom, ligature) => {
|
|||||||
true
|
true
|
||||||
);
|
);
|
||||||
featureRecord = createElementWithAttributes('FeatureRecord', {
|
featureRecord = createElementWithAttributes('FeatureRecord', {
|
||||||
index: featureListCount
|
index: featureListCount,
|
||||||
});
|
});
|
||||||
featureRecord.appendChild(
|
featureRecord.appendChild(
|
||||||
createElementWithAttributes('FeatureTag', { value: 'calt' })
|
createElementWithAttributes('FeatureTag', { value: 'calt' })
|
||||||
@@ -67,10 +78,17 @@ const buildGsubTables = (_dom, ligature) => {
|
|||||||
addFeatureToScriptList('latn', featureIndex);
|
addFeatureToScriptList('latn', featureIndex);
|
||||||
|
|
||||||
lookupListDom = xpath.select('LookupList', gsubDom, true);
|
lookupListDom = xpath.select('LookupList', gsubDom, true);
|
||||||
|
if (options.italicsHack) {
|
||||||
|
// remove all lookups from LookupList
|
||||||
|
Array.from(lookupListDom.childNodes).forEach((c) =>
|
||||||
|
lookupListDom.removeChild(c)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
lookupIndex = xpath.select('count(Lookup)', lookupListDom, true);
|
lookupIndex = xpath.select('count(Lookup)', lookupListDom, true);
|
||||||
|
|
||||||
const lookupDom = createElementWithAttributes('Lookup', {
|
const lookupDom = createElementWithAttributes('Lookup', {
|
||||||
index: lookupIndex++
|
index: lookupIndex++,
|
||||||
});
|
});
|
||||||
appendChildren(
|
appendChildren(
|
||||||
lookupDom,
|
lookupDom,
|
||||||
@@ -87,7 +105,7 @@ const buildGsubTables = (_dom, ligature) => {
|
|||||||
featureDom.appendChild(
|
featureDom.appendChild(
|
||||||
createElementWithAttributes('LookupListIndex', {
|
createElementWithAttributes('LookupListIndex', {
|
||||||
index: featureLookupCount,
|
index: featureLookupCount,
|
||||||
value: lookupDom.getAttribute('index')
|
value: lookupDom.getAttribute('index'),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -122,12 +140,11 @@ const finalizeGsubTables = () => {
|
|||||||
lookupListDom,
|
lookupListDom,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
substLookups.forEach(substLookup => {
|
substLookups.forEach((substLookup) => {
|
||||||
substLookup.setAttribute('value', newIndex);
|
substLookup.setAttribute('value', newIndex);
|
||||||
});
|
});
|
||||||
lookup.setAttribute('index', newIndex++);
|
lookup.setAttribute('index', newIndex++);
|
||||||
lookupListDom.appendChild(lookup);
|
lookupListDom.appendChild(lookup);
|
||||||
lookupListDom.appendChild(lookup);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -150,20 +167,20 @@ const addFeatureToScriptList = (tag, featureIndex) => {
|
|||||||
defaultLangSys.appendChild(
|
defaultLangSys.appendChild(
|
||||||
createElementWithAttributes('FeatureIndex', {
|
createElementWithAttributes('FeatureIndex', {
|
||||||
index: count,
|
index: count,
|
||||||
value: featureIndex
|
value: featureIndex,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildBacktrackFirst = glyphs => {
|
const buildBacktrackFirst = (glyphs) => {
|
||||||
// backtrack = first glyph
|
// backtrack = first glyph
|
||||||
// input = first glphy
|
// input = first glphy
|
||||||
// lookAhead = [1..n]
|
// lookAhead = [1..n]
|
||||||
return buildChainContext([glyphs[0]], [glyphs[0]], glyphs.slice(1));
|
return buildChainContext([glyphs[0]], [glyphs[0]], glyphs.slice(1));
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildLookAheadLast = glyphs => {
|
const buildLookAheadLast = (glyphs) => {
|
||||||
// backtrack = none
|
// backtrack = none
|
||||||
// input = first glyph
|
// input = first glyph
|
||||||
// lookAhead = [1..n] + [n]
|
// lookAhead = [1..n] + [n]
|
||||||
@@ -186,12 +203,12 @@ const buildLigatureSubst = (glyphs, lookup) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getLIGs = length => new Array(length).fill('LIG', 0, length);
|
const getLIGs = (length) => new Array(length).fill('LIG', 0, length);
|
||||||
|
|
||||||
const buildChainContext = (backtrack, input, lookAhead, substitute) => {
|
const buildChainContext = (backtrack, input, lookAhead, substitute) => {
|
||||||
const chainDom = createElementWithAttributes('ChainContextSubst', {
|
const chainDom = createElementWithAttributes('ChainContextSubst', {
|
||||||
index: chainIndex++,
|
index: chainIndex++,
|
||||||
Format: 3
|
Format: 3,
|
||||||
});
|
});
|
||||||
|
|
||||||
buildCoverage(chainDom, 'BacktrackCoverage', backtrack);
|
buildCoverage(chainDom, 'BacktrackCoverage', backtrack);
|
||||||
@@ -218,7 +235,7 @@ const buildCoverage = (chainDom, tagName, coverage) => {
|
|||||||
coverage.forEach((glyph, i) => {
|
coverage.forEach((glyph, i) => {
|
||||||
const coverageDom = createElementWithAttributes(tagName, {
|
const coverageDom = createElementWithAttributes(tagName, {
|
||||||
index: i++,
|
index: i++,
|
||||||
Format: 1
|
Format: 1,
|
||||||
});
|
});
|
||||||
coverageDom.appendChild(
|
coverageDom.appendChild(
|
||||||
createElementWithAttributes('Glyph', { value: glyph })
|
createElementWithAttributes('Glyph', { value: glyph })
|
||||||
@@ -235,7 +252,7 @@ const getSubstLookup = (input, output, lookupDom) => {
|
|||||||
|
|
||||||
if (!lookupDom) {
|
if (!lookupDom) {
|
||||||
lookupDom = createElementWithAttributes('Lookup', {
|
lookupDom = createElementWithAttributes('Lookup', {
|
||||||
index: Object.keys(substLookupMap).length + 1
|
index: Object.keys(substLookupMap).length + 1,
|
||||||
});
|
});
|
||||||
lookupDom.appendChild(
|
lookupDom.appendChild(
|
||||||
createElementWithAttributes('LookupType', { value: 1 })
|
createElementWithAttributes('LookupType', { value: 1 })
|
||||||
@@ -251,7 +268,7 @@ const getSubstLookup = (input, output, lookupDom) => {
|
|||||||
if (!singleSubstDom) {
|
if (!singleSubstDom) {
|
||||||
singleSubstDom = createElementWithAttributes('SingleSubst', {
|
singleSubstDom = createElementWithAttributes('SingleSubst', {
|
||||||
index: 0,
|
index: 0,
|
||||||
Format: 2
|
Format: 2,
|
||||||
});
|
});
|
||||||
lookupDom.appendChild(singleSubstDom);
|
lookupDom.appendChild(singleSubstDom);
|
||||||
}
|
}
|
||||||
@@ -272,14 +289,14 @@ const getSubstLookup = (input, output, lookupDom) => {
|
|||||||
|
|
||||||
const createElementWithAttributes = (tagName, attributes) => {
|
const createElementWithAttributes = (tagName, attributes) => {
|
||||||
const element = dom.createElement(tagName);
|
const element = dom.createElement(tagName);
|
||||||
Object.entries(attributes).forEach(attribute => {
|
Object.entries(attributes).forEach((attribute) => {
|
||||||
element.setAttribute(attribute[0], attribute[1]);
|
element.setAttribute(attribute[0], attribute[1]);
|
||||||
});
|
});
|
||||||
return element;
|
return element;
|
||||||
};
|
};
|
||||||
|
|
||||||
const appendChildren = (node, ...children) => {
|
const appendChildren = (node, ...children) => {
|
||||||
children.forEach(child => node.appendChild(child));
|
children.forEach((child) => node.appendChild(child));
|
||||||
};
|
};
|
||||||
|
|
||||||
//const serialize = dom => new XMLSerializer().serializeToString(dom);
|
//const serialize = dom => new XMLSerializer().serializeToString(dom);
|
||||||
|
|||||||
@@ -17,8 +17,12 @@ const NodeType = {};
|
|||||||
NodeType.TEXT_NODE = 3;
|
NodeType.TEXT_NODE = 3;
|
||||||
|
|
||||||
let dom;
|
let dom;
|
||||||
|
let italicsHack = false;
|
||||||
function main() {
|
function main() {
|
||||||
fontName = process.argv[2];
|
fontName = process.argv[2];
|
||||||
|
italicsHack =
|
||||||
|
process.argv[3] === '--italics-hack' && fontName.includes('Italic');
|
||||||
|
|
||||||
ligFontName = fontName.split('-').join('Lig-');
|
ligFontName = fontName.split('-').join('Lig-');
|
||||||
|
|
||||||
const srcFileName = `./original/${fontName}.ttx`;
|
const srcFileName = `./original/${fontName}.ttx`;
|
||||||
@@ -29,12 +33,12 @@ function main() {
|
|||||||
const profiles = getProfiles();
|
const profiles = getProfiles();
|
||||||
|
|
||||||
// process settings (there may be more than one font to build)
|
// 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');
|
console.log('Done');
|
||||||
}
|
}
|
||||||
|
|
||||||
const buildFont = profile => {
|
const buildFont = (profile, options) => {
|
||||||
// add suffix to dstFileName if present
|
// add suffix to dstFileName if present
|
||||||
const dstFileName = `./build/${ligFontName}${profile.suffixWithLeadingHyphen}.ttx`;
|
const dstFileName = `./build/${ligFontName}${profile.suffixWithLeadingHyphen}.ttx`;
|
||||||
console.log(
|
console.log(
|
||||||
@@ -44,19 +48,19 @@ const buildFont = profile => {
|
|||||||
const ligatures = sortLigatures(
|
const ligatures = sortLigatures(
|
||||||
fs
|
fs
|
||||||
.readdirSync(`./ligature/${ligFontName}/glyphs`)
|
.readdirSync(`./ligature/${ligFontName}/glyphs`)
|
||||||
.filter(file => /\.xml$/.test(file))
|
.filter((file) => /\.xml$/.test(file))
|
||||||
.map(file => file.replace('.xml', ''))
|
.map((file) => file.replace('.xml', ''))
|
||||||
)
|
)
|
||||||
.filter(name => !/\d+\.liga$/.test(name)) // skip alternates (ends with .#)
|
.filter((name) => !/\d+\.liga$/.test(name)) // skip alternates (ends with .#)
|
||||||
.filter(name => filterLigatures(name, profile.ligatures))
|
.filter((name) => filterLigatures(name, profile.ligatures))
|
||||||
.map(name => mapLigatures(name, profile.ligatures))
|
.map((name) => mapLigatures(name, profile.ligatures))
|
||||||
.filter(entry => filterGlyphsExists(entry));
|
.filter((entry) => filterGlyphsExists(entry));
|
||||||
|
|
||||||
const ligaturesWithLIG = ligatures;
|
const ligaturesWithLIG = ligatures;
|
||||||
//[...ligatures, { name: 'LIG', glyph: 'LIG' }];
|
//[...ligatures, { name: 'LIG', glyph: 'LIG' }];
|
||||||
|
|
||||||
processPatch('names', patchNames, dom, ligatures, profile);
|
processPatch('names', patchNames, dom, ligatures, profile);
|
||||||
processPatch('gsub', patchGsub, dom, ligatures);
|
processPatch('gsub', patchGsub, dom, ligatures, options);
|
||||||
processPatch('charstrings', patchCharStrings, dom, ligaturesWithLIG);
|
processPatch('charstrings', patchCharStrings, dom, ligaturesWithLIG);
|
||||||
processPatch('glyphs', patchGlyphs, dom, ligaturesWithLIG);
|
processPatch('glyphs', patchGlyphs, dom, ligaturesWithLIG);
|
||||||
processPatch('hmtx', patchHmtx, dom);
|
processPatch('hmtx', patchHmtx, dom);
|
||||||
@@ -75,8 +79,8 @@ const getProfiles = () => {
|
|||||||
suffix: '',
|
suffix: '',
|
||||||
suffixWithLeadingSpace: '',
|
suffixWithLeadingSpace: '',
|
||||||
suffixWithLeadingHyphen: '',
|
suffixWithLeadingHyphen: '',
|
||||||
ligatures: []
|
ligatures: [],
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,8 +90,8 @@ const getProfiles = () => {
|
|||||||
const content = fs.readFileSync(profilePath, 'utf-8');
|
const content = fs.readFileSync(profilePath, 'utf-8');
|
||||||
content
|
content
|
||||||
.split(/\r|\r\n|\n/g)
|
.split(/\r|\r\n|\n/g)
|
||||||
.filter(line => /^[#]/.test(line) === false && line.length > 0)
|
.filter((line) => /^[#]/.test(line) === false && line.length > 0)
|
||||||
.forEach(line => {
|
.forEach((line) => {
|
||||||
const ch = line.trim()[0];
|
const ch = line.trim()[0];
|
||||||
if (ch === '[') {
|
if (ch === '[') {
|
||||||
let name = line.substr(1, line.indexOf(']') - 1);
|
let name = line.substr(1, line.indexOf(']') - 1);
|
||||||
@@ -96,7 +100,7 @@ const getProfiles = () => {
|
|||||||
suffix: name === 'default' ? '' : name,
|
suffix: name === 'default' ? '' : name,
|
||||||
suffixWithLeadingSpace: name === 'default' ? '' : ' ' + name,
|
suffixWithLeadingSpace: name === 'default' ? '' : ' ' + name,
|
||||||
suffixWithLeadingHyphen: name === 'default' ? '' : '-' + name,
|
suffixWithLeadingHyphen: name === 'default' ? '' : '-' + name,
|
||||||
ligatures: []
|
ligatures: [],
|
||||||
};
|
};
|
||||||
profiles.push(profile);
|
profiles.push(profile);
|
||||||
} else {
|
} else {
|
||||||
@@ -113,12 +117,12 @@ const getProfiles = () => {
|
|||||||
const filterLigatures = (name, mappings) => {
|
const filterLigatures = (name, mappings) => {
|
||||||
// loop through mappings and return if name applies or not
|
// loop through mappings and return if name applies or not
|
||||||
// skip if setting is !name
|
// 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) => {
|
const mapLigatures = (name, mappings) => {
|
||||||
let mapping = { name, glyph: name };
|
let mapping = { name, glyph: name };
|
||||||
mappings.forEach(entry => {
|
mappings.forEach((entry) => {
|
||||||
const [val1, val2] = entry.split('=');
|
const [val1, val2] = entry.split('=');
|
||||||
// handle lig=altliga
|
// handle lig=altliga
|
||||||
if (val1 === name) {
|
if (val1 === name) {
|
||||||
@@ -135,10 +139,10 @@ const filterGlyphsExists = ({ glyph }) => {
|
|||||||
return exists;
|
return exists;
|
||||||
};
|
};
|
||||||
|
|
||||||
const sortLigatures = ligatures => {
|
const sortLigatures = (ligatures) => {
|
||||||
// sort by most glyphs then alphabetically
|
// sort by most glyphs then alphabetically
|
||||||
const sorted = ligatures
|
const sorted = ligatures
|
||||||
.map(ligature => {
|
.map((ligature) => {
|
||||||
return { count: ligature.split('_').length + 1, ligature: ligature };
|
return { count: ligature.split('_').length + 1, ligature: ligature };
|
||||||
})
|
})
|
||||||
.sort(
|
.sort(
|
||||||
@@ -146,7 +150,7 @@ const sortLigatures = ligatures => {
|
|||||||
-compareProperty(a.count, b.count) || // sort by count descending
|
-compareProperty(a.count, b.count) || // sort by count descending
|
||||||
compareProperty(a.ligature, b.ligature) // then by ligature alphabetically
|
compareProperty(a.ligature, b.ligature) // then by ligature alphabetically
|
||||||
)
|
)
|
||||||
.map(entry => entry.ligature);
|
.map((entry) => entry.ligature);
|
||||||
return sorted;
|
return sorted;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -158,20 +162,20 @@ const compareProperty = (a, b) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadXml = name => {
|
const loadXml = (name) => {
|
||||||
const fileName = `./ligature/${ligFontName}/${name}.xml`;
|
const fileName = `./ligature/${ligFontName}/${name}.xml`;
|
||||||
const xml = fs.readFileSync(fileName, 'utf-8');
|
const xml = fs.readFileSync(fileName, 'utf-8');
|
||||||
return new DOMParser().parseFromString(xml);
|
return new DOMParser().parseFromString(xml);
|
||||||
};
|
};
|
||||||
|
|
||||||
const processPatch = (name, patchFunc, dom, ligatures, profile) => {
|
const processPatch = (name, patchFunc, dom, ligatures, profile, options) => {
|
||||||
console.log(`Patching ${name}`);
|
console.log(`Patching ${name}`);
|
||||||
patchFunc(dom, ligatures, profile);
|
patchFunc(dom, ligatures, profile, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
const PlatformId = {
|
const PlatformId = {
|
||||||
mac: 1,
|
mac: 1,
|
||||||
win: 3
|
win: 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
const NameId = {
|
const NameId = {
|
||||||
@@ -182,7 +186,7 @@ const NameId = {
|
|||||||
version: 5,
|
version: 5,
|
||||||
postscriptName: 6,
|
postscriptName: 6,
|
||||||
windowsFamilyName: 16,
|
windowsFamilyName: 16,
|
||||||
fontStyleName: 17
|
fontStyleName: 17,
|
||||||
};
|
};
|
||||||
|
|
||||||
const patchNames = (dom, ligatures, profile) => {
|
const patchNames = (dom, ligatures, profile) => {
|
||||||
@@ -253,7 +257,7 @@ const patchGlyphs = (dom, ligatures) => {
|
|||||||
// only import glyphs specified
|
// only import glyphs specified
|
||||||
let n = glyphsCount;
|
let n = glyphsCount;
|
||||||
// get ligature glyphs
|
// get ligature glyphs
|
||||||
ligatures.forEach(ligature => {
|
ligatures.forEach((ligature) => {
|
||||||
targetGlyphs.appendChild(
|
targetGlyphs.appendChild(
|
||||||
createElementWithAttributes('GlyphID', { id: n++, name: ligature.glyph })
|
createElementWithAttributes('GlyphID', { id: n++, name: ligature.glyph })
|
||||||
);
|
);
|
||||||
@@ -262,18 +266,18 @@ const patchGlyphs = (dom, ligatures) => {
|
|||||||
setAttribute(dom, '/ttFont/maxp/numGlyphs', 'value', n);
|
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
|
// don't patch if no ligatures other than LIG
|
||||||
if (ligatures.length <= 1) return;
|
if (ligatures.length <= 1) return;
|
||||||
|
|
||||||
ligatures.forEach(ligature => {
|
ligatures.forEach((ligature) => {
|
||||||
// build gsub tables
|
// build gsub tables
|
||||||
gsub.buildGsubTables(dom, ligature);
|
gsub.buildGsubTables(dom, ligature, options);
|
||||||
});
|
});
|
||||||
gsub.finalizeGsubTables();
|
gsub.finalizeGsubTables();
|
||||||
};
|
};
|
||||||
|
|
||||||
const patchHmtx = dom => {
|
const patchHmtx = (dom) => {
|
||||||
const mtxCount = xpath.select('count(/ttFont/hmtx/mtx)', dom, true);
|
const mtxCount = xpath.select('count(/ttFont/hmtx/mtx)', dom, true);
|
||||||
setAttribute(dom, '/ttFont/hhea/numberOfHMetrics', 'value', mtxCount);
|
setAttribute(dom, '/ttFont/hhea/numberOfHMetrics', 'value', mtxCount);
|
||||||
|
|
||||||
@@ -306,7 +310,7 @@ const patchCharStrings = (dom, ligatures) => {
|
|||||||
);
|
);
|
||||||
const targetGsubrs = xpath.select('/ttFont/CFF/GlobalSubrs', dom, true);
|
const targetGsubrs = xpath.select('/ttFont/CFF/GlobalSubrs', dom, true);
|
||||||
const fingerprints = {};
|
const fingerprints = {};
|
||||||
ligatures.forEach(ligature => {
|
ligatures.forEach((ligature) => {
|
||||||
console.log(
|
console.log(
|
||||||
`* ${ligature.name}${
|
`* ${ligature.name}${
|
||||||
ligature.name === ligature.glyph ? '' : ' => ' + ligature.glyph
|
ligature.name === ligature.glyph ? '' : ' => ' + ligature.glyph
|
||||||
@@ -318,11 +322,11 @@ const patchCharStrings = (dom, ligatures) => {
|
|||||||
|
|
||||||
const subrs = {
|
const subrs = {
|
||||||
sourcePath: '/Glyph/Subrs',
|
sourcePath: '/Glyph/Subrs',
|
||||||
target: targetSubrs
|
target: targetSubrs,
|
||||||
};
|
};
|
||||||
const gsubrs = {
|
const gsubrs = {
|
||||||
sourcePath: '/Glyph/GlobalSubrs',
|
sourcePath: '/Glyph/GlobalSubrs',
|
||||||
target: targetGsubrs
|
target: targetGsubrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
patchCharStringSubrs(glyphDom, node, fingerprints, subrs, gsubrs);
|
patchCharStringSubrs(glyphDom, node, fingerprints, subrs, gsubrs);
|
||||||
@@ -332,16 +336,16 @@ const patchCharStrings = (dom, ligatures) => {
|
|||||||
createElementWithAttributes('mtx', {
|
createElementWithAttributes('mtx', {
|
||||||
name: ligature.glyph,
|
name: ligature.glyph,
|
||||||
width: glyphDom.getAttribute('width'),
|
width: glyphDom.getAttribute('width'),
|
||||||
lsb: glyphDom.getAttribute('lsb')
|
lsb: glyphDom.getAttribute('lsb'),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
const code = glyphDom.getAttribute('code');
|
const code = glyphDom.getAttribute('code');
|
||||||
if (code) {
|
if (code) {
|
||||||
Array.from(targetCmaps).forEach(node => {
|
Array.from(targetCmaps).forEach((node) => {
|
||||||
node.appendChild(
|
node.appendChild(
|
||||||
createElementWithAttributes('map', {
|
createElementWithAttributes('map', {
|
||||||
code,
|
code,
|
||||||
name: ligature.glyph
|
name: ligature.glyph,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -354,7 +358,7 @@ const patchCharStringSubrs = (glyphDom, node, fingerprints, subrs, gsubrs) => {
|
|||||||
|
|
||||||
const lines = node.childNodes[0].textContent.split(/\r|\r\n|\n/g);
|
const lines = node.childNodes[0].textContent.split(/\r|\r\n|\n/g);
|
||||||
const newLines = [];
|
const newLines = [];
|
||||||
lines.forEach(line => {
|
lines.forEach((line) => {
|
||||||
if (line.trim().length === 0) return;
|
if (line.trim().length === 0) return;
|
||||||
const matches = line.match(/(.*?)\{([0-9a-z]+)\} (callsubr|callgsubr)$/);
|
const matches = line.match(/(.*?)\{([0-9a-z]+)\} (callsubr|callgsubr)$/);
|
||||||
if (matches != null) {
|
if (matches != null) {
|
||||||
@@ -403,21 +407,21 @@ const copyConfigAttribute = (dom, configDom, path, name) => {
|
|||||||
|
|
||||||
const createElementWithAttributes = (tagName, attributes) => {
|
const createElementWithAttributes = (tagName, attributes) => {
|
||||||
const element = dom.createElement(tagName);
|
const element = dom.createElement(tagName);
|
||||||
Object.entries(attributes).forEach(attribute => {
|
Object.entries(attributes).forEach((attribute) => {
|
||||||
element.setAttribute(attribute[0], attribute[1]);
|
element.setAttribute(attribute[0], attribute[1]);
|
||||||
});
|
});
|
||||||
return element;
|
return element;
|
||||||
};
|
};
|
||||||
|
|
||||||
//const dump = dom => console.log(serialize(dom));
|
//const dump = dom => console.log(serialize(dom));
|
||||||
const serialize = dom =>
|
const serialize = (dom) =>
|
||||||
new XMLSerializer().serializeToString(dom, false, node => {
|
new XMLSerializer().serializeToString(dom, false, (node) => {
|
||||||
if (node.nodeType === NodeType.TEXT_NODE) {
|
if (node.nodeType === NodeType.TEXT_NODE) {
|
||||||
if (regExWhitespace.test(node.data)) return null;
|
if (regExWhitespace.test(node.data)) return null;
|
||||||
const data = node.data
|
const data = node.data
|
||||||
.split(/\r|\r\n|\n/g)
|
.split(/\r|\r\n|\n/g)
|
||||||
.filter(s => /\S+/.test(s))
|
.filter((s) => /\S+/.test(s))
|
||||||
.map(s => s.replace(/^\s+/g, ''))
|
.map((s) => s.replace(/^\s+/g, ''))
|
||||||
.join(os.EOL);
|
.join(os.EOL);
|
||||||
|
|
||||||
return node.ownerDocument.createTextNode(data);
|
return node.ownerDocument.createTextNode(data);
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- html comment -->
|
<!-- html comment a => b && c++ -->
|
||||||
|
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<a href="http://localhost">Click Here</a>
|
<a href="http://localhost">Click Here</a>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
const func = (a, b, c, d, e, f, s, n) => {
|
const func = (a, b, c, d, e, f, s, n) => {
|
||||||
// this is a comment
|
// this is a comment
|
||||||
if (a++ && b-- || c >= d || e <= f) {
|
if (a++ && b-- || c >= d || e <= f) {
|
||||||
@@ -10,6 +12,16 @@ const func = (a, b, c, d, e, f, s, n) => {
|
|||||||
a |> b
|
a |> b
|
||||||
a <| b |> c -> d ==> e
|
a <| b |> c -> d ==> e
|
||||||
|
|
||||||
|
// if (a++ && b-- || c >= d || e <= f) {
|
||||||
|
// }
|
||||||
|
// if (s === 'string' && n !== 999) {
|
||||||
|
// }
|
||||||
|
// if (a == b && c != d)
|
||||||
|
// a ?? b
|
||||||
|
// a <- b <-- c <== d
|
||||||
|
// a |> b
|
||||||
|
// a <| b |> c -> d ==> e
|
||||||
|
|
||||||
// italic ligatures
|
// italic ligatures
|
||||||
// != == >= <= -> => ==>
|
// != == >= <= -> => ==>
|
||||||
// === !== && || ++ --
|
// === !== && || ++ --
|
||||||
|
|||||||
Reference in New Issue
Block a user