Socket
Socket
Sign inDemoInstall

opentype.js

Package Overview
Dependencies
Maintainers
1
Versions
47
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

opentype.js - npm Package Compare versions

Comparing version 0.4.9 to 0.4.10

src/tables/fvar.js

2

bower.json
{
"name": "opentype.js",
"version": "0.4.9",
"version": "0.4.10",
"main": "dist/opentype.js",

@@ -5,0 +5,0 @@ "keywords": [

@@ -38,3 +38,3 @@ # Contributing

7. Check if tests pass (currently this just runs the code through JSHint)
7. Check if tests pass

@@ -41,0 +41,0 @@ npm test

{
"name": "opentype.js",
"description": "OpenType font parser",
"version": "0.4.9",
"version": "0.4.10",
"author": {

@@ -29,3 +29,3 @@ "name": "Frederik De Bleser",

"start": "mkdirp build && parallelshell \"npm run watch\" \"node ./bin/server.js\"",
"test": "jshint . && jscs .",
"test": "mocha --recursive && jshint . && jscs .",
"browserify": "browserify src/opentype.js --bare --standalone opentype > dist/opentype.js",

@@ -40,2 +40,3 @@ "uglify": "browserify src/opentype.js --bare --standalone opentype -g uglifyify > dist/opentype.min.js",

"mkdirp": "^0.5.1",
"mocha": "^2.2.5",
"parallelshell": "^1.1.1",

@@ -42,0 +43,0 @@ "rimraf": "^2.4.0",

@@ -80,3 +80,8 @@ opentype.js

### Loading a font synchronously (Node.js)
Use `opentype.loadSync(url)` to load a font from a file and return a `Font` object.
Throws an error if the font could not be parsed. This only works in Node.js.
var font = opentype.loadSync('fonts/Roboto-Black.ttf');
### Writing a font

@@ -95,3 +100,3 @@ Once you have a `Font` object (either by using `opentype.load` or by creating a new one from scratch) you can write it

notdefPath.lineTo(100, 700);
// more drawing instructions....
// more drawing instructions....
var notdefGlyph = new opentype.Glyph({

@@ -103,3 +108,3 @@ name: '.notdef',

});
var aPath = new opentype.Path();

@@ -129,2 +134,4 @@ aPath.moveTo(100, 0);

* `unitsPerEm`: X/Y coordinates in fonts are stored as integers. This value determines the size of the grid. Common values are 2048 and 4096.
* `ascender`: Distance from baseline of highest ascender. In font units, not pixels.
* `descender`: Distance from baseline of lowest descender. In font units, not pixels.

@@ -180,3 +187,3 @@ #### `Font.getPath(text, x, y, fontSize, options)`

* `xMin`, `yMin`, `xMax`, `yMax`: The bounding box of the glyph.
* `path`: The raw, unscaled path of the glyph.
* `path`: The raw, unscaled path of the glyph.

@@ -220,2 +227,11 @@ ##### `Glyph.getPath(x, y, fontSize)`

##### `Path.toPathData(decimalPlaces)`
Convert the Path to a string of path data instructions.
See http://www.w3.org/TR/SVG/paths.html#PathData
* `decimalPlaces`: The amount of decimal places for floating-point values. (default: 2)
##### `Path.toSVG(decimalPlaces)`
Convert the path to a SVG <path> element, as a string.
* `decimalPlaces`: The amount of decimal places for floating-point values. (default: 2)
#### Path commands

@@ -231,3 +247,2 @@ * **Move To**: Move to a new position. This creates a new contour. Example: `{type: 'M', x: 100, y: 200}`

* Support for ligatures and contextual alternates.
* Support for SVG paths.

@@ -234,0 +249,0 @@ Thanks

@@ -0,1 +1,9 @@

0.4.10 (July 30, 2015)
======================
* Add loadSync method for Node.js.
* Unit tests for basic types and tables.
* Implement MACSTRING codec.
* Support multilingual names.
* Handle names of font variation axes and instances.
0.4.9 (June 23, 2015)

@@ -2,0 +10,0 @@ =====================

@@ -17,18 +17,20 @@ // The Font object

// OS X will complain if the names are empty, so we put a single space everywhere by default.
this.familyName = options.familyName || ' ';
this.styleName = options.styleName || ' ';
this.designer = options.designer || ' ';
this.designerURL = options.designerURL || ' ';
this.manufacturer = options.manufacturer || ' ';
this.manufacturerURL = options.manufacturerURL || ' ';
this.license = options.license || ' ';
this.licenseURL = options.licenseURL || ' ';
this.version = options.version || 'Version 0.1';
this.description = options.description || ' ';
this.copyright = options.copyright || ' ';
this.trademark = options.trademark || ' ';
this.names = {
fontFamily: {en: options.familyName || ' '},
fontSubfamily: {en: options.styleName || ' '},
designer: {en: options.designer || ' '},
designerURL: {en: options.designerURL || ' '},
manufacturer: {en: options.manufacturer || ' '},
manufacturerURL: {en: options.manufacturerURL || ' '},
license: {en: options.license || ' '},
licenseURL: {en: options.licenseURL || ' '},
version: {en: options.version || 'Version 0.1'},
description: {en: options.description || ' '},
copyright: {en: options.copyright || ' '},
trademark: {en: options.trademark || ' '}
};
this.unitsPerEm = options.unitsPerEm || 1000;
this.ascender = options.ascender;
this.descender = options.descender;
this.supported = true;
this.supported = true; // Deprecated: parseBuffer will throw an error if font is not supported.
this.glyphs = new glyphset.GlyphSet(this, options.glyphs || []);

@@ -117,6 +119,2 @@ this.encoding = new encoding.DefaultEncoding(this);

Font.prototype.forEachGlyph = function(text, x, y, fontSize, options, callback) {
if (!this.supported) {
return;
}
x = x !== undefined ? x : 0;

@@ -210,2 +208,9 @@ y = y !== undefined ? y : 0;

Font.prototype.getEnglishName = function(name) {
var translations = this.names[name];
if (translations) {
return translations.en;
}
};
// Validate

@@ -222,12 +227,14 @@ Font.prototype.validate = function() {

function assertStringAttribute(attrName) {
assert(_this[attrName] && _this[attrName].trim().length > 0, 'No ' + attrName + ' specified.');
function assertNamePresent(name) {
var englishName = _this.getEnglishName(name);
assert(englishName && englishName.trim().length > 0,
'No English ' + name + ' specified.');
}
// Identification information
assertStringAttribute('familyName');
assertStringAttribute('weightName');
assertStringAttribute('manufacturer');
assertStringAttribute('copyright');
assertStringAttribute('version');
assertNamePresent('fontFamily');
assertNamePresent('weightName');
assertNamePresent('manufacturer');
assertNamePresent('copyright');
assertNamePresent('version');

@@ -258,3 +265,5 @@ // Dimension information

Font.prototype.download = function() {
var fileName = this.familyName.replace(/\s/g, '') + '-' + this.styleName + '.otf';
var familyName = this.getEnglishName('fontFamily');
var styleName = this.getEnglishName('fontSubfamily');
var fileName = familyName.replace(/\s/g, '') + '-' + styleName + '.otf';
var buffer = this.toBuffer();

@@ -261,0 +270,0 @@

@@ -18,2 +18,3 @@ // opentype.js

var cff = require('./tables/cff');
var fvar = require('./tables/fvar');
var glyf = require('./tables/glyf');

@@ -25,2 +26,3 @@ var gpos = require('./tables/gpos');

var kern = require('./tables/kern');
var ltag = require('./tables/ltag');
var loca = require('./tables/loca');

@@ -74,12 +76,15 @@ var maxp = require('./tables/maxp');

// Parse the OpenType file data (as an ArrayBuffer) and return a Font object.
// If the file could not be parsed (most likely because it contains Postscript outlines)
// we return an empty Font object with the `supported` flag set to `false`.
// Throws an error if the font could not be parsed.
function parseBuffer(buffer) {
var indexToLocFormat;
var ltagTable;
var cffOffset;
var fvarOffset;
var glyfOffset;
var gposOffset;
var hmtxOffset;
var glyfOffset;
var kernOffset;
var locaOffset;
var cffOffset;
var kernOffset;
var gposOffset;
var nameOffset;

@@ -116,7 +121,6 @@ // OpenType fonts use big endian byte ordering.

font.encoding = new encoding.CmapEncoding(font.tables.cmap);
if (!font.encoding) {
font.supported = false;
}
break;
case 'fvar':
fvarOffset = offset;
break;
case 'head':

@@ -136,2 +140,5 @@ font.tables.head = head.parse(data, offset);

break;
case 'ltag':
ltagTable = ltag.parse(data, offset);
break;
case 'maxp':

@@ -142,5 +149,3 @@ font.tables.maxp = maxp.parse(data, offset);

case 'name':
font.tables.name = _name.parse(data, offset);
font.familyName = font.tables.name.fontFamily;
font.styleName = font.tables.name.fontSubfamily;
nameOffset = offset;
break;

@@ -173,2 +178,5 @@ case 'OS/2':

font.tables.name = _name.parse(data, nameOffset, ltagTable);
font.names = font.tables.name;
if (glyfOffset && locaOffset) {

@@ -184,17 +192,19 @@ var shortVersion = indexToLocFormat === 0;

} else {
font.supported = false;
throw new Error('Font doesn\'t contain TrueType or CFF outlines.');
}
if (font.supported) {
if (kernOffset) {
font.kerningPairs = kern.parse(data, kernOffset);
} else {
font.kerningPairs = {};
}
if (kernOffset) {
font.kerningPairs = kern.parse(data, kernOffset);
} else {
font.kerningPairs = {};
}
if (gposOffset) {
gpos.parse(data, gposOffset, font);
}
if (gposOffset) {
gpos.parse(data, gposOffset, font);
}
if (fvarOffset) {
font.tables.fvar = fvar.parse(data, fvarOffset, font.names);
}
return font;

@@ -218,6 +228,2 @@ }

var font = parseBuffer(arrayBuffer);
if (!font.supported) {
return callback('Font is not supported (is this a Postscript font?)');
}
return callback(null, font);

@@ -227,2 +233,10 @@ });

// Syncronously load the font from a URL or file.
// When done, return the font object or throw an error.
function loadSync(url) {
var fs = require('fs');
var buffer = fs.readFileSync(url);
return parseBuffer(toArrayBuffer(buffer));
}
exports._parse = parse;

@@ -234,1 +248,2 @@ exports.Font = _font.Font;

exports.load = load;
exports.loadSync = loadSync;

@@ -6,3 +6,5 @@ // The `name` naming table.

var encode = require('../types').encode;
var types = require('../types');
var decode = types.decode;
var encode = types.encode;
var parse = require('../parse');

@@ -38,12 +40,602 @@ var table = require('../table');

// Parse the naming `name` table
// Only Windows Unicode English names are supported.
// Format 1 additional fields are not supported
function parseNameTable(data, start) {
var macLanguages = {
0: 'en',
1: 'fr',
2: 'de',
3: 'it',
4: 'nl',
5: 'sv',
6: 'es',
7: 'da',
8: 'pt',
9: 'no',
10: 'he',
11: 'ja',
12: 'ar',
13: 'fi',
14: 'el',
15: 'is',
16: 'mt',
17: 'tr',
18: 'hr',
19: 'zh-Hant',
20: 'ur',
21: 'hi',
22: 'th',
23: 'ko',
24: 'lt',
25: 'pl',
26: 'hu',
27: 'es',
28: 'lv',
29: 'se',
30: 'fo',
31: 'fa',
32: 'ru',
33: 'zh',
34: 'nl-BE',
35: 'ga',
36: 'sq',
37: 'ro',
38: 'cz',
39: 'sk',
40: 'si',
41: 'yi',
42: 'sr',
43: 'mk',
44: 'bg',
45: 'uk',
46: 'be',
47: 'uz',
48: 'kk',
49: 'az-Cyrl',
50: 'az-Arab',
51: 'hy',
52: 'ka',
53: 'mo',
54: 'ky',
55: 'tg',
56: 'tk',
57: 'mn-CN',
58: 'mn',
59: 'ps',
60: 'ks',
61: 'ku',
62: 'sd',
63: 'bo',
64: 'ne',
65: 'sa',
66: 'mr',
67: 'bn',
68: 'as',
69: 'gu',
70: 'pa',
71: 'or',
72: 'ml',
73: 'kn',
74: 'ta',
75: 'te',
76: 'si',
77: 'my',
78: 'km',
79: 'lo',
80: 'vi',
81: 'id',
82: 'tl',
83: 'ms',
84: 'ms-Arab',
85: 'am',
86: 'ti',
87: 'om',
88: 'so',
89: 'sw',
90: 'rw',
91: 'rn',
92: 'ny',
93: 'mg',
94: 'eo',
128: 'cy',
129: 'eu',
130: 'ca',
131: 'la',
132: 'qu',
133: 'gn',
134: 'ay',
135: 'tt',
136: 'ug',
137: 'dz',
138: 'jv',
139: 'su',
140: 'gl',
141: 'af',
142: 'br',
143: 'iu',
144: 'gd',
145: 'gv',
146: 'ga',
147: 'to',
148: 'el-polyton',
149: 'kl',
150: 'az',
151: 'nn'
};
// MacOS language ID → MacOS script ID
//
// Note that the script ID is not sufficient to determine what encoding
// to use in TrueType files. For some languages, MacOS used a modification
// of a mainstream script. For example, an Icelandic name would be stored
// with smRoman in the TrueType naming table, but the actual encoding
// is a special Icelandic version of the normal Macintosh Roman encoding.
// As another example, Inuktitut uses an 8-bit encoding for Canadian Aboriginal
// Syllables but MacOS had run out of available script codes, so this was
// done as a (pretty radical) "modification" of Ethiopic.
//
// http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/Readme.txt
var macLanguageToScript = {
0: 0, // langEnglish → smRoman
1: 0, // langFrench → smRoman
2: 0, // langGerman → smRoman
3: 0, // langItalian → smRoman
4: 0, // langDutch → smRoman
5: 0, // langSwedish → smRoman
6: 0, // langSpanish → smRoman
7: 0, // langDanish → smRoman
8: 0, // langPortuguese → smRoman
9: 0, // langNorwegian → smRoman
10: 5, // langHebrew → smHebrew
11: 1, // langJapanese → smJapanese
12: 4, // langArabic → smArabic
13: 0, // langFinnish → smRoman
14: 6, // langGreek → smGreek
15: 0, // langIcelandic → smRoman (modified)
16: 0, // langMaltese → smRoman
17: 0, // langTurkish → smRoman (modified)
18: 0, // langCroatian → smRoman (modified)
19: 2, // langTradChinese → smTradChinese
20: 4, // langUrdu → smArabic
21: 9, // langHindi → smDevanagari
22: 21, // langThai → smThai
23: 3, // langKorean → smKorean
24: 29, // langLithuanian → smCentralEuroRoman
25: 29, // langPolish → smCentralEuroRoman
26: 29, // langHungarian → smCentralEuroRoman
27: 29, // langEstonian → smCentralEuroRoman
28: 29, // langLatvian → smCentralEuroRoman
29: 0, // langSami → smRoman
30: 0, // langFaroese → smRoman (modified)
31: 4, // langFarsi → smArabic (modified)
32: 7, // langRussian → smCyrillic
33: 25, // langSimpChinese → smSimpChinese
34: 0, // langFlemish → smRoman
35: 0, // langIrishGaelic → smRoman (modified)
36: 0, // langAlbanian → smRoman
37: 0, // langRomanian → smRoman (modified)
38: 29, // langCzech → smCentralEuroRoman
39: 29, // langSlovak → smCentralEuroRoman
40: 0, // langSlovenian → smRoman (modified)
41: 5, // langYiddish → smHebrew
42: 7, // langSerbian → smCyrillic
43: 7, // langMacedonian → smCyrillic
44: 7, // langBulgarian → smCyrillic
45: 7, // langUkrainian → smCyrillic (modified)
46: 7, // langByelorussian → smCyrillic
47: 7, // langUzbek → smCyrillic
48: 7, // langKazakh → smCyrillic
49: 7, // langAzerbaijani → smCyrillic
50: 4, // langAzerbaijanAr → smArabic
51: 24, // langArmenian → smArmenian
52: 23, // langGeorgian → smGeorgian
53: 7, // langMoldavian → smCyrillic
54: 7, // langKirghiz → smCyrillic
55: 7, // langTajiki → smCyrillic
56: 7, // langTurkmen → smCyrillic
57: 27, // langMongolian → smMongolian
58: 7, // langMongolianCyr → smCyrillic
59: 4, // langPashto → smArabic
60: 4, // langKurdish → smArabic
61: 4, // langKashmiri → smArabic
62: 4, // langSindhi → smArabic
63: 26, // langTibetan → smTibetan
64: 9, // langNepali → smDevanagari
65: 9, // langSanskrit → smDevanagari
66: 9, // langMarathi → smDevanagari
67: 13, // langBengali → smBengali
68: 13, // langAssamese → smBengali
69: 11, // langGujarati → smGujarati
70: 10, // langPunjabi → smGurmukhi
71: 12, // langOriya → smOriya
72: 17, // langMalayalam → smMalayalam
73: 16, // langKannada → smKannada
74: 14, // langTamil → smTamil
75: 15, // langTelugu → smTelugu
76: 18, // langSinhalese → smSinhalese
77: 19, // langBurmese → smBurmese
78: 20, // langKhmer → smKhmer
79: 22, // langLao → smLao
80: 30, // langVietnamese → smVietnamese
81: 0, // langIndonesian → smRoman
82: 0, // langTagalog → smRoman
83: 0, // langMalayRoman → smRoman
84: 4, // langMalayArabic → smArabic
85: 28, // langAmharic → smEthiopic
86: 28, // langTigrinya → smEthiopic
87: 28, // langOromo → smEthiopic
88: 0, // langSomali → smRoman
89: 0, // langSwahili → smRoman
90: 0, // langKinyarwanda → smRoman
91: 0, // langRundi → smRoman
92: 0, // langNyanja → smRoman
93: 0, // langMalagasy → smRoman
94: 0, // langEsperanto → smRoman
128: 0, // langWelsh → smRoman (modified)
129: 0, // langBasque → smRoman
130: 0, // langCatalan → smRoman
131: 0, // langLatin → smRoman
132: 0, // langQuechua → smRoman
133: 0, // langGuarani → smRoman
134: 0, // langAymara → smRoman
135: 7, // langTatar → smCyrillic
136: 4, // langUighur → smArabic
137: 26, // langDzongkha → smTibetan
138: 0, // langJavaneseRom → smRoman
139: 0, // langSundaneseRom → smRoman
140: 0, // langGalician → smRoman
141: 0, // langAfrikaans → smRoman
142: 0, // langBreton → smRoman (modified)
143: 28, // langInuktitut → smEthiopic (modified)
144: 0, // langScottishGaelic → smRoman (modified)
145: 0, // langManxGaelic → smRoman (modified)
146: 0, // langIrishGaelicScript → smRoman (modified)
147: 0, // langTongan → smRoman
148: 6, // langGreekAncient → smRoman
149: 0, // langGreenlandic → smRoman
150: 0, // langAzerbaijanRoman → smRoman
151: 0 // langNynorsk → smRoman
};
// While Microsoft indicates a region/country for all its language
// IDs, we omit the region code if it's equal to the "most likely
// region subtag" according to Unicode CLDR. For scripts, we omit
// the subtag if it is equal to the Suppress-Script entry in the
// IANA language subtag registry for IETF BCP 47.
//
// For example, Microsoft states that its language code 0x041A is
// Croatian in Croatia. We transform this to the BCP 47 language code 'hr'
// and not 'hr-HR' because Croatia is the default country for Croatian,
// according to Unicode CLDR. As another example, Microsoft states
// that 0x101A is Croatian (Latin) in Bosnia-Herzegovina. We transform
// this to 'hr-BA' and not 'hr-Latn-BA' because Latin is the default script
// for the Croatian language, according to IANA.
//
// http://www.unicode.org/cldr/charts/latest/supplemental/likely_subtags.html
// http://www.iana.org/assignments/language-subtag-registry/language-subtag-registry
var windowsLanguages = {
0x0436: 'af',
0x041C: 'sq',
0x0484: 'gsw',
0x045E: 'am',
0x1401: 'ar-DZ',
0x3C01: 'ar-BH',
0x0C01: 'ar',
0x0801: 'ar-IQ',
0x2C01: 'ar-JO',
0x3401: 'ar-KW',
0x3001: 'ar-LB',
0x1001: 'ar-LY',
0x1801: 'ary',
0x2001: 'ar-OM',
0x4001: 'ar-QA',
0x0401: 'ar-SA',
0x2801: 'ar-SY',
0x1C01: 'aeb',
0x3801: 'ar-AE',
0x2401: 'ar-YE',
0x042B: 'hy',
0x044D: 'as',
0x082C: 'az-Cyrl',
0x042C: 'az',
0x046D: 'ba',
0x042D: 'eu',
0x0423: 'be',
0x0845: 'bn',
0x0445: 'bn-IN',
0x201A: 'bs-Cyrl',
0x141A: 'bs',
0x047E: 'br',
0x0402: 'bg',
0x0403: 'ca',
0x0C04: 'zh-HK',
0x1404: 'zh-MO',
0x0804: 'zh',
0x1004: 'zh-SG',
0x0404: 'zh-TW',
0x0483: 'co',
0x041A: 'hr',
0x101A: 'hr-BA',
0x0405: 'cs',
0x0406: 'da',
0x048C: 'prs',
0x0465: 'dv',
0x0813: 'nl-BE',
0x0413: 'nl',
0x0C09: 'en-AU',
0x2809: 'en-BZ',
0x1009: 'en-CA',
0x2409: 'en-029',
0x4009: 'en-IN',
0x1809: 'en-IE',
0x2009: 'en-JM',
0x4409: 'en-MY',
0x1409: 'en-NZ',
0x3409: 'en-PH',
0x4809: 'en-SG',
0x1C09: 'en-ZA',
0x2C09: 'en-TT',
0x0809: 'en-GB',
0x0409: 'en',
0x3009: 'en-ZW',
0x0425: 'et',
0x0438: 'fo',
0x0464: 'fil',
0x040B: 'fi',
0x080C: 'fr-BE',
0x0C0C: 'fr-CA',
0x040C: 'fr',
0x140C: 'fr-LU',
0x180C: 'fr-MC',
0x100C: 'fr-CH',
0x0462: 'fy',
0x0456: 'gl',
0x0437: 'ka',
0x0C07: 'de-AT',
0x0407: 'de',
0x1407: 'de-LI',
0x1007: 'de-LU',
0x0807: 'de-CH',
0x0408: 'el',
0x046F: 'kl',
0x0447: 'gu',
0x0468: 'ha',
0x040D: 'he',
0x0439: 'hi',
0x040E: 'hu',
0x040F: 'is',
0x0470: 'ig',
0x0421: 'id',
0x045D: 'iu',
0x085D: 'iu-Latn',
0x083C: 'ga',
0x0434: 'xh',
0x0435: 'zu',
0x0410: 'it',
0x0810: 'it-CH',
0x0411: 'ja',
0x044B: 'kn',
0x043F: 'kk',
0x0453: 'km',
0x0486: 'quc',
0x0487: 'rw',
0x0441: 'sw',
0x0457: 'kok',
0x0412: 'ko',
0x0440: 'ky',
0x0454: 'lo',
0x0426: 'lv',
0x0427: 'lt',
0x082E: 'dsb',
0x046E: 'lb',
0x042F: 'mk',
0x083E: 'ms-BN',
0x043E: 'ms',
0x044C: 'ml',
0x043A: 'mt',
0x0481: 'mi',
0x047A: 'arn',
0x044E: 'mr',
0x047C: 'moh',
0x0450: 'mn',
0x0850: 'mn-CN',
0x0461: 'ne',
0x0414: 'nb',
0x0814: 'nn',
0x0482: 'oc',
0x0448: 'or',
0x0463: 'ps',
0x0415: 'pl',
0x0416: 'pt',
0x0816: 'pt-PT',
0x0446: 'pa',
0x046B: 'qu-BO',
0x086B: 'qu-EC',
0x0C6B: 'qu',
0x0418: 'ro',
0x0417: 'rm',
0x0419: 'ru',
0x243B: 'smn',
0x103B: 'smj-NO',
0x143B: 'smj',
0x0C3B: 'se-FI',
0x043B: 'se',
0x083B: 'se-SE',
0x203B: 'sms',
0x183B: 'sma-NO',
0x1C3B: 'sms',
0x044F: 'sa',
0x1C1A: 'sr-Cyrl-BA',
0x0C1A: 'sr',
0x181A: 'sr-Latn-BA',
0x081A: 'sr-Latn',
0x046C: 'nso',
0x0432: 'tn',
0x045B: 'si',
0x041B: 'sk',
0x0424: 'sl',
0x2C0A: 'es-AR',
0x400A: 'es-BO',
0x340A: 'es-CL',
0x240A: 'es-CO',
0x140A: 'es-CR',
0x1C0A: 'es-DO',
0x300A: 'es-EC',
0x440A: 'es-SV',
0x100A: 'es-GT',
0x480A: 'es-HN',
0x080A: 'es-MX',
0x4C0A: 'es-NI',
0x180A: 'es-PA',
0x3C0A: 'es-PY',
0x280A: 'es-PE',
0x500A: 'es-PR',
// Microsoft has defined two different language codes for
// “Spanish with modern sorting” and “Spanish with traditional
// sorting”. This makes sense for collation APIs, and it would be
// possible to express this in BCP 47 language tags via Unicode
// extensions (eg., es-u-co-trad is Spanish with traditional
// sorting). However, for storing names in fonts, the distinction
// does not make sense, so we give “es” in both cases.
0x0C0A: 'es',
0x040A: 'es',
0x540A: 'es-US',
0x380A: 'es-UY',
0x200A: 'es-VE',
0x081D: 'sv-FI',
0x041D: 'sv',
0x045A: 'syr',
0x0428: 'tg',
0x085F: 'tzm',
0x0449: 'ta',
0x0444: 'tt',
0x044A: 'te',
0x041E: 'th',
0x0451: 'bo',
0x041F: 'tr',
0x0442: 'tk',
0x0480: 'ug',
0x0422: 'uk',
0x042E: 'hsb',
0x0420: 'ur',
0x0843: 'uz-Cyrl',
0x0443: 'uz',
0x042A: 'vi',
0x0452: 'cy',
0x0488: 'wo',
0x0485: 'sah',
0x0478: 'ii',
0x046A: 'yo'
};
// Returns a IETF BCP 47 language code, for example 'zh-Hant'
// for 'Chinese in the traditional script'.
function getLanguageCode(platformID, languageID, ltag) {
switch (platformID) {
case 0: // Unicode
if (languageID === 0xFFFF) {
return 'und';
} else if (ltag) {
return ltag[languageID];
}
break;
case 1: // Macintosh
return macLanguages[languageID];
case 3: // Windows
return windowsLanguages[languageID];
}
return undefined;
}
var utf16 = 'utf-16';
// MacOS script ID → encoding. This table stores the default case,
// which can be overridden by macLanguageEncodings.
var macScriptEncodings = {
0: 'macintosh', // smRoman
1: 'x-mac-japanese', // smJapanese
2: 'x-mac-chinesetrad', // smTradChinese
3: 'x-mac-korean', // smKorean
6: 'x-mac-greek', // smGreek
7: 'x-mac-cyrillic', // smCyrillic
9: 'x-mac-devanagai', // smDevanagari
10: 'x-mac-gurmukhi', // smGurmukhi
11: 'x-mac-gujarati', // smGujarati
12: 'x-mac-oriya', // smOriya
13: 'x-mac-bengali', // smBengali
14: 'x-mac-tamil', // smTamil
15: 'x-mac-telugu', // smTelugu
16: 'x-mac-kannada', // smKannada
17: 'x-mac-malayalam', // smMalayalam
18: 'x-mac-sinhalese', // smSinhalese
19: 'x-mac-burmese', // smBurmese
20: 'x-mac-khmer', // smKhmer
21: 'x-mac-thai', // smThai
22: 'x-mac-lao', // smLao
23: 'x-mac-georgian', // smGeorgian
24: 'x-mac-armenian', // smArmenian
25: 'x-mac-chinesesimp', // smSimpChinese
26: 'x-mac-tibetan', // smTibetan
27: 'x-mac-mongolian', // smMongolian
28: 'x-mac-ethiopic', // smEthiopic
29: 'x-mac-ce', // smCentralEuroRoman
30: 'x-mac-vietnamese', // smVietnamese
31: 'x-mac-extarabic' // smExtArabic
};
// MacOS language ID → encoding. This table stores the exceptional
// cases, which override macScriptEncodings. For writing MacOS naming
// tables, we need to emit a MacOS script ID. Therefore, we cannot
// merge macScriptEncodings into macLanguageEncodings.
//
// http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/Readme.txt
var macLanguageEncodings = {
15: 'x-mac-icelandic', // langIcelandic
17: 'x-mac-turkish', // langTurkish
18: 'x-mac-croatian', // langCroatian
24: 'x-mac-ce', // langLithuanian
25: 'x-mac-ce', // langPolish
26: 'x-mac-ce', // langHungarian
27: 'x-mac-ce', // langEstonian
28: 'x-mac-ce', // langLatvian
30: 'x-mac-icelandic', // langFaroese
37: 'x-mac-romanian', // langRomanian
38: 'x-mac-ce', // langCzech
39: 'x-mac-ce', // langSlovak
40: 'x-mac-ce', // langSlovenian
143: 'x-mac-inuit', // langInuktitut
146: 'x-mac-gaelic' // langIrishGaelicScript
};
function getEncoding(platformID, encodingID, languageID) {
switch (platformID) {
case 0: // Unicode
return utf16;
case 1: // Apple Macintosh
return macLanguageEncodings[languageID] || macScriptEncodings[encodingID];
case 3: // Microsoft Windows
if (encodingID === 1 || encodingID === 10) {
return utf16;
}
break;
}
return undefined;
}
// Parse the naming `name` table.
// FIXME: Format 1 additional fields are not supported yet.
// ltag is the content of the `ltag' table, such as ['en', 'zh-Hans', 'de-CH-1904'].
function parseNameTable(data, start, ltag) {
var name = {};
var p = new parse.Parser(data, start);
name.format = p.parseUShort();
var format = p.parseUShort();
var count = p.parseUShort();
var stringOffset = p.offset + p.parseUShort();
var unknownCount = 0;
for (var i = 0; i < count; i++) {

@@ -54,29 +646,30 @@ var platformID = p.parseUShort();

var nameID = p.parseUShort();
var property = nameTableNames[nameID];
var property = nameTableNames[nameID] || nameID;
var byteLength = p.parseUShort();
var offset = p.parseUShort();
// platformID - encodingID - languageID standard combinations :
// 1 - 0 - 0 : Macintosh, Roman, English
// 3 - 1 - 0x409 : Windows, Unicode BMP (UCS-2), en-US
if (platformID === 3 && encodingID === 1 && languageID === 0x409) {
var codePoints = [];
var length = byteLength / 2;
for (var j = 0; j < length; j++, offset += 2) {
codePoints[j] = parse.getShort(data, stringOffset + offset);
var language = getLanguageCode(platformID, languageID, ltag);
var encoding = getEncoding(platformID, encodingID, languageID);
if (encoding !== undefined && language !== undefined) {
var text;
if (encoding === utf16) {
text = decode.UTF16(data, stringOffset + offset, byteLength);
} else {
text = decode.MACSTRING(data, stringOffset + offset, byteLength, encoding);
}
var str = String.fromCharCode.apply(null, codePoints);
if (property) {
name[property] = str;
if (text) {
var translations = name[property];
if (translations === undefined) {
translations = name[property] = {};
}
translations[language] = text;
}
else {
unknownCount++;
name['unknown' + unknownCount] = str;
}
}
}
if (name.format === 1) {
name.langTagCount = p.parseUShort();
var langTagCount = 0;
if (format === 1) {
// FIXME: Also handle Microsoft's 'name' table 1.
langTagCount = p.parseUShort();
}

@@ -87,2 +680,13 @@

// {23: 'foo'} → {'foo': 23}
// ['bar', 'baz'] → {'bar': 0, 'baz': 1}
function reverseDict(dict) {
var result = {};
for (var key in dict) {
result[dict[key]] = parseInt(key);
}
return result;
}
function makeNameRecord(platformID, encodingID, languageID, nameID, length, offset) {

@@ -99,56 +703,129 @@ return new table.Table('NameRecord', [

function addMacintoshNameRecord(t, recordID, s, offset) {
// Macintosh, Roman, English
var stringBytes = encode.STRING(s);
t.records.push(makeNameRecord(1, 0, 0, recordID, stringBytes.length, offset));
t.strings.push(stringBytes);
offset += stringBytes.length;
return offset;
// Finds the position of needle in haystack, or -1 if not there.
// Like String.indexOf(), but for arrays.
function findSubArray(needle, haystack) {
var needleLength = needle.length;
var limit = haystack.length - needleLength + 1;
loop:
for (var pos = 0; pos < limit; pos++) {
for (; pos < limit; pos++) {
for (var k = 0; k < needleLength; k++) {
if (haystack[pos + k] !== needle[k]) {
continue loop;
}
}
return pos;
}
}
return -1;
}
function addWindowsNameRecord(t, recordID, s, offset) {
// Windows, Unicode BMP (UCS-2), US English
var utf16Bytes = encode.UTF16(s);
t.records.push(makeNameRecord(3, 1, 0x0409, recordID, utf16Bytes.length, offset));
t.strings.push(utf16Bytes);
offset += utf16Bytes.length;
function addStringToPool(s, pool) {
var offset = findSubArray(s, pool);
if (offset < 0) {
offset = pool.length;
for (var i = 0, len = s.length; i < len; ++i) {
pool.push(s[i]);
}
}
return offset;
}
function makeNameTable(options) {
var t = new table.Table('name', [
{name: 'format', type: 'USHORT', value: 0},
{name: 'count', type: 'USHORT', value: 0},
{name: 'stringOffset', type: 'USHORT', value: 0}
]);
t.records = [];
t.strings = [];
var offset = 0;
var i;
var s;
// Add Macintosh records first
for (i = 0; i < nameTableNames.length; i += 1) {
if (options[nameTableNames[i]] !== undefined) {
s = options[nameTableNames[i]];
offset = addMacintoshNameRecord(t, i, s, offset);
function makeNameTable(names, ltag) {
var nameID;
var nameIDs = [];
var namesWithNumericKeys = {};
var nameTableIds = reverseDict(nameTableNames);
for (var key in names) {
var id = nameTableIds[key];
if (id === undefined) {
id = key;
}
nameID = parseInt(id);
namesWithNumericKeys[nameID] = names[key];
nameIDs.push(nameID);
}
// Then add Windows records
for (i = 0; i < nameTableNames.length; i += 1) {
if (options[nameTableNames[i]] !== undefined) {
s = options[nameTableNames[i]];
offset = addWindowsNameRecord(t, i, s, offset);
var macLanguageIds = reverseDict(macLanguages);
var windowsLanguageIds = reverseDict(windowsLanguages);
var nameRecords = [];
var stringPool = [];
for (var i = 0; i < nameIDs.length; i++) {
nameID = nameIDs[i];
var translations = namesWithNumericKeys[nameID];
for (var lang in translations) {
var text = translations[lang];
// For MacOS, we try to emit the name in the form that was introduced
// in the initial version of the TrueType spec (in the late 1980s).
// However, this can fail for various reasons: the requested BCP 47
// language code might not have an old-style Mac equivalent;
// we might not have a codec for the needed character encoding;
// or the name might contain characters that cannot be expressed
// in the old-style Macintosh encoding. In case of failure, we emit
// the name in a more modern fashion (Unicode encoding with BCP 47
// language tags) that is recognized by MacOS 10.5, released in 2009.
// If fonts were only read by operating systems, we could simply
// emit all names in the modern form; this would be much easier.
// However, there are many applications and libraries that read
// 'name' tables directly, and these will usually only recognize
// the ancient form (silently skipping the unrecognized names).
var macPlatform = 1; // Macintosh
var macLanguage = macLanguageIds[lang];
var macScript = macLanguageToScript[macLanguage];
var macEncoding = getEncoding(macPlatform, macScript, macLanguage);
var macName = encode.MACSTRING(text, macEncoding);
if (macName === undefined) {
macPlatform = 0; // Unicode
macLanguage = ltag.indexOf(lang);
if (macLanguage < 0) {
macLanguage = ltag.length;
ltag.push(lang);
}
macScript = 4; // Unicode 2.0 and later
macName = encode.UTF16(text);
}
var macNameOffset = addStringToPool(macName, stringPool);
nameRecords.push(makeNameRecord(macPlatform, macScript, macLanguage,
nameID, macName.length, macNameOffset));
var winLanguage = windowsLanguageIds[lang];
if (winLanguage !== undefined) {
var winName = encode.UTF16(text);
var winNameOffset = addStringToPool(winName, stringPool);
nameRecords.push(makeNameRecord(3, 1, winLanguage,
nameID, winName.length, winNameOffset));
}
}
}
t.count = t.records.length;
t.stringOffset = 6 + t.count * 12;
for (i = 0; i < t.records.length; i += 1) {
t.fields.push({name: 'record_' + i, type: 'TABLE', value: t.records[i]});
}
nameRecords.sort(function(a, b) {
return ((a.platformID - b.platformID) ||
(a.encodingID - b.encodingID) ||
(a.languageID - b.languageID) ||
(a.nameID - b.nameID));
});
for (i = 0; i < t.strings.length; i += 1) {
t.fields.push({name: 'string_' + i, type: 'LITERAL', value: t.strings[i]});
var t = new table.Table('name', [
{name: 'format', type: 'USHORT', value: 0},
{name: 'count', type: 'USHORT', value: nameRecords.length},
{name: 'stringOffset', type: 'USHORT', value: 6 + nameRecords.length * 12}
]);
for (var r = 0; r < nameRecords.length; r++) {
t.fields.push({name: 'record_' + r, type: 'TABLE', value: nameRecords[r]});
}
t.fields.push({name: 'strings', type: 'LITERAL', value: stringPool});
return t;

@@ -155,0 +832,0 @@ }

@@ -17,2 +17,3 @@ // The `sfnt` wrapper provides organization for the tables in the font.

var hmtx = require('./hmtx');
var ltag = require('./ltag');
var maxp = require('./maxp');

@@ -243,34 +244,50 @@ var _name = require('./name');

var fullName = font.familyName + ' ' + font.styleName;
var postScriptName = font.familyName.replace(/\s/g, '') + '-' + font.styleName;
var nameTable = _name.make({
copyright: font.copyright,
fontFamily: font.familyName,
fontSubfamily: font.styleName,
uniqueID: font.manufacturer + ':' + fullName,
fullName: fullName,
version: font.version,
postScriptName: postScriptName,
trademark: font.trademark,
manufacturer: font.manufacturer,
designer: font.designer,
description: font.description,
manufacturerURL: font.manufacturerURL,
designerURL: font.designerURL,
license: font.license,
licenseURL: font.licenseURL,
preferredFamily: font.familyName,
preferredSubfamily: font.styleName
});
var englishFamilyName = font.getEnglishName('fontFamily');
var englishStyleName = font.getEnglishName('fontSubfamily');
var englishFullName = englishFamilyName + ' ' + englishStyleName;
var postScriptName = font.getEnglishName('postScriptName');
if (!postScriptName) {
postScriptName = englishFamilyName.replace(/\s/g, '') + '-' + englishStyleName;
}
var names = {};
for (var n in font.names) {
names[n] = font.names[n];
}
if (!names.uniqueID) {
names.uniqueID = {en: font.getEnglishName('manufacturer') + ':' + englishFullName};
}
if (!names.postScriptName) {
names.postScriptName = {en: postScriptName};
}
if (!names.preferredFamily) {
names.preferredFamily = font.names.fontFamily;
}
if (!names.preferredSubfamily) {
names.preferredSubfamily = font.names.fontSubfamily;
}
var languageTags = [];
var nameTable = _name.make(names, languageTags);
var ltagTable = (languageTags.length > 0 ? ltag.make(languageTags) : undefined);
var postTable = post.make();
var cffTable = cff.make(font.glyphs, {
version: font.version,
fullName: fullName,
familyName: font.familyName,
weightName: font.styleName,
version: font.getEnglishName('version'),
fullName: englishFullName,
familyName: englishFamilyName,
weightName: englishStyleName,
postScriptName: postScriptName,
unitsPerEm: font.unitsPerEm
});
// Order the tables according to the the OpenType specification 1.4.
// The order does not matter because makeSfntTable() will sort them.
var tables = [headTable, hheaTable, maxpTable, os2Table, nameTable, cmapTable, postTable, cffTable, hmtxTable];
if (ltagTable) {
tables.push(ltagTable);
}

@@ -277,0 +294,0 @@ var sfntTable = makeSfntTable(tables);

@@ -39,3 +39,3 @@ // Data types used in the OpenType font file.

sizeOf.BYTE = constant(1);
sizeOf.CHAR = constant(1);

@@ -169,5 +169,5 @@ // Convert an ASCII string to a list of bytes.

sizeOf.NUMBER16 = constant(2);
sizeOf.NUMBER16 = constant(3);
// Convert a signed number between -(2^31) and +(2^31-1) to a four-byte value.
// Convert a signed number between -(2^31) and +(2^31-1) to a five-byte value.
// This is useful if you want to be sure you always use four bytes,

@@ -179,3 +179,3 @@ // at the expense of wasting a few bytes for smaller numbers.

sizeOf.NUMBER32 = constant(4);
sizeOf.NUMBER32 = constant(5);

@@ -228,8 +228,19 @@ encode.REAL = function(v) {

// Convert a ASCII string to a list of UTF16 bytes.
decode.UTF16 = function(data, offset, numBytes) {
var codePoints = [];
var numChars = numBytes / 2;
for (var j = 0; j < numChars; j++, offset += 2) {
codePoints[j] = data.getUint16(offset);
}
return String.fromCharCode.apply(null, codePoints);
};
// Convert a JavaScript string to UTF16-BE.
encode.UTF16 = function(v) {
var b = [];
for (var i = 0; i < v.length; i += 1) {
b.push(0);
b.push(v.charCodeAt(i));
var codepoint = v.charCodeAt(i);
b.push((codepoint >> 8) & 0xFF);
b.push(codepoint & 0xFF);
}

@@ -244,2 +255,163 @@

// Data for converting old eight-bit Macintosh encodings to Unicode.
// This representation is optimized for decoding; encoding is slower
// and needs more memory. The assumption is that all opentype.js users
// want to open fonts, but saving a font will be comperatively rare
// so it can be more expensive. Keyed by IANA character set name.
//
// Python script for generating these strings:
//
// s = u''.join([chr(c).decode('mac_greek') for c in range(128, 256)])
// print(s.encode('utf-8'))
var eightBitMacEncodings = {
'x-mac-croatian': // Python: 'mac_croatian'
'ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®Š™´¨≠ŽØ∞±≤≥∆µ∂∑∏š∫ªºΩžø' +
'¿¡¬√ƒ≈Ć«Č… ÀÃÕŒœĐ—“”‘’÷◊©⁄€‹›Æ»–·‚„‰ÂćÁčÈÍÎÏÌÓÔđÒÚÛÙıˆ˜¯πË˚¸Êæˇ',
'x-mac-cyrillic': // Python: 'mac_cyrillic'
'АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ†°Ґ£§•¶І®©™Ђђ≠Ѓѓ∞±≤≥іµґЈЄєЇїЉљЊњ' +
'јЅ¬√ƒ≈∆«»… ЋћЌќѕ–—“”‘’÷„ЎўЏџ№Ёёяабвгдежзийклмнопрстуфхцчшщъыьэю',
'x-mac-gaelic':
// http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/GAELIC.TXT
'ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØḂ±≤≥ḃĊċḊḋḞḟĠġṀæø' +
'ṁṖṗɼƒſṠ«»… ÀÃÕŒœ–—“”‘’ṡẛÿŸṪ€‹›Ŷŷṫ·Ỳỳ⁊ÂÊÁËÈÍÎÏÌÓÔ♣ÒÚÛÙıÝýŴŵẄẅẀẁẂẃ',
'x-mac-greek': // Python: 'mac_greek'
'Ĺ²É³ÖÜ΅àâä΄¨çéèê룙î‰ôö¦€ùûü†ΓΔΘΛΞΠß®©ΣΪ§≠°·Α±≤≥¥ΒΕΖΗΙΚΜΦΫΨΩ' +
'άΝ¬ΟΡ≈Τ«»… ΥΧΆΈœ–―“”‘’÷ΉΊΌΎέήίόΏύαβψδεφγηιξκλμνοπώρστθωςχυζϊϋΐΰ\u00AD',
'x-mac-icelandic': // Python: 'mac_iceland'
'ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûüÝ°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø' +
'¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€ÐðÞþý·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ',
'x-mac-inuit':
// http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/INUIT.TXT
'ᐃᐄᐅᐆᐊᐋᐱᐲᐳᐴᐸᐹᑉᑎᑏᑐᑑᑕᑖᑦᑭᑮᑯᑰᑲᑳᒃᒋᒌᒍᒎᒐᒑ°ᒡᒥᒦ•¶ᒧ®©™ᒨᒪᒫᒻᓂᓃᓄᓅᓇᓈᓐᓯᓰᓱᓲᓴᓵᔅᓕᓖᓗ' +
'ᓘᓚᓛᓪᔨᔩᔪᔫᔭ… ᔮᔾᕕᕖᕗ–—“”‘’ᕘᕙᕚᕝᕆᕇᕈᕉᕋᕌᕐᕿᖀᖁᖂᖃᖄᖅᖏᖐᖑᖒᖓᖔᖕᙱᙲᙳᙴᙵᙶᖖᖠᖡᖢᖣᖤᖥᖦᕼŁł',
'x-mac-ce': // Python: 'mac_latin2'
'ÄĀāÉĄÖÜáąČäčĆć鏟ĎíďĒēĖóėôöõúĚěü†°Ę£§•¶ß®©™ę¨≠ģĮįĪ≤≥īĶ∂∑łĻļĽľĹĺŅ' +
'ņѬ√ńŇ∆«»… ňŐÕőŌ–—“”‘’÷◊ōŔŕŘ‹›řŖŗŠ‚„šŚśÁŤťÍŽžŪÓÔūŮÚůŰűŲųÝýķŻŁżĢˇ',
macintosh: // Python: 'mac_roman'
'ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø' +
'¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€‹›fifl‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ',
'x-mac-romanian': // Python: 'mac_romanian'
'ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ĂȘ∞±≤≥¥µ∂∑∏π∫ªºΩăș' +
'¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€‹›Țț‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ',
'x-mac-turkish': // Python: 'mac_turkish'
'ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø' +
'¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸĞğİıŞş‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙˆ˜¯˘˙˚¸˝˛ˇ'
};
// Decodes an old-style Macintosh string. Returns either a Unicode JavaScript
// string, or 'undefined' if the encoding is unsupported. For example, we do
// not support Chinese, Japanese or Korean because these would need large
// mapping tables.
decode.MACSTRING = function(dataView, offset, dataLength, encoding) {
var table = eightBitMacEncodings[encoding];
if (table === undefined) {
return undefined;
}
var result = '';
for (var i = 0; i < dataLength; i++) {
var c = dataView.getUint8(offset + i);
// In all eight-bit Mac encodings, the characters 0x00..0x7F are
// mapped to U+0000..U+007F; we only need to look up the others.
if (c <= 0x7F) {
result += String.fromCharCode(c);
} else {
result += table[c & 0x7F];
}
}
return result;
};
// Helper function for encode.MACSTRING. Returns a dictionary for mapping
// Unicode character codes to their 8-bit MacOS equivalent. This table
// is not exactly a super cheap data structure, but we do not care because
// encoding Macintosh strings is only rarely needed in typical applications.
var macEncodingTableCache = typeof WeakMap === 'function' && new WeakMap();
var macEncodingCacheKeys;
var getMacEncodingTable = function(encoding) {
// Since we use encoding as a cache key for WeakMap, it has to be
// a String object and not a literal. And at least on NodeJS 2.10.1,
// WeakMap requires that the same String instance is passed for cache hits.
if (!macEncodingCacheKeys) {
macEncodingCacheKeys = {};
for (var e in eightBitMacEncodings) {
/*jshint -W053 */ // Suppress "Do not use String as a constructor."
macEncodingCacheKeys[e] = new String(e);
}
}
var cacheKey = macEncodingCacheKeys[encoding];
if (cacheKey === undefined) {
return undefined;
}
// We can't do "if (cache.has(key)) {return cache.get(key)}" here:
// since garbage collection may run at any time, it could also kick in
// between the calls to cache.has() and cache.get(). In that case,
// we would return 'undefined' even though we do support the encoding.
if (macEncodingTableCache) {
var cachedTable = macEncodingTableCache.get(cacheKey);
if (cachedTable !== undefined) {
return cachedTable;
}
}
var decodingTable = eightBitMacEncodings[encoding];
if (decodingTable === undefined) {
return undefined;
}
var encodingTable = {};
for (var i = 0; i < decodingTable.length; i++) {
encodingTable[decodingTable.charCodeAt(i)] = i + 0x80;
}
if (macEncodingTableCache) {
macEncodingTableCache.set(cacheKey, encodingTable);
}
return encodingTable;
};
// Encodes an old-style Macintosh string. Returns a byte array upon success.
// If the requested encoding is unsupported, or if the input string contains
// a character that cannot be expressed in the encoding, the function returns
// 'undefined'.
encode.MACSTRING = function(str, encoding) {
var table = getMacEncodingTable(encoding);
if (table === undefined) {
return undefined;
}
var result = [];
for (var i = 0; i < str.length; i++) {
var c = str.charCodeAt(i);
// In all eight-bit Mac encodings, the characters 0x00..0x7F are
// mapped to U+0000..U+007F; we only need to look up the others.
if (c >= 0x80) {
c = table[c];
if (c === undefined) {
// str contains a Unicode character that cannot be encoded
// in the requested encoding.
return undefined;
}
}
result.push(c);
}
return result;
};
sizeOf.MACSTRING = function(str, encoding) {
var b = encode.MACSTRING(str, encoding);
if (b !== undefined) {
return b.length;
} else {
return 0;
}
};
// Convert a list of values to a CFF INDEX structure.

@@ -354,4 +526,8 @@ // The values should be objects containing name / type / value.

encode.CHARSTRING = function(ops) {
if (wmm && wmm.has(ops)) {
return wmm.get(ops);
// See encode.MACSTRING for why we don't do "if (wmm && wmm.has(ops))".
if (wmm) {
var cachedValue = wmm.get(ops);
if (cachedValue !== undefined) {
return cachedValue;
}
}

@@ -387,2 +563,8 @@

sizeOf.OBJECT = function(v) {
var sizeOfFunction = sizeOf[v.type];
check.argument(sizeOfFunction !== undefined, 'No sizeOf function for type ' + v.type);
return sizeOfFunction(v.value);
};
// Convert a table object to bytes.

@@ -411,2 +593,21 @@ // A table contains a list of fields containing the metadata (name, type and default value).

sizeOf.TABLE = function(table) {
var numBytes = 0;
var length = table.fields.length;
for (var i = 0; i < length; i += 1) {
var field = table.fields[i];
var sizeOfFunction = sizeOf[field.type];
check.argument(sizeOfFunction !== undefined, 'No sizeOf function for field type ' + field.type);
var value = table[field.name];
if (value === undefined) {
value = field.value;
}
numBytes += sizeOfFunction(value);
}
return numBytes;
};
// Merge in a list of bytes.

@@ -413,0 +614,0 @@ encode.LITERAL = function(v) {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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

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

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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