Show More
Commit Description:
force log out when password change
Commit Description:
force log out when password change
References:
File last commit:
Show/Diff file:
Action:
node_modules/fontkit/src/layout/UnicodeLayoutEngine.js
| 250 lines
| 6.7 KiB
| application/javascript
| JavascriptLexer
|
r789 | import unicode from 'unicode-properties'; | |||
/** | ||||
* This class is used when GPOS does not define 'mark' or 'mkmk' features | ||||
* for positioning marks relative to base glyphs. It uses the unicode | ||||
* combining class property to position marks. | ||||
* | ||||
* Based on code from Harfbuzz, thanks! | ||||
* https://github.com/behdad/harfbuzz/blob/master/src/hb-ot-shape-fallback.cc | ||||
*/ | ||||
export default class UnicodeLayoutEngine { | ||||
constructor(font) { | ||||
this.font = font; | ||||
} | ||||
positionGlyphs(glyphs, positions) { | ||||
// find each base + mark cluster, and position the marks relative to the base | ||||
let clusterStart = 0; | ||||
let clusterEnd = 0; | ||||
for (let index = 0; index < glyphs.length; index++) { | ||||
let glyph = glyphs[index]; | ||||
if (glyph.isMark) { // TODO: handle ligatures | ||||
clusterEnd = index; | ||||
} else { | ||||
if (clusterStart !== clusterEnd) { | ||||
this.positionCluster(glyphs, positions, clusterStart, clusterEnd); | ||||
} | ||||
clusterStart = clusterEnd = index; | ||||
} | ||||
} | ||||
if (clusterStart !== clusterEnd) { | ||||
this.positionCluster(glyphs, positions, clusterStart, clusterEnd); | ||||
} | ||||
return positions; | ||||
} | ||||
positionCluster(glyphs, positions, clusterStart, clusterEnd) { | ||||
let base = glyphs[clusterStart]; | ||||
let baseBox = base.cbox.copy(); | ||||
// adjust bounding box for ligature glyphs | ||||
if (base.codePoints.length > 1) { | ||||
// LTR. TODO: RTL support. | ||||
baseBox.minX += ((base.codePoints.length - 1) * baseBox.width) / base.codePoints.length; | ||||
} | ||||
let xOffset = -positions[clusterStart].xAdvance; | ||||
let yOffset = 0; | ||||
let yGap = this.font.unitsPerEm / 16; | ||||
// position each of the mark glyphs relative to the base glyph | ||||
for (let index = clusterStart + 1; index <= clusterEnd; index++) { | ||||
let mark = glyphs[index]; | ||||
let markBox = mark.cbox; | ||||
let position = positions[index]; | ||||
let combiningClass = this.getCombiningClass(mark.codePoints[0]); | ||||
if (combiningClass !== 'Not_Reordered') { | ||||
position.xOffset = position.yOffset = 0; | ||||
// x positioning | ||||
switch (combiningClass) { | ||||
case 'Double_Above': | ||||
case 'Double_Below': | ||||
// LTR. TODO: RTL support. | ||||
position.xOffset += baseBox.minX - markBox.width / 2 - markBox.minX; | ||||
break; | ||||
case 'Attached_Below_Left': | ||||
case 'Below_Left': | ||||
case 'Above_Left': | ||||
// left align | ||||
position.xOffset += baseBox.minX - markBox.minX; | ||||
break; | ||||
case 'Attached_Above_Right': | ||||
case 'Below_Right': | ||||
case 'Above_Right': | ||||
// right align | ||||
position.xOffset += baseBox.maxX - markBox.width - markBox.minX; | ||||
break; | ||||
default: // Attached_Below, Attached_Above, Below, Above, other | ||||
// center align | ||||
position.xOffset += baseBox.minX + (baseBox.width - markBox.width) / 2 - markBox.minX; | ||||
} | ||||
// y positioning | ||||
switch (combiningClass) { | ||||
case 'Double_Below': | ||||
case 'Below_Left': | ||||
case 'Below': | ||||
case 'Below_Right': | ||||
case 'Attached_Below_Left': | ||||
case 'Attached_Below': | ||||
// add a small gap between the glyphs if they are not attached | ||||
if (combiningClass === 'Attached_Below_Left' || combiningClass === 'Attached_Below') { | ||||
baseBox.minY += yGap; | ||||
} | ||||
position.yOffset = -baseBox.minY - markBox.maxY; | ||||
baseBox.minY += markBox.height; | ||||
break; | ||||
case 'Double_Above': | ||||
case 'Above_Left': | ||||
case 'Above': | ||||
case 'Above_Right': | ||||
case 'Attached_Above': | ||||
case 'Attached_Above_Right': | ||||
// add a small gap between the glyphs if they are not attached | ||||
if (combiningClass === 'Attached_Above' || combiningClass === 'Attached_Above_Right') { | ||||
baseBox.maxY += yGap; | ||||
} | ||||
position.yOffset = baseBox.maxY - markBox.minY; | ||||
baseBox.maxY += markBox.height; | ||||
break; | ||||
} | ||||
position.xAdvance = position.yAdvance = 0; | ||||
position.xOffset += xOffset; | ||||
position.yOffset += yOffset; | ||||
} else { | ||||
xOffset -= position.xAdvance; | ||||
yOffset -= position.yAdvance; | ||||
} | ||||
} | ||||
return; | ||||
} | ||||
getCombiningClass(codePoint) { | ||||
let combiningClass = unicode.getCombiningClass(codePoint); | ||||
// Thai / Lao need some per-character work | ||||
if ((codePoint & ~0xff) === 0x0e00) { | ||||
if (combiningClass === 'Not_Reordered') { | ||||
switch (codePoint) { | ||||
case 0x0e31: | ||||
case 0x0e34: | ||||
case 0x0e35: | ||||
case 0x0e36: | ||||
case 0x0e37: | ||||
case 0x0e47: | ||||
case 0x0e4c: | ||||
case 0x0e3d: | ||||
case 0x0e4e: | ||||
return 'Above_Right'; | ||||
case 0x0eb1: | ||||
case 0x0eb4: | ||||
case 0x0eb5: | ||||
case 0x0eb6: | ||||
case 0x0eb7: | ||||
case 0x0ebb: | ||||
case 0x0ecc: | ||||
case 0x0ecd: | ||||
return 'Above'; | ||||
case 0x0ebc: | ||||
return 'Below'; | ||||
} | ||||
} else if (codePoint === 0x0e3a) { // virama | ||||
return 'Below_Right'; | ||||
} | ||||
} | ||||
switch (combiningClass) { | ||||
// Hebrew | ||||
case 'CCC10': // sheva | ||||
case 'CCC11': // hataf segol | ||||
case 'CCC12': // hataf patah | ||||
case 'CCC13': // hataf qamats | ||||
case 'CCC14': // hiriq | ||||
case 'CCC15': // tsere | ||||
case 'CCC16': // segol | ||||
case 'CCC17': // patah | ||||
case 'CCC18': // qamats | ||||
case 'CCC20': // qubuts | ||||
case 'CCC22': // meteg | ||||
return 'Below'; | ||||
case 'CCC23': // rafe | ||||
return 'Attached_Above'; | ||||
case 'CCC24': // shin dot | ||||
return 'Above_Right'; | ||||
case 'CCC25': // sin dot | ||||
case 'CCC19': // holam | ||||
return 'Above_Left'; | ||||
case 'CCC26': // point varika | ||||
return 'Above'; | ||||
case 'CCC21': // dagesh | ||||
break; | ||||
// Arabic and Syriac | ||||
case 'CCC27': // fathatan | ||||
case 'CCC28': // dammatan | ||||
case 'CCC30': // fatha | ||||
case 'CCC31': // damma | ||||
case 'CCC33': // shadda | ||||
case 'CCC34': // sukun | ||||
case 'CCC35': // superscript alef | ||||
case 'CCC36': // superscript alaph | ||||
return 'Above'; | ||||
case 'CCC29': // kasratan | ||||
case 'CCC32': // kasra | ||||
return 'Below'; | ||||
// Thai | ||||
case 'CCC103': // sara u / sara uu | ||||
return 'Below_Right'; | ||||
case 'CCC107': // mai | ||||
return 'Above_Right'; | ||||
// Lao | ||||
case 'CCC118': // sign u / sign uu | ||||
return 'Below'; | ||||
case 'CCC122': // mai | ||||
return 'Above'; | ||||
// Tibetan | ||||
case 'CCC129': // sign aa | ||||
case 'CCC132': // sign u | ||||
return 'Below'; | ||||
case 'CCC130': // sign i | ||||
return 'Above'; | ||||
} | ||||
return combiningClass; | ||||
} | ||||
} | ||||