|
|
import {binarySearch} from '../utils';
|
|
|
|
|
|
export default class KernProcessor {
|
|
|
constructor(font) {
|
|
|
this.kern = font.kern;
|
|
|
}
|
|
|
|
|
|
process(glyphs, positions) {
|
|
|
for (let glyphIndex = 0; glyphIndex < glyphs.length - 1; glyphIndex++) {
|
|
|
let left = glyphs[glyphIndex].id;
|
|
|
let right = glyphs[glyphIndex + 1].id;
|
|
|
positions[glyphIndex].xAdvance += this.getKerning(left, right);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
getKerning(left, right) {
|
|
|
let res = 0;
|
|
|
|
|
|
for (let table of this.kern.tables) {
|
|
|
if (table.coverage.crossStream) {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
switch (table.version) {
|
|
|
case 0:
|
|
|
if (!table.coverage.horizontal) {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
case 1:
|
|
|
if (table.coverage.vertical || table.coverage.variation) {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
default:
|
|
|
throw new Error(`Unsupported kerning table version ${table.version}`);
|
|
|
}
|
|
|
|
|
|
let val = 0;
|
|
|
let s = table.subtable;
|
|
|
switch (table.format) {
|
|
|
case 0:
|
|
|
let pairIdx = binarySearch(s.pairs, function (pair) {
|
|
|
return (left - pair.left) || (right - pair.right);
|
|
|
});
|
|
|
|
|
|
if (pairIdx >= 0) {
|
|
|
val = s.pairs[pairIdx].value;
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 2:
|
|
|
let leftOffset = 0, rightOffset = 0;
|
|
|
if (left >= s.leftTable.firstGlyph && left < s.leftTable.firstGlyph + s.leftTable.nGlyphs) {
|
|
|
leftOffset = s.leftTable.offsets[left - s.leftTable.firstGlyph];
|
|
|
} else {
|
|
|
leftOffset = s.array.off;
|
|
|
}
|
|
|
|
|
|
if (right >= s.rightTable.firstGlyph && right < s.rightTable.firstGlyph + s.rightTable.nGlyphs) {
|
|
|
rightOffset = s.rightTable.offsets[right - s.rightTable.firstGlyph];
|
|
|
}
|
|
|
|
|
|
let index = (leftOffset + rightOffset - s.array.off) / 2;
|
|
|
val = s.array.values.get(index);
|
|
|
break;
|
|
|
|
|
|
case 3:
|
|
|
if (left >= s.glyphCount || right >= s.glyphCount) {
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
val = s.kernValue[s.kernIndex[s.leftClass[left] * s.rightClassCount + s.rightClass[right]]];
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
throw new Error(`Unsupported kerning sub-table format ${table.format}`);
|
|
|
}
|
|
|
|
|
|
// Microsoft supports the override flag, which resets the result
|
|
|
// Otherwise, the sum of the results from all subtables is returned
|
|
|
if (table.coverage.override) {
|
|
|
res = val;
|
|
|
} else {
|
|
|
res += val;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return res;
|
|
|
}
|
|
|
}
|
|
|
|