Current File : /home/tradevaly/www/node_modules/fontkit/src/aat/AATStateMachine.js |
import AATLookupTable from './AATLookupTable';
const START_OF_TEXT_STATE = 0;
const START_OF_LINE_STATE = 1;
const END_OF_TEXT_CLASS = 0;
const OUT_OF_BOUNDS_CLASS = 1;
const DELETED_GLYPH_CLASS = 2;
const END_OF_LINE_CLASS = 3;
const DONT_ADVANCE = 0x4000;
export default class AATStateMachine {
constructor(stateTable) {
this.stateTable = stateTable;
this.lookupTable = new AATLookupTable(stateTable.classTable);
}
process(glyphs, reverse, processEntry) {
let currentState = START_OF_TEXT_STATE; // START_OF_LINE_STATE is used for kashida glyph insertions sometimes I think?
let index = reverse ? glyphs.length - 1 : 0;
let dir = reverse ? -1 : 1;
while ((dir === 1 && index <= glyphs.length) || (dir === -1 && index >= -1)) {
let glyph = null;
let classCode = OUT_OF_BOUNDS_CLASS;
let shouldAdvance = true;
if (index === glyphs.length || index === -1) {
classCode = END_OF_TEXT_CLASS;
} else {
glyph = glyphs[index];
if (glyph.id === 0xffff) { // deleted glyph
classCode = DELETED_GLYPH_CLASS;
} else {
classCode = this.lookupTable.lookup(glyph.id);
if (classCode == null) {
classCode = OUT_OF_BOUNDS_CLASS;
}
}
}
let row = this.stateTable.stateArray.getItem(currentState);
let entryIndex = row[classCode];
let entry = this.stateTable.entryTable.getItem(entryIndex);
if (classCode !== END_OF_TEXT_CLASS && classCode !== DELETED_GLYPH_CLASS) {
processEntry(glyph, entry, index);
shouldAdvance = !(entry.flags & DONT_ADVANCE);
}
currentState = entry.newState;
if (shouldAdvance) {
index += dir;
}
}
return glyphs;
}
/**
* Performs a depth-first traversal of the glyph strings
* represented by the state machine.
*/
traverse(opts, state = 0, visited = new Set) {
if (visited.has(state)) {
return;
}
visited.add(state);
let {nClasses, stateArray, entryTable} = this.stateTable;
let row = stateArray.getItem(state);
// Skip predefined classes
for (let classCode = 4; classCode < nClasses; classCode++) {
let entryIndex = row[classCode];
let entry = entryTable.getItem(entryIndex);
// Try all glyphs in the class
for (let glyph of this.lookupTable.glyphsForValue(classCode)) {
if (opts.enter) {
opts.enter(glyph, entry);
}
if (entry.newState !== 0) {
this.traverse(opts, entry.newState, visited);
}
if (opts.exit) {
opts.exit(glyph, entry);
}
}
}
}
}