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.5.8 to 1.6.0

src/tables/HVAR.js

7

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

@@ -17,3 +17,3 @@ "keywords": [

"prepublish": "make",
"coverage": "babel-node ./node_modules/.bin/isparta cover ./node_modules/.bin/_mocha"
"coverage": "BABEL_ENV=cover nyc mocha"
},

@@ -48,2 +48,3 @@ "main": "index.js",

"babel-cli": "^6.14.0",
"babel-plugin-istanbul": "^4.1.3",
"babel-plugin-transform-class-properties": "^6.16.0",

@@ -59,4 +60,4 @@ "babel-plugin-transform-decorators-legacy": "^1.3.4",

"iconv-lite": "^0.4.13",
"isparta": "^3.5.3",
"mocha": "^2.0.1",
"nyc": "^10.3.2",
"rollup": "^0.34.10",

@@ -63,0 +64,0 @@ "rollup-plugin-babel": "^2.6.1",

@@ -70,3 +70,3 @@ import isEqual from 'deep-equal';

let b = stream.readUInt8();
if (b <= 21) {
if (b < 28) {
if (b === 12) {

@@ -73,0 +73,0 @@ b = (b << 8) | stream.readUInt8();

@@ -25,8 +25,11 @@ import r from 'restructure';

if (this.topDictIndex.length !== 1) {
throw new Error("Only a single font is allowed in CFF");
if (this.version < 2) {
if (this.topDictIndex.length !== 1) {
throw new Error("Only a single font is allowed in CFF");
}
this.topDict = this.topDictIndex[0];
}
this.isCIDFont = (this.topDict.ROS != null);
this.isCIDFont = this.topDict.ROS != null;
return this;

@@ -36,2 +39,6 @@ }

string(sid) {
if (this.version >= 2) {
return null;
}
if (sid < standardStrings.length) {

@@ -44,8 +51,8 @@ return standardStrings[sid];

get topDict() {
return this.topDictIndex[0];
}
get postscriptName() {
if (this.version < 2) {
return this.nameIndex[0];
}
get postscriptName() {
return this.nameIndex[0];
return null;
}

@@ -67,2 +74,7 @@

getGlyphName(gid) {
// CFF2 glyph names are in the post table.
if (this.version >= 2) {
return null;
}
// CID-keyed fonts don't have glyph names

@@ -103,3 +115,5 @@ if (this.isCIDFont) {

fdForGlyph(gid) {
if (!this.topDict.FDSelect) { return null; }
if (!this.topDict.FDSelect) {
return null;
}

@@ -111,2 +125,3 @@ switch (this.topDict.FDSelect.version) {

case 3:
case 4:
let { ranges } = this.topDict.FDSelect;

@@ -142,3 +157,7 @@ let low = 0;

return this.topDict.Private;
if (this.version < 2) {
return this.topDict.Private;
}
return this.topDict.FDArray[0].Private;
}

@@ -145,0 +164,0 @@ }

@@ -8,4 +8,16 @@ import r from 'restructure';

getCFFVersion(ctx) {
while (ctx && !ctx.hdrSize) {
ctx = ctx.parent;
}
return ctx ? ctx.version : -1;
}
decode(stream, parent) {
let count = stream.readUInt16BE();
let version = this.getCFFVersion(parent);
let count = version >= 2
? stream.readUInt32BE()
: stream.readUInt16BE();
if (count === 0) {

@@ -12,0 +24,0 @@ return [];

@@ -5,2 +5,14 @@ import CFFDict from './CFFDict';

class CFFBlendOp {
static decode(stream, parent, operands) {
let numBlends = operands.pop();
// TODO: actually blend. For now just consume the deltas
// since we don't use any of the values anyway.
while (operands.length > numBlends) {
operands.pop();
}
}
}
export default new CFFDict([

@@ -25,3 +37,5 @@ // key name type default

[21, 'nominalWidthX', 'number', 0],
[22, 'vsindex', 'number', 0],
[23, 'blend', CFFBlendOp, null],
[19, 'Subrs', new CFFPointer(new CFFIndex, {type: 'local'}), null]
]);

@@ -10,2 +10,3 @@ import r from 'restructure';

import { ISOAdobeCharset, ExpertCharset, ExpertSubsetCharset } from './CFFCharsets';
import { ItemVariationStore } from '../tables/variations';

@@ -112,3 +113,3 @@ // Checks if an operand is an index of a predefined value,

let FDRange = new r.Struct({
let FDRange3 = new r.Struct({
first: r.uint16,

@@ -118,2 +119,7 @@ fd: r.uint8

let FDRange4 = new r.Struct({
first: r.uint32,
fd: r.uint16
});
let FDSelect = new r.VersionedStruct(r.uint8, {

@@ -126,4 +132,10 @@ 0: {

nRanges: r.uint16,
ranges: new r.Array(FDRange, 'nRanges'),
ranges: new r.Array(FDRange3, 'nRanges'),
sentinel: r.uint16
},
4: {
nRanges: r.uint32,
ranges: new r.Array(FDRange4, 'nRanges'),
sentinel: r.uint32
}

@@ -195,17 +207,34 @@ });

let CFFHeader = new r.Struct({
majorVersion: r.uint8,
minorVersion: r.uint8,
hdrSize: r.uint8,
offSize: r.uint8
});
let VariationStore = new r.Struct({
length: r.uint16,
itemVariationStore: ItemVariationStore
})
let CFFTop = new r.Struct({
header: CFFHeader,
nameIndex: new CFFIndex(new r.String('length')),
topDictIndex: new CFFIndex(CFFTopDict),
stringIndex: new CFFIndex(new r.String('length')),
globalSubrIndex: new CFFIndex()
let CFF2TopDict = new CFFDict([
[[12, 7], 'FontMatrix', 'array', [0.001, 0, 0, 0.001, 0, 0]],
[17, 'CharStrings', new CFFPointer(new CFFIndex), null],
[[12, 37], 'FDSelect', new CFFPointer(FDSelect), null],
[[12, 36], 'FDArray', new CFFPointer(new CFFIndex(FontDict)), null],
[24, 'vstore', new CFFPointer(VariationStore), null],
[25, 'maxstack', 'number', 193]
]);
let CFFTop = new r.VersionedStruct(r.fixed16, {
1: {
hdrSize: r.uint8,
offSize: r.uint8,
nameIndex: new CFFIndex(new r.String('length')),
topDictIndex: new CFFIndex(CFFTopDict),
stringIndex: new CFFIndex(new r.String('length')),
globalSubrIndex: new CFFIndex
},
2: {
hdrSize: r.uint8,
length: r.uint16,
topDict: CFF2TopDict,
globalSubrIndex: new CFFIndex
}
});
export default CFFTop;

@@ -9,2 +9,6 @@ import Glyph from './Glyph';

_getName() {
if (this._font.CFF2) {
return super._getName();
}
return this._font['CFF '].getGlyphName(this.id);

@@ -27,3 +31,3 @@ }

let cff = this._font['CFF '];
let cff = this._font.CFF2 || this._font['CFF '];
let str = cff.topDict.CharStrings[this.id];

@@ -54,7 +58,15 @@ let end = str.offset + str.length;

let vstore = cff.topDict.vstore && cff.topDict.vstore.itemVariationStore;
let vsindex = privateDict.vsindex;
let variationProcessor = this._font._variationProcessor;
function checkWidth() {
if (width == null) {
width = stack.shift() + privateDict.nominalWidthX;
}
}
function parseStems() {
if (stack.length % 2 !== 0) {
if (width === null) {
width = stack.shift() + privateDict.nominalWidthX;
}
checkWidth();
}

@@ -89,3 +101,3 @@

if (stack.length > 1) {
if (typeof width === 'undefined' || width === null) { width = stack.shift() + privateDict.nominalWidthX; }
checkWidth();
}

@@ -148,7 +160,14 @@

case 11: // return
if (cff.version >= 2) {
break;
}
return;
case 14: // endchar
if (cff.version >= 2) {
break;
}
if (stack.length > 0) {
if (typeof width === 'undefined' || width === null) { width = stack.shift() + privateDict.nominalWidthX; }
checkWidth();
}

@@ -162,2 +181,42 @@

case 15: { // vsindex
if (cff.version < 2) {
throw new Error('vsindex operator not supported in CFF v1');
}
vsindex = stack.pop();
break;
}
case 16: { // blend
if (cff.version < 2) {
throw new Error('blend operator not supported in CFF v1');
}
if (!variationProcessor) {
throw new Error('blend operator in non-variation font');
}
let blendVector = variationProcessor.getBlendVector(vstore, vsindex);
let numBlends = stack.pop();
let numOperands = numBlends * blendVector.length;
let delta = stack.length - numOperands;
let base = delta - numBlends;
for (let i = 0; i < numBlends; i++) {
let sum = stack[base + i];
for (let j = 0; j < blendVector.length; j++) {
sum += blendVector[j] * stack[delta++];
}
stack[base + i] = sum;
}
while (numOperands--) {
stack.pop();
}
break;
}
case 19: // hintmask

@@ -171,4 +230,3 @@ case 20: // cntrmask

if (stack.length > 2) {
if (typeof width === 'undefined' || width === null) { width = stack.shift() + privateDict.nominalWidthX; }
let haveWidth = true;
checkWidth();
}

@@ -183,3 +241,3 @@

if (stack.length > 1) {
if (typeof width === 'undefined' || width === null) { width = stack.shift() + privateDict.nominalWidthX; }
checkWidth();
}

@@ -542,4 +600,9 @@

parse();
if (open) {
path.closePath();
}
return path;
}
}

@@ -86,2 +86,6 @@ import { cache } from '../decorators';

if (this._font._variationProcessor && this._font.HVAR) {
advanceWidth += this._font._variationProcessor.getAdvanceAdjustment(this.id, this._font.HVAR);
}
return this._metrics = { advanceWidth, advanceHeight, leftBearing, topBearing };

@@ -88,0 +92,0 @@ }

@@ -28,2 +28,3 @@ const TUPLES_SHARE_POINT_NUMBERS = 0x8000;

this.normalizedCoords = this.normalizeCoords(coords);
this.blendVectors = new Map;
}

@@ -384,2 +385,96 @@

}
getAdvanceAdjustment(gid, table) {
let outerIndex, innerIndex;
if (table.advanceWidthMapping) {
let idx = gid;
if (idx >= table.advanceWidthMapping.mapCount) {
idx = table.advanceWidthMapping.mapCount - 1;
}
let entryFormat = table.advanceWidthMapping.entryFormat;
({outerIndex, innerIndex} = table.advanceWidthMapping.mapData[idx]);
} else {
outerIndex = 0;
innerIndex = gid;
}
return this.getMetricDelta(table.itemVariationStore, outerIndex, innerIndex);
}
// See pseudo code from `Font Variations Overview'
// in the OpenType specification.
getMetricDelta(itemStore, outerIndex, innerIndex) {
let varData = itemStore.itemVariationData[outerIndex];
let deltaSet = varData.deltaSets[innerIndex];
let blendVector = this.getBlendVector(itemStore, outerIndex);
let netAdjustment = 0;
for (let master = 0; master < varData.regionIndexCount; master++) {
netAdjustment += deltaSet.deltas[master] * blendVector[master];
}
return netAdjustment;
}
getBlendVector(itemStore, outerIndex) {
let varData = itemStore.itemVariationData[outerIndex];
if (this.blendVectors.has(varData)) {
return this.blendVectors.get(varData);
}
let normalizedCoords = this.normalizedCoords;
let blendVector = [];
// outer loop steps through master designs to be blended
for (let master = 0; master < varData.regionIndexCount; master++) {
let scalar = 1;
let regionIndex = varData.regionIndexes[master];
let axes = itemStore.variationRegionList.variationRegions[regionIndex];
// inner loop steps through axes in this region
for (let j = 0; j < axes.length; j++) {
let axis = axes[j];
let axisScalar;
// compute the scalar contribution of this axis
// ignore invalid ranges
if (axis.startCoord > axis.peakCoord || axis.peakCoord > axis.endCoord) {
axisScalar = 1;
} else if (axis.startCoord < 0 && axis.endCoord > 0 && axis.peakCoord !== 0) {
axisScalar = 1;
// peak of 0 means ignore this axis
} else if (axis.peakCoord === 0) {
axisScalar = 1;
// ignore this region if coords are out of range
} else if (normalizedCoords[j] < axis.startCoord || normalizedCoords[j] > axis.endCoord) {
axisScalar = 0;
// calculate a proportional factor
} else {
if (normalizedCoords[j] === axis.peakCoord) {
axisScalar = 1;
} else if (normalizedCoords[j] < axis.peakCoord) {
axisScalar = (normalizedCoords[j] - axis.startCoord + Number.EPSILON) /
(axis.peakCoord - axis.startCoord + Number.EPSILON);
} else {
axisScalar = (axis.endCoord - normalizedCoords[j] + Number.EPSILON) /
(axis.endCoord - axis.peakCoord + Number.EPSILON);
}
}
// take product of all the axis scalars
scalar *= axisScalar;
}
blendVector[master] = scalar;
}
this.blendVectors.set(varData, blendVector);
return blendVector;
}
}

@@ -281,4 +281,4 @@ import Glyph from './Glyph';

// Recompute and cache metrics if we performed variation processing
if (glyph.phantomPoints) {
// Recompute and cache metrics if we performed variation processing, and don't have an HVAR table
if (glyph.phantomPoints && !this._font.directory.tables.HVAR) {
this._metrics.advanceWidth = glyph.phantomPoints[1].x - glyph.phantomPoints[0].x;

@@ -312,5 +312,4 @@ this._metrics.advanceHeight = glyph.phantomPoints[3].y - glyph.phantomPoints[2].y;

if (this._font._variationProcessor) {
// Decode the font data (and cache for later).
// This triggers recomputation of metrics
if (this._font._variationProcessor && !this._font.HVAR) {
// No HVAR table, decode the glyph. This triggers recomputation of metrics.
this.path;

@@ -380,3 +379,3 @@ }

}
path.closePath();

@@ -383,0 +382,0 @@ }

@@ -20,2 +20,7 @@ import GlyphIterator from './GlyphIterator';

// Setup variation substitutions
this.variationsIndex = font._variationProcessor
? this.findVariationsIndex(font._variationProcessor.normalizedCoords)
: -1;
// initialize to default script + language

@@ -95,3 +100,4 @@ this.selectScript();

let record = this.table.featureList[featureIndex];
this.features[record.tag] = record.feature;
let substituteFeature = this.substituteFeatureForVariations(featureIndex);
this.features[record.tag] = substituteFeature || record.feature;
}

@@ -127,2 +133,42 @@ }

substituteFeatureForVariations(featureIndex) {
if (this.variationsIndex === -1) {
return null;
}
let record = this.table.featureVariations.featureVariationRecords[this.variationsIndex];
let substitutions = record.featureTableSubstitution.substitutions;
for (let substitution of substitutions) {
if (substitution.featureIndex === featureIndex) {
return substitution.alternateFeatureTable;
}
}
return null;
}
findVariationsIndex(coords) {
let variations = this.table.featureVariations;
if (!variations) {
return -1;
}
let records = variations.featureVariationRecords;
for (let i = 0; i < records.length; i++) {
let conditions = records[i].conditionSet.conditionTable;
if (this.variationConditionsMatch(conditions, coords)) {
return i;
}
}
return -1;
}
variationConditionsMatch(conditions, coords) {
return conditions.every(condition => {
let coord = condition.axisIndex < coords.length ? coords[condition.axisIndex] : 0;
return condition.filterRangeMinValue <= coord && coord <= condition.filterRangeMaxValue;
});
}
applyFeatures(userFeatures, glyphs, advances) {

@@ -129,0 +175,0 @@ let lookups = this.lookupsForFeatures(userFeatures);

import unicode from 'unicode-properties';
const VARIATION_FEATURES = ['rvrn'];
const COMMON_FEATURES = ['ccmp', 'locl', 'rlig', 'mark', 'mkmk'];

@@ -29,3 +30,3 @@ const FRACTIONAL_FEATURES = ['frac', 'numr', 'dnom'];

plan.add({
global: DIRECTIONAL_FEATURES[plan.direction],
global: [...VARIATION_FEATURES, ...DIRECTIONAL_FEATURES[plan.direction]],
local: FRACTIONAL_FEATURES

@@ -32,0 +33,0 @@ });

@@ -155,2 +155,5 @@ import Subset from './Subset';

let top = {
version: 1,
hdrSize: this.cff.hdrSize,
offSize: this.cff.length,
header: this.cff.header,

@@ -157,0 +160,0 @@ nameIndex: [this.cff.postscriptName],

import r from 'restructure';
import { ScriptList, FeatureList, LookupList, Coverage, ClassDef, Device } from './opentype';
import {ScriptList, FeatureList, LookupList, Coverage, ClassDef, Device} from './opentype';
import {ItemVariationStore} from './variations';

@@ -41,4 +42,4 @@ let AttachPoint = new r.Array(r.uint16, r.uint16);

export default new r.VersionedStruct(r.uint32, {
0x00010000: {
glyphClassDef: new r.Pointer(r.uint16, ClassDef), // 1: base glyph, 2: ligature, 3: mark, 4: component
header: {
glyphClassDef: new r.Pointer(r.uint16, ClassDef),
attachList: new r.Pointer(r.uint16, AttachList),

@@ -48,9 +49,11 @@ ligCaretList: new r.Pointer(r.uint16, LigCaretList),

},
0x00010000: {},
0x00010002: {
glyphClassDef: new r.Pointer(r.uint16, ClassDef),
attachList: new r.Pointer(r.uint16, AttachList),
ligCaretList: new r.Pointer(r.uint16, LigCaretList),
markAttachClassDef: new r.Pointer(r.uint16, ClassDef),
markGlyphSetsDef: new r.Pointer(r.uint16, MarkGlyphSetsDef)
},
0x00010003: {
markGlyphSetsDef: new r.Pointer(r.uint16, MarkGlyphSetsDef),
itemVariationStore: new r.Pointer(r.uint32, ItemVariationStore)
}
});
import r from 'restructure';
import { ScriptList, FeatureList, LookupList, Coverage, ClassDef, Device, Context, ChainingContext } from './opentype';
import {ScriptList, FeatureList, LookupList, Coverage, ClassDef, Device, Context, ChainingContext} from './opentype';
import {FeatureVariations} from './variations';

@@ -194,7 +195,13 @@ let ValueFormat = new r.Bitfield(r.uint16, [

export default new r.Struct({
version: r.int32,
scriptList: new r.Pointer(r.uint16, ScriptList),
featureList: new r.Pointer(r.uint16, FeatureList),
lookupList: new r.Pointer(r.uint16, new LookupList(GPOSLookup))
export default new r.VersionedStruct(r.uint32, {
header: {
scriptList: new r.Pointer(r.uint16, ScriptList),
featureList: new r.Pointer(r.uint16, FeatureList),
lookupList: new r.Pointer(r.uint16, new LookupList(GPOSLookup))
},
0x00010000: {},
0x00010001: {
featureVariations: new r.Pointer(r.uint32, FeatureVariations)
}
});

@@ -201,0 +208,0 @@

import r from 'restructure';
import { ScriptList, FeatureList, LookupList, Coverage, ClassDef, Device, Context, ChainingContext } from './opentype';
import {ScriptList, FeatureList, LookupList, Coverage, ClassDef, Device, Context, ChainingContext} from './opentype';
import {FeatureVariations} from './variations';

@@ -72,7 +73,13 @@ let Sequence = new r.Array(r.uint16, r.uint16);

export default new r.Struct({
version: r.int32,
scriptList: new r.Pointer(r.uint16, ScriptList),
featureList: new r.Pointer(r.uint16, FeatureList),
lookupList: new r.Pointer(r.uint16, new LookupList(GSUBLookup))
export default new r.VersionedStruct(r.uint32, {
header: {
scriptList: new r.Pointer(r.uint16, ScriptList),
featureList: new r.Pointer(r.uint16, FeatureList),
lookupList: new r.Pointer(r.uint16, new LookupList(GSUBLookup))
},
0x00010000: {},
0x00010001: {
featureVariations: new r.Pointer(r.uint32, FeatureVariations)
}
});

@@ -43,2 +43,3 @@ let tables = {};

tables['CFF '] = CFFFont;
tables['CFF2'] = CFFFont;
tables.VORG = VORG;

@@ -73,3 +74,7 @@

// OpenType variations tables
import HVAR from './HVAR';
tables.HVAR = HVAR;
// Other OpenType Tables

@@ -76,0 +81,0 @@ import DSIG from './DSIG';

@@ -36,3 +36,3 @@ import r from 'restructure';

let Feature = new r.Struct({
export let Feature = new r.Struct({
featureParams: r.uint16, // pointer

@@ -39,0 +39,0 @@ lookupCount: r.uint16,

@@ -29,2 +29,4 @@ import r from 'restructure';

this.stream = stream;
this.variationCoords = variationCoords;
this._directoryPos = this.stream.pos;

@@ -44,6 +46,2 @@ this._tables = {};

}
if (variationCoords) {
this._variationProcessor = new GlyphVariationProcessor(this, variationCoords);
}
}

@@ -377,3 +375,3 @@

} else if (this.directory.tables['CFF ']) {
} else if (this.directory.tables['CFF '] || this.directory.tables.CFF2) {
this._glyphs[glyph] = new CFFGlyph(glyph, characters, this);

@@ -430,2 +428,3 @@ }

*/
@cache
get variationAxes() {

@@ -456,2 +455,3 @@ let res = {};

*/
@cache
get namedVariations() {

@@ -485,4 +485,4 @@ let res = {};

getVariation(settings) {
if (!this.directory.tables.fvar || !this.directory.tables.gvar || !this.directory.tables.glyf) {
throw new Error('Variations require a font with the fvar, gvar, and glyf tables.');
if (!(this.directory.tables.fvar && ((this.directory.tables.gvar && this.directory.tables.glyf) || this.directory.tables.CFF2))) {
throw new Error('Variations require a font with the fvar, gvar and glyf, or CFF2 tables.');
}

@@ -517,2 +517,22 @@

@cache
get _variationProcessor() {
if (!this.fvar) {
return null;
}
let variationCoords = this.variationCoords;
// Ignore if no variation coords and not CFF2
if (!variationCoords && !this.CFF2) {
return null;
}
if (!variationCoords) {
variationCoords = this.fvar.axis.map(axis => axis.defaultValue);
}
return new GlyphVariationProcessor(this, variationCoords);
}
// Standardized format plugin API

@@ -519,0 +539,0 @@ getFont(name) {

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