font-ligatures
Version:
Find ligature replacements for any system font
86 lines (75 loc) • 2.95 kB
text/typescript
import { ClassDefTable } from '../tables';
/**
* Get the number of the class to which the glyph belongs, or null if it doesn't
* belong to any of them.
*
* @param table JSON representation of the class def table
* @param glyphId Index of the glyph to look for
*/
export default function getGlyphClass(table: ClassDefTable, glyphId: number | [number, number]): Map<number | [number, number], number | null> {
switch (table.format) {
// https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-2
case 2:
if (Array.isArray(glyphId)) {
return getRangeGlyphClass(table, glyphId);
} else {
return new Map([[
glyphId,
getIndividualGlyphClass(table, glyphId)
]]);
}
// https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-1
default:
return new Map([[glyphId, null]]);
}
}
function getRangeGlyphClass(table: ClassDefTable.Format2, glyphId: [number, number]): Map<number | [number, number], number | null> {
let classStart: number = glyphId[0];
let currentClass: number | null = getIndividualGlyphClass(table, classStart);
let search: number = glyphId[0] + 1;
const result = new Map<[number, number] | number, number | null>();
while (search < glyphId[1]) {
const clazz = getIndividualGlyphClass(table, search);
if (clazz !== currentClass) {
if (search - classStart <= 1) {
result.set(classStart, currentClass);
} else {
result.set([classStart, search], currentClass);
}
}
search++;
}
if (search - classStart <= 1) {
result.set(classStart, currentClass);
} else {
result.set([classStart, search], currentClass);
}
return result;
}
function getIndividualGlyphClass(table: ClassDefTable.Format2, glyphId: number): number | null {
for (const range of table.ranges) {
if (range.start <= glyphId && range.end >= glyphId) {
return range.classId;
}
}
return null;
}
export function listClassGlyphs(table: ClassDefTable, index: number): (number | [number, number])[] {
switch (table.format) {
case 2:
const results: (number | [number, number])[] = [];
for (const range of table.ranges) {
if (range.classId !== index) {
continue;
}
if (range.end === range.start) {
results.push(range.start);
} else {
results.push([range.start, range.end + 1]);
}
}
return results;
default:
return [];
}
}