Socket
Socket
Sign inDemoInstall

fontkit

Package Overview
Dependencies
Maintainers
1
Versions
38
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fontkit - npm Package Compare versions

Comparing version 1.6.1 to 1.7.1

indic.trie

5

package.json
{
"name": "fontkit",
"version": "1.6.1",
"version": "1.7.1",
"description": "An advanced font engine for Node and the browser",

@@ -28,3 +28,4 @@ "keywords": [

"data.trie",
"use.trie"
"use.trie",
"indic.trie"
],

@@ -31,0 +32,0 @@ "author": "Devon Govett <devongovett@gmail.com>",

6

src/aat/AATFeatureMap.js

@@ -481,5 +481,5 @@ // see https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html

let res = {};
for (let k = 0; k < features.length; k++) {
for (let k in features) {
let r;
if (r = OTMapping[features[k]]) {
if (r = OTMapping[k]) {
if (res[r[0]] == null) {

@@ -489,3 +489,3 @@ res[r[0]] = {};

res[r[0]][r[1]] = true;
res[r[0]][r[1]] = features[k];
}

@@ -492,0 +492,0 @@ }

@@ -12,12 +12,10 @@ import * as AATFeatureMap from './AATFeatureMap';

substitute(glyphs, features, script, language) {
substitute(glyphRun) {
// AAT expects the glyphs to be in visual order prior to morx processing,
// so reverse the glyphs if the script is right-to-left.
let isRTL = Script.direction(script) === 'rtl';
if (isRTL) {
if (glyphRun.direction === 'rtl') {
glyphs.reverse();
}
this.morxProcessor.process(glyphs, AATFeatureMap.mapOTToAAT(features));
return glyphs;
this.morxProcessor.process(glyphRun.glyphs, AATFeatureMap.mapOTToAAT(glyphRun.features));
}

@@ -24,0 +22,0 @@

import BBox from '../glyph/BBox';
import * as Script from '../layout/Script';

@@ -8,3 +9,3 @@ /**

export default class GlyphRun {
constructor(glyphs, positions) {
constructor(glyphs, features, script, language) {
/**

@@ -20,3 +21,38 @@ * An array of Glyph objects in the run

*/
this.positions = positions;
this.positions = null;
/**
* The script that was requested for shaping. This was either passed in or detected automatically.
* @type {string}
*/
this.script = script;
/**
* The language requested for shaping, as passed in. If `null`, the default language for the
* script was used.
* @type {string}
*/
this.language = language || null;
/**
* The directionality of the requested script (either ltr or rtl).
* @type {string}
*/
this.direction = Script.direction(script);
/**
* The features requested during shaping. This is a combination of user
* specified features and features chosen by the shaper.
* @type {object}
*/
this.features = {};
// Convert features to an object
if (Array.isArray(features)) {
for (let tag of features) {
this.features[tag] = true;
}
} else if (typeof features === 'object') {
this.features = features;
}
}

@@ -23,0 +59,0 @@

@@ -26,3 +26,3 @@ import KernProcessor from './KernProcessor';

layout(string, features = [], script, language) {
layout(string, features, script, language) {
// Make the features parameter optional

@@ -57,5 +57,8 @@ if (typeof features === 'string') {

let glyphRun = new GlyphRun(glyphs, features, script, language);
// Return early if there are no glyphs
if (glyphs.length === 0) {
return new GlyphRun(glyphs, []);
glyphRun.positions = [];
return glyphRun;
}

@@ -65,9 +68,11 @@

if (this.engine && this.engine.setup) {
this.engine.setup(glyphs, features, script, language);
this.engine.setup(glyphRun);
}
// Substitute and position the glyphs
glyphs = this.substitute(glyphs, features, script, language);
let positions = this.position(glyphs, features, script, language);
this.substitute(glyphRun);
this.position(glyphRun);
this.hideDefaultIgnorables(glyphRun.glyphs, glyphRun.positions);
// Let the layout engine clean up any state it might have

@@ -78,17 +83,15 @@ if (this.engine && this.engine.cleanup) {

return new GlyphRun(glyphs, positions);
return glyphRun;
}
substitute(glyphs, features, script, language) {
substitute(glyphRun) {
// Call the advanced layout engine to make substitutions
if (this.engine && this.engine.substitute) {
glyphs = this.engine.substitute(glyphs, features, script, language);
this.engine.substitute(glyphRun);
}
return glyphs;
}
position(glyphs, features, script, language) {
position(glyphRun) {
// Get initial glyph positions
let positions = glyphs.map(glyph => new GlyphPosition(glyph.advanceWidth));
glyphRun.positions = glyphRun.glyphs.map(glyph => new GlyphPosition(glyph.advanceWidth));
let positioned = null;

@@ -98,3 +101,3 @@

if (this.engine && this.engine.position) {
positioned = this.engine.position(glyphs, positions, features, script, language);
positioned = this.engine.position(glyphRun);
}

@@ -108,7 +111,7 @@

this.unicodeLayoutEngine.positionGlyphs(glyphs, positions);
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) && this.font.kern) {
if ((!positioned || !positioned.kern) && glyphRun.features.kern !== false && this.font.kern) {
if (!this.kernProcessor) {

@@ -118,8 +121,46 @@ this.kernProcessor = new KernProcessor(this.font);

this.kernProcessor.process(glyphs, positions);
this.kernProcessor.process(glyphRun.glyphs, glyphRun.positions);
glyphRun.features.kern = true;
}
}
return positions;
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) {

@@ -126,0 +167,0 @@ let features = [];

@@ -87,3 +87,3 @@ import unicode from 'unicode-properties';

Old_Turkic: 'orkh',
Oriya: 'orya',
Oriya: ['ory2', 'orya'],
Osmanya: 'osma',

@@ -117,3 +117,3 @@ Palmyrene: 'palm',

New_Tai_Lue: 'talu',
Tamil: 'taml',
Tamil: ['tml2', 'taml'],
Tai_Viet: 'tavt',

@@ -138,2 +138,14 @@ Telugu: ['tel2', 'telu'],

const OPENTYPE_SCRIPTS = {};
for (let script in UNICODE_SCRIPTS) {
let tag = UNICODE_SCRIPTS[script];
if (Array.isArray(tag)) {
for (let t of tag) {
OPENTYPE_SCRIPTS[t] = script;
}
} else {
OPENTYPE_SCRIPTS[tag] = script;
}
}
export function fromUnicode(script) {

@@ -143,2 +155,6 @@ return UNICODE_SCRIPTS[script];

export function fromOpenType(tag) {
return OPENTYPE_SCRIPTS[tag];
}
export function forString(string) {

@@ -145,0 +161,0 @@ let len = string.length;

@@ -5,3 +5,3 @@ import unicode from 'unicode-properties';

export default class GlyphInfo {
constructor(font, id, codePoints = [], features = []) {
constructor(font, id, codePoints = [], features) {
this._font = font;

@@ -23,3 +23,3 @@ this.codePoints = codePoints;

this.ligatureComponent = null;
this.ligated = false;
this.isLigated = false;
this.cursiveAttachment = null;

@@ -29,2 +29,3 @@ this.markAttachment = null;

this.substituted = false;
this.isMultiplied = false;
}

@@ -40,12 +41,21 @@

if (this._font.GDEF && this._font.GDEF.glyphClassDef) {
let GDEF = this._font.GDEF;
if (GDEF && GDEF.glyphClassDef) {
// TODO: clean this up
let classID = OTProcessor.prototype.getClassID(id, this._font.GDEF.glyphClassDef);
let classID = OTProcessor.prototype.getClassID(id, GDEF.glyphClassDef);
this.isBase = classID === 1;
this.isLigature = classID === 2;
this.isMark = classID === 3;
this.isLigature = classID === 2;
this.markAttachmentType = GDEF.markAttachClassDef ? OTProcessor.prototype.getClassID(id, GDEF.markAttachClassDef) : 0;
} else {
this.isMark = this.codePoints.every(unicode.isMark);
this.isBase = !this.isMark;
this.isLigature = this.codePoints.length > 1;
this.markAttachmentType = 0;
}
}
copy() {
return new GlyphInfo(this._font, this.id, this.codePoints, this.features);
}
}
export default class GlyphIterator {
constructor(glyphs, flags) {
constructor(glyphs, options) {
this.glyphs = glyphs;
this.reset(flags);
this.reset(options);
}
reset(flags = {}) {
this.flags = flags;
this.index = 0;
reset(options = {}, index = 0) {
this.options = options;
this.flags = options.flags || {};
this.markAttachmentType = options.markAttachmentType || 0;
this.index = index;
}

@@ -16,6 +18,7 @@

shouldIgnore(glyph, flags) {
return ((flags.ignoreMarks && glyph.isMark) ||
(flags.ignoreBaseGlyphs && !glyph.isMark) ||
(flags.ignoreLigatures && glyph.isLigature));
shouldIgnore(glyph) {
return (this.flags.ignoreMarks && glyph.isMark) ||
(this.flags.ignoreBaseGlyphs && glyph.isBase) ||
(this.flags.ignoreLigatures && glyph.isLigature) ||
(this.markAttachmentType && glyph.isMark && glyph.markAttachmentType !== this.markAttachmentType);
}

@@ -25,3 +28,3 @@

this.index += dir;
while (0 <= this.index && this.index < this.glyphs.length && this.shouldIgnore(this.glyphs[this.index], this.flags)) {
while (0 <= this.index && this.index < this.glyphs.length && this.shouldIgnore(this.glyphs[this.index])) {
this.index += dir;

@@ -28,0 +31,0 @@ }

@@ -42,2 +42,3 @@ import OTProcessor from './OTProcessor';

glyph.substituted = true;
glyph.isMultiplied = true;
return glyph;

@@ -44,0 +45,0 @@ });

@@ -25,15 +25,25 @@ import ShapingPlan from './ShapingPlan';

setup(glyphs, features, script, language) {
setup(glyphRun) {
// Map glyphs to GlyphInfo objects so data can be passed between
// GSUB and GPOS without mutating the real (shared) Glyph objects.
this.glyphInfos = glyphs.map(glyph => new GlyphInfo(this.font, glyph.id, [...glyph.codePoints]));
this.glyphInfos = glyphRun.glyphs.map(glyph => new GlyphInfo(this.font, glyph.id, [...glyph.codePoints]));
// Select a script based on what is available in GSUB/GPOS.
let script = this.GSUBProcessor
? this.GSUBProcessor.selectScript(glyphRun.script, glyphRun.language)
: this.GPOSProcessor.selectScript(glyphRun.script, glyphRun.language);
// Choose a shaper based on the script, and setup a shaping plan.
// This determines which features to apply to which glyphs.
this.shaper = Shapers.choose(script);
this.plan = new ShapingPlan(this.font, script, language);
return this.shaper.plan(this.plan, this.glyphInfos, features);
this.plan = new ShapingPlan(this.font, script);
this.shaper.plan(this.plan, this.glyphInfos, glyphRun.features);
// Assign chosen features to output glyph run
for (let key in this.plan.allFeatures) {
glyphRun.features[key] = true;
}
}
substitute(glyphs) {
substitute(glyphRun) {
if (this.GSUBProcessor) {

@@ -43,25 +53,23 @@ this.plan.process(this.GSUBProcessor, this.glyphInfos);

// Map glyph infos back to normal Glyph objects
glyphs = this.glyphInfos.map(glyphInfo => this.font.getGlyph(glyphInfo.id, glyphInfo.codePoints));
glyphRun.glyphs = this.glyphInfos.map(glyphInfo => this.font.getGlyph(glyphInfo.id, glyphInfo.codePoints));
}
return glyphs;
}
position(glyphs, positions) {
position(glyphRun) {
if (this.shaper.zeroMarkWidths === 'BEFORE_GPOS') {
this.zeroMarkAdvances(positions);
this.zeroMarkAdvances(glyphRun.positions);
}
if (this.GPOSProcessor) {
this.plan.process(this.GPOSProcessor, this.glyphInfos, positions);
this.plan.process(this.GPOSProcessor, this.glyphInfos, glyphRun.positions);
}
if (this.shaper.zeroMarkWidths === 'AFTER_GPOS') {
this.zeroMarkAdvances(positions);
this.zeroMarkAdvances(glyphRun.positions);
}
// Reverse the glyphs and positions if the script is right-to-left
if (this.plan.direction === 'rtl') {
glyphs.reverse();
positions.reverse();
if (glyphRun.direction === 'rtl') {
glyphRun.glyphs.reverse();
glyphRun.positions.reverse();
}

@@ -68,0 +76,0 @@

@@ -32,2 +32,3 @@ import GlyphIterator from './GlyphIterator';

this.ligatureID = 1;
this.currentFeature = null;
}

@@ -44,4 +45,4 @@

for (let entry of this.table.scriptList) {
for (let s of script) {
for (let s of script) {
for (let entry of this.table.scriptList) {
if (entry.tag === s) {

@@ -61,6 +62,2 @@ return entry;

entry = this.findScript(script);
if (script) {
entry = this.findScript(script);
}
if (!entry) {

@@ -71,3 +68,3 @@ entry = this.findScript(DEFAULT_SCRIPTS);

if (!entry) {
return;
return this.scriptTag;
}

@@ -79,18 +76,23 @@

this.language = null;
this.languageTag = null;
changed = true;
}
if (!language && language !== this.langugeTag) {
if (!language || language !== this.languageTag) {
this.language = null;
for (let lang of this.script.langSysRecords) {
if (lang.tag === language) {
this.language = lang.langSys;
this.langugeTag = lang.tag;
changed = true;
this.languageTag = lang.tag;
break;
}
}
}
if (!this.language) {
this.language = this.script.defaultLangSys;
if (!this.language) {
this.language = this.script.defaultLangSys;
this.languageTag = null;
}
changed = true;
}

@@ -109,2 +111,4 @@

}
return this.scriptTag;
}

@@ -188,2 +192,3 @@

for (let {feature, lookup} of lookups) {
this.currentFeature = feature;
this.glyphIterator.reset(lookup.flags);

@@ -214,15 +219,23 @@

applyLookupList(lookupRecords) {
let options = this.glyphIterator.options;
let glyphIndex = this.glyphIterator.index;
for (let lookupRecord of lookupRecords) {
this.glyphIterator.index = glyphIndex;
// Reset flags and find glyph index for this lookup record
this.glyphIterator.reset(options, glyphIndex);
this.glyphIterator.increment(lookupRecord.sequenceIndex);
// Get the lookup and setup flags for subtables
let lookup = this.table.lookupList.get(lookupRecord.lookupListIndex);
this.glyphIterator.reset(lookup.flags, this.glyphIterator.index);
// Apply lookup subtables until one matches
for (let table of lookup.subTables) {
this.applyLookup(lookup.lookupType, table);
if (this.applyLookup(lookup.lookupType, table)) {
break;
}
}
}
this.glyphIterator.index = glyphIndex;
this.glyphIterator.reset(options, glyphIndex);
return true;

@@ -258,3 +271,3 @@ }

while (idx < sequence.length && glyph && fn(sequence[idx], glyph.id)) {
while (idx < sequence.length && glyph && fn(sequence[idx], glyph)) {
if (matched) {

@@ -277,7 +290,14 @@ matched.push(this.glyphIterator.index);

sequenceMatches(sequenceIndex, sequence) {
return this.match(sequenceIndex, sequence, (component, glyph) => component === glyph);
return this.match(sequenceIndex, sequence, (component, glyph) => component === glyph.id);
}
sequenceMatchIndices(sequenceIndex, sequence) {
return this.match(sequenceIndex, sequence, (component, glyph) => component === glyph, []);
return this.match(sequenceIndex, sequence, (component, glyph) => {
// If the current feature doesn't apply to this glyph,
if (!(this.currentFeature in glyph.features)) {
return false;
}
return component === glyph.id;
}, []);
}

@@ -287,3 +307,3 @@

return this.match(sequenceIndex, sequence, (coverage, glyph) =>
this.coverageIndex(coverage, glyph) >= 0
this.coverageIndex(coverage, glyph.id) >= 0
);

@@ -317,3 +337,3 @@ }

return this.match(sequenceIndex, sequence, (classID, glyph) =>
classID === this.getClassID(glyph, classDef)
classID === this.getClassID(glyph.id, classDef)
);

@@ -320,0 +340,0 @@ }

@@ -40,3 +40,4 @@ import unicode from 'unicode-properties';

static planPostprocessing(plan, userFeatures) {
plan.add([...COMMON_FEATURES, ...HORIZONTAL_FEATURES, ...userFeatures]);
plan.add([...COMMON_FEATURES, ...HORIZONTAL_FEATURES]);
plan.setFeatureOverrides(userFeatures);
}

@@ -43,0 +44,0 @@

import DefaultShaper from './DefaultShaper';
import ArabicShaper from './ArabicShaper';
import HangulShaper from './HangulShaper';
import IndicShaper from './IndicShaper';
import UniversalShaper from './UniversalShaper';

@@ -18,2 +19,22 @@

bng2: IndicShaper, // Bengali
beng: IndicShaper, // Bengali
dev2: IndicShaper, // Devanagari
deva: IndicShaper, // Devanagari
gjr2: IndicShaper, // Gujarati
gujr: IndicShaper, // Gujarati
guru: IndicShaper, // Gurmukhi
gur2: IndicShaper, // Gurmukhi
knda: IndicShaper, // Kannada
knd2: IndicShaper, // Kannada
mlm2: IndicShaper, // Malayalam
mlym: IndicShaper, // Malayalam
ory2: IndicShaper, // Oriya
orya: IndicShaper, // Oriya
taml: IndicShaper, // Tamil
tml2: IndicShaper, // Tamil
telu: IndicShaper, // Telugu
tel2: IndicShaper, // Telugu
khmr: IndicShaper, // Khmer
bali: UniversalShaper, // Balinese

@@ -70,6 +91,14 @@ batk: UniversalShaper, // Batak

export function choose(script) {
let shaper = SHAPERS[script];
if (shaper) { return shaper; }
if (!Array.isArray(script)) {
script = [script];
}
for (let s of script) {
let shaper = SHAPERS[s];
if (shaper) {
return shaper;
}
}
return DefaultShaper;
}

@@ -13,6 +13,5 @@ import * as Script from '../layout/Script';

export default class ShapingPlan {
constructor(font, script, language) {
constructor(font, script) {
this.font = font;
this.script = script;
this.language = language;
this.direction = Script.direction(script);

@@ -28,8 +27,13 @@ this.stages = [];

*/
_addFeatures(features) {
let stage = this.stages[this.stages.length - 1];
_addFeatures(features, global) {
let stageIndex = this.stages.length - 1;
let stage = this.stages[stageIndex];
for (let feature of features) {
if (!this.allFeatures[feature]) {
if (this.allFeatures[feature] == null) {
stage.push(feature);
this.allFeatures[feature] = true;
this.allFeatures[feature] = stageIndex;
if (global) {
this.globalFeatures[feature] = true;
}
}

@@ -40,11 +44,2 @@ }

/**
* Adds the given features to the global list
*/
_addGlobal(features) {
for (let feature of features) {
this.globalFeatures[feature] = true;
}
}
/**
* Add features to the last stage

@@ -62,12 +57,6 @@ */

if (Array.isArray(arg)) {
this._addFeatures(arg);
if (global) {
this._addGlobal(arg);
}
this._addFeatures(arg, global);
} else if (typeof arg === 'object') {
let features = (arg.global || []).concat(arg.local || []);
this._addFeatures(features);
if (arg.global) {
this._addGlobal(arg.global);
}
this._addFeatures(arg.global || [], true);
this._addFeatures(arg.local || [], false);
} else {

@@ -90,2 +79,19 @@ throw new Error("Unsupported argument to ShapingPlan#add");

setFeatureOverrides(features) {
if (Array.isArray(features)) {
this.add(features);
} else if (typeof features === 'object') {
for (let tag in features) {
if (features[tag]) {
this.add(tag);
} else if (this.allFeatures[tag] != null) {
let stage = this.stages[this.allFeatures[tag]];
stage.splice(stage.indexOf(tag), 1);
delete this.allFeatures[tag];
delete this.globalFeatures[tag];
}
}
}
}
/**

@@ -111,3 +117,3 @@ * Assigns the global features to the given glyphs

if (!positions) {
stage(this.font, glyphs, positions);
stage(this.font, glyphs, this);
}

@@ -114,0 +120,0 @@

@@ -49,6 +49,9 @@ import r from 'restructure';

let LookupFlags = new r.Bitfield(r.uint16, [
'rightToLeft', 'ignoreBaseGlyphs', 'ignoreLigatures',
'ignoreMarks', 'useMarkFilteringSet', null, 'markAttachmentType'
]);
let LookupFlags = new r.Struct({
markAttachmentType: r.uint8,
flags: new r.Bitfield(r.uint8, [
'rightToLeft', 'ignoreBaseGlyphs', 'ignoreLigatures',
'ignoreMarks', 'useMarkFilteringSet'
])
});

@@ -61,3 +64,3 @@ export function LookupList(SubTable) {

subTables: new r.Array(new r.Pointer(r.uint16, SubTable), 'subTableCount'),
markFilteringSet: r.uint16 // TODO: only present when flags says so...
markFilteringSet: new r.Optional(r.uint16, t => t.flags.flags.useMarkFilteringSet)
});

@@ -64,0 +67,0 @@

@@ -368,2 +368,6 @@ import r from 'restructure';

getAvailableFeatures(script, language) {
return this._layoutEngine.getAvailableFeatures(script, language);
}
_getBaseGlyph(glyph, characters = []) {

@@ -370,0 +374,0 @@ if (!this._glyphs[glyph]) {

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc