unicode-shaper
Version:
Shape unicode text so that renderers like WebGL and WebGPU can properly display the glyphs.
115 lines • 3.88 kB
JavaScript
/**
* Shared shaper - swaps characters
* @param input - input unicode buffer
* @param comparitor - characters to swap
*/
export function sharedShaper(input, comparitor) {
for (let i = 0; i < input.length; i++) {
if (i === 0)
continue;
if (comparitor.includes(input[i])) {
[input[i - 1], input[i]] = [input[i], input[i - 1]];
}
}
}
/**
* Build clusters
* @param defs - array of definitions
* @param cmp - comparator
* @returns - array of clusters
*/
export function buildClusters(defs, cmp) {
const clusters = [];
let defIDX = 0;
for (let idx = 0; idx < defs.length; idx++) {
if (cmp(defs[idx].mType)) {
clusters.push({ defs: defs.slice(defIDX, idx), whitespace: defs[idx].code[0] });
defIDX = idx + 1;
}
}
// store last
if (defIDX < defs.length)
clusters.push({ defs: defs.slice(defIDX) });
return clusters;
}
/**
* Check if two types are the same or if the second type is J
* @param a - first type
* @param b - second type as a unicode
* @param toMType - function to convert unicode to type
* @returns - true if both types are the same
*/
export function mTypeIsSame(a, b, toMType) {
// if b is joiner, return true
if (b === 0x200d || b === 0x034f)
return true;
// otherwise compare the two
return a === toMType(b);
}
/**
* Convert input to clusters of definitions
* @param input - input unicode buffer
* @param toMType - function to convert unicode to type
* @returns - array of clusters
*/
export function buildDefinitions(input, toMType) {
const clusters = [];
let idx = 0;
while (idx < input.length) {
const startIDX = idx;
const code = input[idx];
const mType = toMType(code);
let endIDX = idx + 1;
// while we find joiners and the same type, continue
while (endIDX < input.length && mTypeIsSame(mType, input[endIDX], toMType)) {
endIDX++;
}
clusters.push({ mType, code: input.slice(startIDX, endIDX) });
idx = endIDX;
}
return clusters;
}
/**
* Once the Buginese shaping engine has analyzed the run into
* clusters as described above, it performs any required reordering.
* Pre-base vowels (VPre) are reordered to the start of the syllable
* cluster. A sequence of multiple pre-base vowels is permitted.
* Such sequences are moved as a block to the beginning of the cluster.
* In the following example, the run of code points represents a
* single cluster.
* @param cluster - cluster of definitions
* @param enumType - the enum to use
* @returns - Returns the cluster sorted by dominant type
*/
export function commonGetSorted(cluster, enumType) {
// sort
let idx = 0;
while (idx < cluster.defs.length) {
const { mType } = cluster.defs[idx];
if (mType === enumType.VPre) {
// Pre-base vowels (VPre) are reordered to the start of the syllable cluster.
const vPre = cluster.defs.splice(idx, 1);
cluster.defs.unshift(vPre[0]);
}
else if (mType === enumType.VAbv || mType === enumType.VBlw || mType === enumType.VPst) {
// TODO: always put the head position consonant infront of the head letter
// let headIDX = idx;
// while (
// headIDX > 0 &&
// cluster.defs[headIDX].mType !== MType.C &&
// cluster.defs[headIDX].mType !== MType.GB
// ) {
// headIDX--;
// }
// const vowelSign = cluster.defs.splice(idx, 1);
// cluster.defs.splice(headIDX, 0, vowelSign[0]);
}
idx++;
}
// store
const reordered = [];
for (const def of cluster.defs)
reordered.push(...def.code);
return reordered;
}
//# sourceMappingURL=shared.js.map