Show More
Commit Description:
fig bugs in login report
Commit Description:
fig bugs in login report
References:
File last commit:
Show/Diff file:
Action:
node_modules/fontkit/src/layout/LayoutEngine.js
| 190 lines
| 5.7 KiB
| application/javascript
| JavascriptLexer
|
r789 | import KernProcessor from './KernProcessor'; | |||
import UnicodeLayoutEngine from './UnicodeLayoutEngine'; | ||||
import GlyphRun from './GlyphRun'; | ||||
import GlyphPosition from './GlyphPosition'; | ||||
import * as Script from './Script'; | ||||
import unicode from 'unicode-properties'; | ||||
import AATLayoutEngine from '../aat/AATLayoutEngine'; | ||||
import OTLayoutEngine from '../opentype/OTLayoutEngine'; | ||||
export default class LayoutEngine { | ||||
constructor(font) { | ||||
this.font = font; | ||||
this.unicodeLayoutEngine = null; | ||||
this.kernProcessor = null; | ||||
// Choose an advanced layout engine. We try the AAT morx table first since more | ||||
// scripts are currently supported because the shaping logic is built into the font. | ||||
if (this.font.morx) { | ||||
this.engine = new AATLayoutEngine(this.font); | ||||
} else if (this.font.GSUB || this.font.GPOS) { | ||||
this.engine = new OTLayoutEngine(this.font); | ||||
} | ||||
} | ||||
layout(string, features, script, language, direction) { | ||||
// Make the features parameter optional | ||||
if (typeof features === 'string') { | ||||
direction = language; | ||||
language = script; | ||||
script = features; | ||||
features = []; | ||||
} | ||||
// Map string to glyphs if needed | ||||
if (typeof string === 'string') { | ||||
// Attempt to detect the script from the string if not provided. | ||||
if (script == null) { | ||||
script = Script.forString(string); | ||||
} | ||||
var glyphs = this.font.glyphsForString(string); | ||||
} else { | ||||
// Attempt to detect the script from the glyph code points if not provided. | ||||
if (script == null) { | ||||
let codePoints = []; | ||||
for (let glyph of string) { | ||||
codePoints.push(...glyph.codePoints); | ||||
} | ||||
script = Script.forCodePoints(codePoints); | ||||
} | ||||
var glyphs = string; | ||||
} | ||||
let glyphRun = new GlyphRun(glyphs, features, script, language, direction); | ||||
// Return early if there are no glyphs | ||||
if (glyphs.length === 0) { | ||||
glyphRun.positions = []; | ||||
return glyphRun; | ||||
} | ||||
// Setup the advanced layout engine | ||||
if (this.engine && this.engine.setup) { | ||||
this.engine.setup(glyphRun); | ||||
} | ||||
// Substitute and position the glyphs | ||||
this.substitute(glyphRun); | ||||
this.position(glyphRun); | ||||
this.hideDefaultIgnorables(glyphRun.glyphs, glyphRun.positions); | ||||
// Let the layout engine clean up any state it might have | ||||
if (this.engine && this.engine.cleanup) { | ||||
this.engine.cleanup(); | ||||
} | ||||
return glyphRun; | ||||
} | ||||
substitute(glyphRun) { | ||||
// Call the advanced layout engine to make substitutions | ||||
if (this.engine && this.engine.substitute) { | ||||
this.engine.substitute(glyphRun); | ||||
} | ||||
} | ||||
position(glyphRun) { | ||||
// Get initial glyph positions | ||||
glyphRun.positions = glyphRun.glyphs.map(glyph => new GlyphPosition(glyph.advanceWidth)); | ||||
let positioned = null; | ||||
// Call the advanced layout engine. Returns the features applied. | ||||
if (this.engine && this.engine.position) { | ||||
positioned = this.engine.position(glyphRun); | ||||
} | ||||
// if there is no GPOS table, use unicode properties to position marks. | ||||
if (!positioned && (!this.engine || this.engine.fallbackPosition)) { | ||||
if (!this.unicodeLayoutEngine) { | ||||
this.unicodeLayoutEngine = new UnicodeLayoutEngine(this.font); | ||||
} | ||||
this.unicodeLayoutEngine.positionGlyphs(glyphRun.glyphs, glyphRun.positions); | ||||
} | ||||
// if kerning is not supported by GPOS, do kerning with the TrueType/AAT kern table | ||||
if ((!positioned || !positioned.kern) && glyphRun.features.kern !== false && this.font.kern) { | ||||
if (!this.kernProcessor) { | ||||
this.kernProcessor = new KernProcessor(this.font); | ||||
} | ||||
this.kernProcessor.process(glyphRun.glyphs, glyphRun.positions); | ||||
glyphRun.features.kern = true; | ||||
} | ||||
} | ||||
hideDefaultIgnorables(glyphs, positions) { | ||||
let space = this.font.glyphForCodePoint(0x20); | ||||
for (let i = 0; i < glyphs.length; i++) { | ||||
if (this.isDefaultIgnorable(glyphs[i].codePoints[0])) { | ||||
glyphs[i] = space; | ||||
positions[i].xAdvance = 0; | ||||
positions[i].yAdvance = 0; | ||||
} | ||||
} | ||||
} | ||||
isDefaultIgnorable(ch) { | ||||
// From DerivedCoreProperties.txt in the Unicode database, | ||||
// minus U+115F, U+1160, U+3164 and U+FFA0, which is what | ||||
// Harfbuzz and Uniscribe do. | ||||
let plane = ch >> 16; | ||||
if (plane === 0) { | ||||
// BMP | ||||
switch (ch >> 8) { | ||||
case 0x00: return ch === 0x00AD; | ||||
case 0x03: return ch === 0x034F; | ||||
case 0x06: return ch === 0x061C; | ||||
case 0x17: return 0x17B4 <= ch && ch <= 0x17B5; | ||||
case 0x18: return 0x180B <= ch && ch <= 0x180E; | ||||
case 0x20: return (0x200B <= ch && ch <= 0x200F) || (0x202A <= ch && ch <= 0x202E) || (0x2060 <= ch && ch <= 0x206F); | ||||
case 0xFE: return (0xFE00 <= ch && ch <= 0xFE0F) || ch === 0xFEFF; | ||||
case 0xFF: return 0xFFF0 <= ch && ch <= 0xFFF8; | ||||
default: return false; | ||||
} | ||||
} else { | ||||
// Other planes | ||||
switch (plane) { | ||||
case 0x01: return (0x1BCA0 <= ch && ch <= 0x1BCA3) || (0x1D173 <= ch && ch <= 0x1D17A); | ||||
case 0x0E: return 0xE0000 <= ch && ch <= 0xE0FFF; | ||||
default: return false; | ||||
} | ||||
} | ||||
} | ||||
getAvailableFeatures(script, language) { | ||||
let features = []; | ||||
if (this.engine) { | ||||
features.push(...this.engine.getAvailableFeatures(script, language)); | ||||
} | ||||
if (this.font.kern && features.indexOf('kern') === -1) { | ||||
features.push('kern'); | ||||
} | ||||
return features; | ||||
} | ||||
stringsForGlyph(gid) { | ||||
let result = new Set; | ||||
let codePoints = this.font._cmapProcessor.codePointsForGlyph(gid); | ||||
for (let codePoint of codePoints) { | ||||
result.add(String.fromCodePoint(codePoint)); | ||||
} | ||||
if (this.engine && this.engine.stringsForGlyph) { | ||||
for (let string of this.engine.stringsForGlyph(gid)) { | ||||
result.add(string); | ||||
} | ||||
} | ||||
return Array.from(result); | ||||
} | ||||
} | ||||