
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
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);
}
}
}
}
}