opentype.js
Advanced tools
Comparing version 0.6.4 to 0.6.5
{ | ||
"name": "opentype.js", | ||
"version": "0.6.4", | ||
"version": "0.6.5", | ||
"main": "dist/opentype.js", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -64,2 +64,2 @@ # Contributing | ||
4. Commit (`git commit -a`) and create a tag (e.g. `git tag 1.2.1`). Push and push tags (`git push && git push --tags`). | ||
5. Run `npm publish` to publish the package to npm. Bower updates automatically. | ||
5. Once published, [Travis](https://travis-ci.org/) will push the new tagged release to npm. Bower updates automatically. |
{ | ||
"name": "opentype.js", | ||
"description": "OpenType font parser", | ||
"version": "0.6.4", | ||
"version": "0.6.5", | ||
"author": { | ||
@@ -30,4 +30,4 @@ "name": "Frederik De Bleser", | ||
"test": "mocha --recursive && jshint . && jscs .", | ||
"browserify": "browserify src/opentype.js --bare --standalone opentype > dist/opentype.js", | ||
"uglify": "browserify src/opentype.js --bare --standalone opentype -g uglifyify > dist/opentype.min.js", | ||
"browserify": "browserify src/opentype.js -p licensify --bare --standalone opentype > dist/opentype.js", | ||
"uglify": "browserify src/opentype.js -p licensify --bare --standalone opentype -g uglifyify > dist/opentype.min.js", | ||
"dist": "rimraf build && rimraf dist && mkdirp build && mkdirp dist && npm run test && npm run browserify && npm run uglify" | ||
@@ -40,7 +40,8 @@ }, | ||
"mkdirp": "^0.5.1", | ||
"mocha": "^2.4.5", | ||
"mocha": "^2.5.3", | ||
"parallelshell": "^2.0.0", | ||
"rimraf": "^2.5.2", | ||
"uglifyify": "^3.0.1", | ||
"watchify": "^3.7.0" | ||
"watchify": "^3.7.0", | ||
"licensify": "^3.1.2" | ||
}, | ||
@@ -47,0 +48,0 @@ "browser": { |
opentype.js | ||
=========== | ||
[![Join the chat at https://gitter.im/nodebox/opentype.js](https://badges.gitter.im/nodebox/opentype.js.svg)](https://gitter.im/nodebox/opentype.js) | ||
opentype.js is a JavaScript parser and writer for TrueType and OpenType fonts. | ||
@@ -4,0 +6,0 @@ |
@@ -0,1 +1,8 @@ | ||
0.6.5 (September 9, 2016) | ||
========================= | ||
* GSUB reading and writing by @fpirsch. This is still missing a user-friendly API. | ||
* Add support for cmap table format 12, which enables support for Unicode characters outside of the 0x0 - 0xFFFF range. | ||
* Better API documentation using [JSDoc](http://usejsdoc.org/). | ||
* Accessing xMin/... metrics works before path load. | ||
0.6.4 (June 30, 2016) | ||
@@ -2,0 +9,0 @@ ========================= |
@@ -5,2 +5,6 @@ // Run-time checking of preconditions. | ||
exports.fail = function(message) { | ||
throw new Error(message); | ||
}; | ||
// Precondition function that checks if the given predicate is true. | ||
@@ -10,3 +14,3 @@ // If not, it will throw an error. | ||
if (!predicate) { | ||
throw new Error(message); | ||
exports.fail(message); | ||
} | ||
@@ -13,0 +17,0 @@ }; |
@@ -124,5 +124,11 @@ // Glyph encoding | ||
// This is the encoding used for fonts created from scratch. | ||
// It loops through all glyphs and finds the appropriate unicode value. | ||
// Since it's linear time, other encodings will be faster. | ||
/** | ||
* This is the encoding used for fonts created from scratch. | ||
* It loops through all glyphs and finds the appropriate unicode value. | ||
* Since it's linear time, other encodings will be faster. | ||
* @exports opentype.DefaultEncoding | ||
* @class | ||
* @constructor | ||
* @param {opentype.Font} | ||
*/ | ||
function DefaultEncoding(font) { | ||
@@ -149,2 +155,8 @@ this.font = font; | ||
/** | ||
* @exports opentype.CmapEncoding | ||
* @class | ||
* @constructor | ||
* @param {Object} cmap - a object with the cmap encoded data | ||
*/ | ||
function CmapEncoding(cmap) { | ||
@@ -154,2 +166,6 @@ this.cmap = cmap; | ||
/** | ||
* @param {string} c - the character | ||
* @return {number} The glyph index. | ||
*/ | ||
CmapEncoding.prototype.charToGlyphIndex = function(c) { | ||
@@ -159,2 +175,9 @@ return this.cmap.glyphIndexMap[c.charCodeAt(0)] || 0; | ||
/** | ||
* @exports opentype.CffEncoding | ||
* @class | ||
* @constructor | ||
* @param {string} encoding - The encoding | ||
* @param {Array} charset - The charcater set. | ||
*/ | ||
function CffEncoding(encoding, charset) { | ||
@@ -165,2 +188,6 @@ this.encoding = encoding; | ||
/** | ||
* @param {string} s - The character | ||
* @return {number} The index. | ||
*/ | ||
CffEncoding.prototype.charToGlyphIndex = function(s) { | ||
@@ -172,2 +199,8 @@ var code = s.charCodeAt(0); | ||
/** | ||
* @exports opentype.GlyphNames | ||
* @class | ||
* @constructor | ||
* @param {Object} post | ||
*/ | ||
function GlyphNames(post) { | ||
@@ -203,2 +236,7 @@ var i; | ||
/** | ||
* Gets the index of a glyph by name. | ||
* @param {string} name - The glyph name | ||
* @return {number} The index | ||
*/ | ||
GlyphNames.prototype.nameToGlyphIndex = function(name) { | ||
@@ -208,2 +246,6 @@ return this.names.indexOf(name); | ||
/** | ||
* @param {number} gid | ||
* @return {string} | ||
*/ | ||
GlyphNames.prototype.glyphIndexToName = function(gid) { | ||
@@ -213,2 +255,6 @@ return this.names[gid]; | ||
/** | ||
* @alias opentype.addGlyphNames | ||
* @param {opentype.Font} | ||
*/ | ||
function addGlyphNames(font) { | ||
@@ -230,3 +276,3 @@ var glyph; | ||
glyph.name = font.cffEncoding.charset[i]; | ||
} else { | ||
} else if (font.glyphNames.names) { | ||
glyph.name = font.glyphNames.glyphIndexToName(i); | ||
@@ -233,0 +279,0 @@ } |
262
src/font.js
@@ -9,7 +9,41 @@ // The Font object | ||
var glyphset = require('./glyphset'); | ||
var Substitution = require('./substitution'); | ||
var util = require('./util'); | ||
// A Font represents a loaded OpenType font file. | ||
// It contains a set of glyphs and methods to draw text on a drawing context, | ||
// or to get a path representing the text. | ||
/** | ||
* @typedef FontOptions | ||
* @type Object | ||
* @property {Boolean} empty - whether to create a new empty font | ||
* @property {string} familyName | ||
* @property {string} styleName | ||
* @property {string=} fullName | ||
* @property {string=} postScriptName | ||
* @property {string=} designer | ||
* @property {string=} designerURL | ||
* @property {string=} manufacturer | ||
* @property {string=} manufacturerURL | ||
* @property {string=} license | ||
* @property {string=} licenseURL | ||
* @property {string=} version | ||
* @property {string=} description | ||
* @property {string=} copyright | ||
* @property {string=} trademark | ||
* @property {Number} unitsPerEm | ||
* @property {Number} ascender | ||
* @property {Number} descender | ||
* @property {Number} createdTimestamp | ||
* @property {string=} weightClass | ||
* @property {string=} widthClass | ||
* @property {string=} fsSelection | ||
*/ | ||
/** | ||
* A Font represents a loaded OpenType font file. | ||
* It contains a set of glyphs and methods to draw text on a drawing context, | ||
* or to get a path representing the text. | ||
* @exports opentype.Font | ||
* @class | ||
* @param {FontOptions} | ||
* @constructor | ||
*/ | ||
function Font(options) { | ||
@@ -58,6 +92,11 @@ options = options || {}; | ||
this.encoding = new encoding.DefaultEncoding(this); | ||
this.substitution = new Substitution(this); | ||
this.tables = this.tables || {}; | ||
} | ||
// Check if the font has a glyph for the given character. | ||
/** | ||
* Check if the font has a glyph for the given character. | ||
* @param {string} | ||
* @return {Boolean} | ||
*/ | ||
Font.prototype.hasChar = function(c) { | ||
@@ -67,5 +106,9 @@ return this.encoding.charToGlyphIndex(c) !== null; | ||
// Convert the given character to a single glyph index. | ||
// Note that this function assumes that there is a one-to-one mapping between | ||
// the given character and a glyph; for complex scripts this might not be the case. | ||
/** | ||
* Convert the given character to a single glyph index. | ||
* Note that this function assumes that there is a one-to-one mapping between | ||
* the given character and a glyph; for complex scripts this might not be the case. | ||
* @param {string} | ||
* @return {Number} | ||
*/ | ||
Font.prototype.charToGlyphIndex = function(s) { | ||
@@ -75,5 +118,9 @@ return this.encoding.charToGlyphIndex(s); | ||
// Convert the given character to a single Glyph object. | ||
// Note that this function assumes that there is a one-to-one mapping between | ||
// the given character and a glyph; for complex scripts this might not be the case. | ||
/** | ||
* Convert the given character to a single Glyph object. | ||
* Note that this function assumes that there is a one-to-one mapping between | ||
* the given character and a glyph; for complex scripts this might not be the case. | ||
* @param {string} | ||
* @return {opentype.Glyph} | ||
*/ | ||
Font.prototype.charToGlyph = function(c) { | ||
@@ -90,6 +137,10 @@ var glyphIndex = this.charToGlyphIndex(c); | ||
// Convert the given text to a list of Glyph objects. | ||
// Note that there is no strict one-to-one mapping between characters and | ||
// glyphs, so the list of returned glyphs can be larger or smaller than the | ||
// length of the given string. | ||
/** | ||
* Convert the given text to a list of Glyph objects. | ||
* Note that there is no strict one-to-one mapping between characters and | ||
* glyphs, so the list of returned glyphs can be larger or smaller than the | ||
* length of the given string. | ||
* @param {string} | ||
* @return {opentype.Glyph[]} | ||
*/ | ||
Font.prototype.stringToGlyphs = function(s) { | ||
@@ -105,2 +156,6 @@ var glyphs = []; | ||
/** | ||
* @param {string} | ||
* @return {Number} | ||
*/ | ||
Font.prototype.nameToGlyphIndex = function(name) { | ||
@@ -110,2 +165,6 @@ return this.glyphNames.nameToGlyphIndex(name); | ||
/** | ||
* @param {string} | ||
* @return {opentype.Glyph} | ||
*/ | ||
Font.prototype.nameToGlyph = function(name) { | ||
@@ -122,2 +181,6 @@ var glyphIndex = this.nametoGlyphIndex(name); | ||
/** | ||
* @param {Number} | ||
* @return {String} | ||
*/ | ||
Font.prototype.glyphIndexToName = function(gid) { | ||
@@ -131,6 +194,11 @@ if (!this.glyphNames.glyphIndexToName) { | ||
// Retrieve the value of the kerning pair between the left glyph (or its index) | ||
// and the right glyph (or its index). If no kerning pair is found, return 0. | ||
// The kerning value gets added to the advance width when calculating the spacing | ||
// between glyphs. | ||
/** | ||
* Retrieve the value of the kerning pair between the left glyph (or its index) | ||
* and the right glyph (or its index). If no kerning pair is found, return 0. | ||
* The kerning value gets added to the advance width when calculating the spacing | ||
* between glyphs. | ||
* @param {opentype.Glyph} leftGlyph | ||
* @param {opentype.Glyph} rightGlyph | ||
* @return {Number} | ||
*/ | ||
Font.prototype.getKerningValue = function(leftGlyph, rightGlyph) { | ||
@@ -144,4 +212,18 @@ leftGlyph = leftGlyph.index || leftGlyph; | ||
// Helper function that invokes the given callback for each glyph in the given text. | ||
// The callback gets `(glyph, x, y, fontSize, options)`. | ||
/** | ||
* @typedef GlyphRenderOptions | ||
* @type Object | ||
* @property {boolean} [kerning] - whether to include kerning values | ||
*/ | ||
/** | ||
* Helper function that invokes the given callback for each glyph in the given text. | ||
* The callback gets `(glyph, x, y, fontSize, options)`.* @param {string} text | ||
* @param {string} text - The text to apply. | ||
* @param {number} [x=0] - Horizontal position of the beginning of the text. | ||
* @param {number} [y=0] - Vertical position of the *baseline* of the text. | ||
* @param {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. | ||
* @param {GlyphRenderOptions=} options | ||
* @param {Function} callback | ||
*/ | ||
Font.prototype.forEachGlyph = function(text, x, y, fontSize, options, callback) { | ||
@@ -169,12 +251,11 @@ x = x !== undefined ? x : 0; | ||
// Create a Path object that represents the given text. | ||
// | ||
// text - The text to create. | ||
// x - Horizontal position of the beginning of the text. (default: 0) | ||
// y - Vertical position of the *baseline* of the text. (default: 0) | ||
// fontSize - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. (default: 72) | ||
// Options is an optional object that contains: | ||
// - kerning - Whether to take kerning information into account. (default: true) | ||
// | ||
// Returns a Path object. | ||
/** | ||
* Create a Path object that represents the given text. | ||
* @param {string} text - The text to create. | ||
* @param {number} [x=0] - Horizontal position of the beginning of the text. | ||
* @param {number} [y=0] - Vertical position of the *baseline* of the text. | ||
* @param {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. | ||
* @param {GlyphRenderOptions=} options | ||
* @return {opentype.Path} | ||
*/ | ||
Font.prototype.getPath = function(text, x, y, fontSize, options) { | ||
@@ -190,12 +271,11 @@ var fullPath = new path.Path(); | ||
// Create an array of Path objects that represent the glyps of a given text. | ||
// | ||
// text - The text to create. | ||
// x - Horizontal position of the beginning of the text. (default: 0) | ||
// y - Vertical position of the *baseline* of the text. (default: 0) | ||
// fontSize - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. (default: 72) | ||
// Options is an optional object that contains: | ||
// - kerning - Whether to take kerning information into account. (default: true) | ||
// | ||
// Returns an array of Path objects. | ||
/** | ||
* Create an array of Path objects that represent the glyps of a given text. | ||
* @param {string} text - The text to create. | ||
* @param {number} [x=0] - Horizontal position of the beginning of the text. | ||
* @param {number} [y=0] - Vertical position of the *baseline* of the text. | ||
* @param {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. | ||
* @param {GlyphRenderOptions=} options | ||
* @return {opentype.Path[]} | ||
*/ | ||
Font.prototype.getPaths = function(text, x, y, fontSize, options) { | ||
@@ -211,11 +291,11 @@ var glyphPaths = []; | ||
// Draw the text on the given drawing context. | ||
// | ||
// ctx - A 2D drawing context, like Canvas. | ||
// text - The text to create. | ||
// x - Horizontal position of the beginning of the text. (default: 0) | ||
// y - Vertical position of the *baseline* of the text. (default: 0) | ||
// fontSize - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. (default: 72) | ||
// Options is an optional object that contains: | ||
// - kerning - Whether to take kerning information into account. (default: true) | ||
/** | ||
* Draw the text on the given drawing context. | ||
* @param {CanvasRenderingContext2D} ctx - A 2D drawing context, like Canvas. | ||
* @param {string} text - The text to create. | ||
* @param {number} [x=0] - Horizontal position of the beginning of the text. | ||
* @param {number} [y=0] - Vertical position of the *baseline* of the text. | ||
* @param {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. | ||
* @param {GlyphRenderOptions=} options | ||
*/ | ||
Font.prototype.draw = function(ctx, text, x, y, fontSize, options) { | ||
@@ -225,12 +305,12 @@ this.getPath(text, x, y, fontSize, options).draw(ctx); | ||
// Draw the points of all glyphs in the text. | ||
// On-curve points will be drawn in blue, off-curve points will be drawn in red. | ||
// | ||
// ctx - A 2D drawing context, like Canvas. | ||
// text - The text to create. | ||
// x - Horizontal position of the beginning of the text. (default: 0) | ||
// y - Vertical position of the *baseline* of the text. (default: 0) | ||
// fontSize - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. (default: 72) | ||
// Options is an optional object that contains: | ||
// - kerning - Whether to take kerning information into account. (default: true) | ||
/** | ||
* Draw the points of all glyphs in the text. | ||
* On-curve points will be drawn in blue, off-curve points will be drawn in red. | ||
* @param {CanvasRenderingContext2D} ctx - A 2D drawing context, like Canvas. | ||
* @param {string} text - The text to create. | ||
* @param {number} [x=0] - Horizontal position of the beginning of the text. | ||
* @param {number} [y=0] - Vertical position of the *baseline* of the text. | ||
* @param {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. | ||
* @param {GlyphRenderOptions=} options | ||
*/ | ||
Font.prototype.drawPoints = function(ctx, text, x, y, fontSize, options) { | ||
@@ -242,14 +322,14 @@ this.forEachGlyph(text, x, y, fontSize, options, function(glyph, gX, gY, gFontSize) { | ||
// Draw lines indicating important font measurements for all glyphs in the text. | ||
// Black lines indicate the origin of the coordinate system (point 0,0). | ||
// Blue lines indicate the glyph bounding box. | ||
// Green line indicates the advance width of the glyph. | ||
// | ||
// ctx - A 2D drawing context, like Canvas. | ||
// text - The text to create. | ||
// x - Horizontal position of the beginning of the text. (default: 0) | ||
// y - Vertical position of the *baseline* of the text. (default: 0) | ||
// fontSize - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. (default: 72) | ||
// Options is an optional object that contains: | ||
// - kerning - Whether to take kerning information into account. (default: true) | ||
/** | ||
* Draw lines indicating important font measurements for all glyphs in the text. | ||
* Black lines indicate the origin of the coordinate system (point 0,0). | ||
* Blue lines indicate the glyph bounding box. | ||
* Green line indicates the advance width of the glyph. | ||
* @param {CanvasRenderingContext2D} ctx - A 2D drawing context, like Canvas. | ||
* @param {string} text - The text to create. | ||
* @param {number} [x=0] - Horizontal position of the beginning of the text. | ||
* @param {number} [y=0] - Vertical position of the *baseline* of the text. | ||
* @param {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. | ||
* @param {GlyphRenderOptions=} options | ||
*/ | ||
Font.prototype.drawMetrics = function(ctx, text, x, y, fontSize, options) { | ||
@@ -261,2 +341,6 @@ this.forEachGlyph(text, x, y, fontSize, options, function(glyph, gX, gY, gFontSize) { | ||
/** | ||
* @param {string} | ||
* @return {string} | ||
*/ | ||
Font.prototype.getEnglishName = function(name) { | ||
@@ -269,3 +353,5 @@ var translations = this.names[name]; | ||
// Validate | ||
/** | ||
* Validate | ||
*/ | ||
Font.prototype.validate = function() { | ||
@@ -298,8 +384,13 @@ var warnings = []; | ||
// Convert the font object to a SFNT data structure. | ||
// This structure contains all the necessary tables and metadata to create a binary OTF file. | ||
/** | ||
* Convert the font object to a SFNT data structure. | ||
* This structure contains all the necessary tables and metadata to create a binary OTF file. | ||
* @return {opentype.Table} | ||
*/ | ||
Font.prototype.toTables = function() { | ||
return sfnt.fontToTable(this); | ||
}; | ||
/** | ||
* @deprecated Font.toBuffer is deprecated. Use Font.toArrayBuffer instead. | ||
*/ | ||
Font.prototype.toBuffer = function() { | ||
@@ -309,3 +400,6 @@ console.warn('Font.toBuffer is deprecated. Use Font.toArrayBuffer instead.'); | ||
}; | ||
/** | ||
* Converts a `opentype.Font` into an `ArrayBuffer` | ||
* @return {ArrayBuffer} | ||
*/ | ||
Font.prototype.toArrayBuffer = function() { | ||
@@ -323,3 +417,5 @@ var sfntTable = this.toTables(); | ||
// Initiate a download of the OpenType font. | ||
/** | ||
* Initiate a download of the OpenType font. | ||
*/ | ||
Font.prototype.download = function() { | ||
@@ -348,3 +444,3 @@ var familyName = this.getEnglishName('fontFamily'); | ||
function(err) { | ||
throw err; | ||
throw new Error(err.name + ': ' + err.message); | ||
}); | ||
@@ -357,3 +453,5 @@ } else { | ||
}; | ||
/** | ||
* @private | ||
*/ | ||
Font.prototype.fsSelectionValues = { | ||
@@ -372,2 +470,5 @@ ITALIC: 0x001, //1 | ||
/** | ||
* @private | ||
*/ | ||
Font.prototype.usWidthClasses = { | ||
@@ -385,2 +486,5 @@ ULTRA_CONDENSED: 1, | ||
/** | ||
* @private | ||
*/ | ||
Font.prototype.usWeightClasses = { | ||
@@ -387,0 +491,0 @@ THIN: 100, |
101
src/glyph.js
@@ -27,2 +27,14 @@ // The Glyph object | ||
} | ||
/** | ||
* @typedef GlyphOptions | ||
* @type Object | ||
* @property {string} [name] - The glyph name | ||
* @property {number} [unicode] | ||
* @property {Array} [unicodes] | ||
* @property {number} [xMin] | ||
* @property {number} [yMin] | ||
* @property {number} [xMax] | ||
* @property {number} [yMax] | ||
* @property {number} [advanceWidth] | ||
*/ | ||
@@ -34,2 +46,8 @@ // A Glyph is an individual mark that often corresponds to a character. | ||
// The `Glyph` class contains utility methods for drawing the path and its points. | ||
/** | ||
* @exports opentype.Glyph | ||
* @class | ||
* @param {GlyphOptions} | ||
* @constructor | ||
*/ | ||
function Glyph(options) { | ||
@@ -41,2 +59,5 @@ // By putting all the code on a prototype function (which is only declared once) | ||
/** | ||
* @param {GlyphOptions} | ||
*/ | ||
Glyph.prototype.bindConstructorValues = function(options) { | ||
@@ -78,2 +99,5 @@ this.index = options.index || 0; | ||
/** | ||
* @param {number} | ||
*/ | ||
Glyph.prototype.addUnicode = function(unicode) { | ||
@@ -87,8 +111,10 @@ if (this.unicodes.length === 0) { | ||
// Convert the glyph to a Path we can draw on a drawing context. | ||
// | ||
// x - Horizontal position of the glyph. (default: 0) | ||
// y - Vertical position of the *baseline* of the glyph. (default: 0) | ||
// fontSize - Font size, in pixels (default: 72). | ||
// options - xScale and yScale to strech the glyph. | ||
/** | ||
* Convert the glyph to a Path we can draw on a drawing context. | ||
* @param {number} [x=0] - Horizontal position of the beginning of the text. | ||
* @param {number} [y=0] - Vertical position of the *baseline* of the text. | ||
* @param {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. | ||
* @param {Object=} options - xScale, yScale to strech the glyph. | ||
* @return {opentype.Path} | ||
*/ | ||
Glyph.prototype.getPath = function(x, y, fontSize, options) { | ||
@@ -126,5 +152,8 @@ x = x !== undefined ? x : 0; | ||
// Split the glyph into contours. | ||
// This function is here for backwards compatibility, and to | ||
// provide raw access to the TrueType glyph outlines. | ||
/** | ||
* Split the glyph into contours. | ||
* This function is here for backwards compatibility, and to | ||
* provide raw access to the TrueType glyph outlines. | ||
* @return {Array} | ||
*/ | ||
Glyph.prototype.getContours = function() { | ||
@@ -150,3 +179,6 @@ if (this.points === undefined) { | ||
// Calculate the xMin/yMin/xMax/yMax/lsb/rsb for a Glyph. | ||
/** | ||
* Calculate the xMin/yMin/xMax/yMax/lsb/rsb for a Glyph. | ||
* @return {Object} | ||
*/ | ||
Glyph.prototype.getMetrics = function() { | ||
@@ -202,9 +234,10 @@ var commands = this.path.commands; | ||
// Draw the glyph on the given context. | ||
// | ||
// ctx - The drawing context. | ||
// x - Horizontal position of the glyph. (default: 0) | ||
// y - Vertical position of the *baseline* of the glyph. (default: 0) | ||
// fontSize - Font size, in pixels (default: 72). | ||
// options - xScale, yScale to strech the glyph | ||
/** | ||
* Draw the glyph on the given context. | ||
* @param {CanvasRenderingContext2D} ctx - A 2D drawing context, like Canvas. | ||
* @param {number} [x=0] - Horizontal position of the beginning of the text. | ||
* @param {number} [y=0] - Vertical position of the *baseline* of the text. | ||
* @param {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. | ||
* @param {Object=} options - xScale, yScale to strech the glyph. | ||
*/ | ||
Glyph.prototype.draw = function(ctx, x, y, fontSize, options) { | ||
@@ -214,9 +247,10 @@ this.getPath(x, y, fontSize, options).draw(ctx); | ||
// Draw the points of the glyph. | ||
// On-curve points will be drawn in blue, off-curve points will be drawn in red. | ||
// | ||
// ctx - The drawing context. | ||
// x - Horizontal position of the glyph. (default: 0) | ||
// y - Vertical position of the *baseline* of the glyph. (default: 0) | ||
// fontSize - Font size, in pixels (default: 72). | ||
/** | ||
* Draw the points of the glyph. | ||
* On-curve points will be drawn in blue, off-curve points will be drawn in red. | ||
* @param {CanvasRenderingContext2D} ctx - A 2D drawing context, like Canvas. | ||
* @param {number} [x=0] - Horizontal position of the beginning of the text. | ||
* @param {number} [y=0] - Vertical position of the *baseline* of the text. | ||
* @param {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. | ||
*/ | ||
Glyph.prototype.drawPoints = function(ctx, x, y, fontSize) { | ||
@@ -265,11 +299,12 @@ | ||
// Draw lines indicating important font measurements. | ||
// Black lines indicate the origin of the coordinate system (point 0,0). | ||
// Blue lines indicate the glyph bounding box. | ||
// Green line indicates the advance width of the glyph. | ||
// | ||
// ctx - The drawing context. | ||
// x - Horizontal position of the glyph. (default: 0) | ||
// y - Vertical position of the *baseline* of the glyph. (default: 0) | ||
// fontSize - Font size, in pixels (default: 72). | ||
/** | ||
* Draw lines indicating important font measurements. | ||
* Black lines indicate the origin of the coordinate system (point 0,0). | ||
* Blue lines indicate the glyph bounding box. | ||
* Green line indicates the advance width of the glyph. | ||
* @param {CanvasRenderingContext2D} ctx - A 2D drawing context, like Canvas. | ||
* @param {number} [x=0] - Horizontal position of the beginning of the text. | ||
* @param {number} [y=0] - Vertical position of the *baseline* of the text. | ||
* @param {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. | ||
*/ | ||
Glyph.prototype.drawMetrics = function(ctx, x, y, fontSize) { | ||
@@ -276,0 +311,0 @@ var scale; |
@@ -7,5 +7,27 @@ // The GlyphSet object | ||
// A GlyphSet represents all glyphs available in the font, but modelled using | ||
// a deferred glyph loader, for retrieving glyphs only once they are absolutely | ||
// necessary, to keep the memory footprint down. | ||
// Define a property on the glyph that depends on the path being loaded. | ||
function defineDependentProperty(glyph, externalName, internalName) { | ||
Object.defineProperty(glyph, externalName, { | ||
get: function() { | ||
// Request the path property to make sure the path is loaded. | ||
glyph.path; // jshint ignore:line | ||
return glyph[internalName]; | ||
}, | ||
set: function(newValue) { | ||
glyph[internalName] = newValue; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
} | ||
/** | ||
* A GlyphSet represents all glyphs available in the font, but modelled using | ||
* a deferred glyph loader, for retrieving glyphs only once they are absolutely | ||
* necessary, to keep the memory footprint down. | ||
* @exports opentype.GlyphSet | ||
* @class | ||
* @param {opentype.Font} | ||
* @param {Array} | ||
*/ | ||
function GlyphSet(font, glyphs) { | ||
@@ -23,2 +45,6 @@ this.font = font; | ||
/** | ||
* @param {number} index | ||
* @return {opentype.Glyph} | ||
*/ | ||
GlyphSet.prototype.get = function(index) { | ||
@@ -32,2 +58,6 @@ if (typeof this.glyphs[index] === 'function') { | ||
/** | ||
* @param {number} index | ||
* @param {Object} | ||
*/ | ||
GlyphSet.prototype.push = function(index, loader) { | ||
@@ -38,2 +68,8 @@ this.glyphs[index] = loader; | ||
/** | ||
* @alias opentype.glyphLoader | ||
* @param {opentype.Font} font | ||
* @param {number} index | ||
* @return {opentype.Glyph} | ||
*/ | ||
function glyphLoader(font, index) { | ||
@@ -47,4 +83,11 @@ return new _glyph.Glyph({index: index, font: font}); | ||
* the glyph's path is actually requested for text shaping. | ||
* @alias opentype.ttfGlyphLoader | ||
* @param {opentype.Font} font | ||
* @param {number} index | ||
* @param {Function} parseGlyph | ||
* @param {Object} data | ||
* @param {number} position | ||
* @param {Function} buildPath | ||
* @return {opentype.Glyph} | ||
*/ | ||
function ttfGlyphLoader(font, index, parseGlyph, data, position, buildPath) { | ||
@@ -61,6 +104,18 @@ return function() { | ||
defineDependentProperty(glyph, 'xMin', '_xMin'); | ||
defineDependentProperty(glyph, 'xMax', '_xMax'); | ||
defineDependentProperty(glyph, 'yMin', '_yMin'); | ||
defineDependentProperty(glyph, 'yMax', '_yMax'); | ||
return glyph; | ||
}; | ||
} | ||
/** | ||
* @alias opentype.cffGlyphLoader | ||
* @param {opentype.Font} font | ||
* @param {number} index | ||
* @param {Function} parseCFFCharstring | ||
* @param {string} charstring | ||
* @return {opentype.Glyph} | ||
*/ | ||
function cffGlyphLoader(font, index, parseCFFCharstring, charstring) { | ||
@@ -67,0 +122,0 @@ return function() { |
@@ -24,2 +24,3 @@ // opentype.js | ||
var gpos = require('./tables/gpos'); | ||
var gsub = require('./tables/gsub'); | ||
var head = require('./tables/head'); | ||
@@ -35,5 +36,16 @@ var hhea = require('./tables/hhea'); | ||
var post = require('./tables/post'); | ||
var meta = require('./tables/meta'); | ||
/** | ||
* The opentype library. | ||
* @namespace opentype | ||
*/ | ||
// File loaders ///////////////////////////////////////////////////////// | ||
/** | ||
* Loads a font from a file. The callback throws an error message as the first parameter if it fails | ||
* and the font as an ArrayBuffer in the second parameter if it succeeds. | ||
* @param {string} path - The path of the file | ||
* @param {Function} callback - The function to call when the font load completes | ||
*/ | ||
function loadFromFile(path, callback) { | ||
@@ -49,3 +61,8 @@ var fs = require('fs'); | ||
} | ||
/** | ||
* Loads a font from a URL. The callback throws an error message as the first parameter if it fails | ||
* and the font as an ArrayBuffer in the second parameter if it succeeds. | ||
* @param {string} url - The URL of the font file. | ||
* @param {Function} callback - The function to call when the font load completes | ||
*/ | ||
function loadFromUrl(url, callback) { | ||
@@ -67,3 +84,8 @@ var request = new XMLHttpRequest(); | ||
// Table Directory Entries ////////////////////////////////////////////// | ||
/** | ||
* Parses OpenType table entries. | ||
* @param {DataView} | ||
* @param {Number} | ||
* @return {Object[]} | ||
*/ | ||
function parseOpenTypeTableEntries(data, numTables) { | ||
@@ -84,2 +106,8 @@ var tableEntries = []; | ||
/** | ||
* Parses WOFF table entries. | ||
* @param {DataView} | ||
* @param {Number} | ||
* @return {Object[]} | ||
*/ | ||
function parseWOFFTableEntries(data, numTables) { | ||
@@ -108,2 +136,14 @@ var tableEntries = []; | ||
/** | ||
* @typedef TableData | ||
* @type Object | ||
* @property {DataView} data - The DataView | ||
* @property {number} offset - The data offset. | ||
*/ | ||
/** | ||
* @param {DataView} | ||
* @param {Object} | ||
* @return {TableData} | ||
*/ | ||
function uncompressTable(data, tableEntry) { | ||
@@ -127,4 +167,8 @@ if (tableEntry.compression === 'WOFF') { | ||
// Parse the OpenType file data (as an ArrayBuffer) and return a Font object. | ||
// Throws an error if the font could not be parsed. | ||
/** | ||
* Parse the OpenType file data (as an ArrayBuffer) and return a Font object. | ||
* Throws an error if the font could not be parsed. | ||
* @param {ArrayBuffer} | ||
* @return {opentype.Font} | ||
*/ | ||
function parseBuffer(buffer) { | ||
@@ -173,2 +217,3 @@ var indexToLocFormat; | ||
var gposTableEntry; | ||
var gsubTableEntry; | ||
var hmtxTableEntry; | ||
@@ -178,2 +223,3 @@ var kernTableEntry; | ||
var nameTableEntry; | ||
var metaTableEntry; | ||
@@ -244,2 +290,8 @@ for (var i = 0; i < numTables; i += 1) { | ||
break; | ||
case 'GSUB': | ||
gsubTableEntry = tableEntry; | ||
break; | ||
case 'meta': | ||
metaTableEntry = tableEntry; | ||
break; | ||
} | ||
@@ -281,2 +333,7 @@ } | ||
if (gsubTableEntry) { | ||
var gsubTable = uncompressTable(data, gsubTableEntry); | ||
font.tables.gsub = gsub.parse(gsubTable.data, gsubTable.offset); | ||
} | ||
if (fvarTableEntry) { | ||
@@ -287,11 +344,21 @@ var fvarTable = uncompressTable(data, fvarTableEntry); | ||
if (metaTableEntry) { | ||
var metaTable = uncompressTable(data, metaTableEntry); | ||
font.tables.meta = meta.parse(metaTable.data, metaTable.offset); | ||
font.metas = font.tables.meta; | ||
} | ||
return font; | ||
} | ||
// Asynchronously load the font from a URL or a filesystem. When done, call the callback | ||
// with two arguments `(err, font)`. The `err` will be null on success, | ||
// the `font` is a Font object. | ||
// | ||
// We use the node.js callback convention so that | ||
// opentype.js can integrate with frameworks like async.js. | ||
/** | ||
* Asynchronously load the font from a URL or a filesystem. When done, call the callback | ||
* with two arguments `(err, font)`. The `err` will be null on success, | ||
* the `font` is a Font object. | ||
* We use the node.js callback convention so that | ||
* opentype.js can integrate with frameworks like async.js. | ||
* @alias opentype.load | ||
* @param {string} url - The URL of the font to load. | ||
* @param {Function} callback - The callback. | ||
*/ | ||
function load(url, callback) { | ||
@@ -314,4 +381,9 @@ var isNode = typeof window === 'undefined'; | ||
// Synchronously load the font from a URL or file. | ||
// When done, return the font object or throw an error. | ||
/** | ||
* Synchronously load the font from a URL or file. | ||
* When done, returns the font object or throws an error. | ||
* @alias opentype.loadSync | ||
* @param {string} url - The URL of the font to load. | ||
* @return {opentype.Font} | ||
*/ | ||
function loadSync(url) { | ||
@@ -318,0 +390,0 @@ var fs = require('fs'); |
285
src/parse.js
@@ -5,2 +5,4 @@ // Parsing utility functions | ||
var check = require('./check'); | ||
// Retrieve an unsigned byte from the DataView. | ||
@@ -15,7 +17,7 @@ exports.getByte = function getByte(dataView, offset) { | ||
// The value is stored in big endian. | ||
exports.getUShort = function(dataView, offset) { | ||
function getUShort(dataView, offset) { | ||
return dataView.getUint16(offset, false); | ||
}; | ||
} | ||
exports.getCard16 = exports.getUShort; | ||
exports.getUShort = exports.getCard16 = getUShort; | ||
@@ -151,16 +153,2 @@ // Retrieve a signed 16-bit short from the DataView. | ||
Parser.prototype.parseOffset16List = | ||
Parser.prototype.parseUShortList = function(count) { | ||
var offsets = new Array(count); | ||
var dataView = this.data; | ||
var offset = this.offset + this.relativeOffset; | ||
for (var i = 0; i < count; i++) { | ||
offsets[i] = exports.getUShort(dataView, offset); | ||
offset += 2; | ||
} | ||
this.relativeOffset += count * 2; | ||
return offsets; | ||
}; | ||
Parser.prototype.parseString = function(length) { | ||
@@ -188,3 +176,3 @@ var dataView = this.data; | ||
var v = exports.getULong(this.data, this.offset + this.relativeOffset + 4); | ||
// Substract seconds between 01/01/1904 and 01/01/1970 | ||
// Subtract seconds between 01/01/1904 and 01/01/1970 | ||
// to convert Apple Mac timstamp to Standard Unix timestamp | ||
@@ -196,14 +184,8 @@ v -= 2082844800; | ||
Parser.prototype.parseFixed = function() { | ||
var v = exports.getULong(this.data, this.offset + this.relativeOffset); | ||
this.relativeOffset += 4; | ||
return v / 65536; | ||
}; | ||
Parser.prototype.parseVersion = function() { | ||
var major = exports.getUShort(this.data, this.offset + this.relativeOffset); | ||
var major = getUShort(this.data, this.offset + this.relativeOffset); | ||
// How to interpret the minor version is very vague in the spec. 0x5000 is 5, 0x1000 is 1 | ||
// This returns the correct number if minor = 0xN000 where N is 0-9 | ||
var minor = exports.getUShort(this.data, this.offset + this.relativeOffset + 2); | ||
var minor = getUShort(this.data, this.offset + this.relativeOffset + 2); | ||
this.relativeOffset += 4; | ||
@@ -221,2 +203,253 @@ return major + minor / 0x1000 / 10; | ||
///// Parsing lists and records /////////////////////////////// | ||
// Parse a list of 16 bit integers. The length of the list can be read on the stream | ||
// or provided as an argument. | ||
Parser.prototype.parseOffset16List = | ||
Parser.prototype.parseUShortList = function(count) { | ||
if (count === undefined) { count = this.parseUShort(); } | ||
var offsets = new Array(count); | ||
var dataView = this.data; | ||
var offset = this.offset + this.relativeOffset; | ||
for (var i = 0; i < count; i++) { | ||
offsets[i] = dataView.getUint16(offset); | ||
offset += 2; | ||
} | ||
this.relativeOffset += count * 2; | ||
return offsets; | ||
}; | ||
/** | ||
* Parse a list of items. | ||
* Record count is optional, if omitted it is read from the stream. | ||
* itemCallback is one of the Parser methods. | ||
*/ | ||
Parser.prototype.parseList = function(count, itemCallback) { | ||
if (!itemCallback) { | ||
itemCallback = count; | ||
count = this.parseUShort(); | ||
} | ||
var list = new Array(count); | ||
for (var i = 0; i < count; i++) { | ||
list[i] = itemCallback.call(this); | ||
} | ||
return list; | ||
}; | ||
/** | ||
* Parse a list of records. | ||
* Record count is optional, if omitted it is read from the stream. | ||
* Example of recordDescription: { sequenceIndex: Parser.uShort, lookupListIndex: Parser.uShort } | ||
*/ | ||
Parser.prototype.parseRecordList = function(count, recordDescription) { | ||
// If the count argument is absent, read it in the stream. | ||
if (!recordDescription) { | ||
recordDescription = count; | ||
count = this.parseUShort(); | ||
} | ||
var records = new Array(count); | ||
var fields = Object.keys(recordDescription); | ||
for (var i = 0; i < count; i++) { | ||
var rec = {}; | ||
for (var j = 0; j < fields.length; j++) { | ||
var fieldName = fields[j]; | ||
var fieldType = recordDescription[fieldName]; | ||
rec[fieldName] = fieldType.call(this); | ||
} | ||
records[i] = rec; | ||
} | ||
return records; | ||
}; | ||
// Parse a data structure into an object | ||
// Example of description: { sequenceIndex: Parser.uShort, lookupListIndex: Parser.uShort } | ||
Parser.prototype.parseStruct = function(description) { | ||
if (typeof description === 'function') { | ||
return description.call(this); | ||
} else { | ||
var fields = Object.keys(description); | ||
var struct = {}; | ||
for (var j = 0; j < fields.length; j++) { | ||
var fieldName = fields[j]; | ||
var fieldType = description[fieldName]; | ||
struct[fieldName] = fieldType.call(this); | ||
} | ||
return struct; | ||
} | ||
}; | ||
Parser.prototype.parsePointer = function(description) { | ||
var structOffset = this.parseOffset16(); | ||
if (structOffset > 0) { // NULL offset => return indefined | ||
return new Parser(this.data, this.offset + structOffset).parseStruct(description); | ||
} | ||
}; | ||
/** | ||
* Parse a list of offsets to lists of 16-bit integers, | ||
* or a list of offsets to lists of offsets to any kind of items. | ||
* If itemCallback is not provided, a list of list of UShort is assumed. | ||
* If provided, itemCallback is called on each item and must parse the item. | ||
* See examples in tables/gsub.js | ||
*/ | ||
Parser.prototype.parseListOfLists = function(itemCallback) { | ||
var offsets = this.parseOffset16List(); | ||
var count = offsets.length; | ||
var relativeOffset = this.relativeOffset; | ||
var list = new Array(count); | ||
for (var i = 0; i < count; i++) { | ||
var start = offsets[i]; | ||
if (start === 0) { // NULL offset | ||
list[i] = undefined; // Add i as owned property to list. Convenient with assert. | ||
continue; | ||
} | ||
this.relativeOffset = start; | ||
if (itemCallback) { | ||
var subOffsets = this.parseOffset16List(); | ||
var subList = new Array(subOffsets.length); | ||
for (var j = 0; j < subOffsets.length; j++) { | ||
this.relativeOffset = start + subOffsets[j]; | ||
subList[j] = itemCallback.call(this); | ||
} | ||
list[i] = subList; | ||
} else { | ||
list[i] = this.parseUShortList(); | ||
} | ||
} | ||
this.relativeOffset = relativeOffset; | ||
return list; | ||
}; | ||
///// Complex tables parsing ////////////////////////////////// | ||
// Parse a coverage table in a GSUB, GPOS or GDEF table. | ||
// https://www.microsoft.com/typography/OTSPEC/chapter2.htm | ||
// parser.offset must point to the start of the table containing the coverage. | ||
Parser.prototype.parseCoverage = function() { | ||
var startOffset = this.offset + this.relativeOffset; | ||
var format = this.parseUShort(); | ||
var count = this.parseUShort(); | ||
if (format === 1) { | ||
return { | ||
format: 1, | ||
glyphs: this.parseUShortList(count) | ||
}; | ||
} else if (format === 2) { | ||
var ranges = new Array(count); | ||
for (var i = 0; i < count; i++) { | ||
ranges[i] = { | ||
start: this.parseUShort(), | ||
end: this.parseUShort(), | ||
index: this.parseUShort() | ||
}; | ||
} | ||
return { | ||
format: 2, | ||
ranges: ranges | ||
}; | ||
} | ||
check.assert(false, '0x' + startOffset.toString(16) + ': Coverage format must be 1 or 2.'); | ||
}; | ||
// Parse a Class Definition Table in a GSUB, GPOS or GDEF table. | ||
// https://www.microsoft.com/typography/OTSPEC/chapter2.htm | ||
Parser.prototype.parseClassDef = function() { | ||
var startOffset = this.offset + this.relativeOffset; | ||
var format = this.parseUShort(); | ||
if (format === 1) { | ||
return { | ||
format: 1, | ||
startGlyph: this.parseUShort(), | ||
classes: this.parseUShortList() | ||
}; | ||
} else if (format === 2) { | ||
return { | ||
format: 2, | ||
ranges: this.parseRecordList({ | ||
start: Parser.uShort, | ||
end: Parser.uShort, | ||
classId: Parser.uShort | ||
}) | ||
}; | ||
} | ||
check.assert(false, '0x' + startOffset.toString(16) + ': ClassDef format must be 1 or 2.'); | ||
}; | ||
///// Static methods /////////////////////////////////// | ||
// These convenience methods can be used as callbacks and should be called with "this" context set to a Parser instance. | ||
Parser.list = function(count, itemCallback) { | ||
return function() { | ||
return this.parseList(count, itemCallback); | ||
}; | ||
}; | ||
Parser.recordList = function(count, recordDescription) { | ||
return function() { | ||
return this.parseRecordList(count, recordDescription); | ||
}; | ||
}; | ||
Parser.pointer = function(description) { | ||
return function() { | ||
return this.parsePointer(description); | ||
}; | ||
}; | ||
Parser.tag = Parser.prototype.parseTag; | ||
Parser.byte = Parser.prototype.parseByte; | ||
Parser.uShort = Parser.offset16 = Parser.prototype.parseUShort; | ||
Parser.uShortList = Parser.prototype.parseUShortList; | ||
Parser.struct = Parser.prototype.parseStruct; | ||
Parser.coverage = Parser.prototype.parseCoverage; | ||
Parser.classDef = Parser.prototype.parseClassDef; | ||
///// Script, Feature, Lookup lists /////////////////////////////////////////////// | ||
// https://www.microsoft.com/typography/OTSPEC/chapter2.htm | ||
var langSysTable = { | ||
reserved: Parser.uShort, | ||
reqFeatureIndex: Parser.uShort, | ||
featureIndexes: Parser.uShortList | ||
}; | ||
Parser.prototype.parseScriptList = function() { | ||
return this.parsePointer(Parser.recordList({ | ||
tag: Parser.tag, | ||
script: Parser.pointer({ | ||
defaultLangSys: Parser.pointer(langSysTable), | ||
langSysRecords: Parser.recordList({ | ||
tag: Parser.tag, | ||
langSys: Parser.pointer(langSysTable) | ||
}) | ||
}) | ||
})); | ||
}; | ||
Parser.prototype.parseFeatureList = function() { | ||
return this.parsePointer(Parser.recordList({ | ||
tag: Parser.tag, | ||
feature: Parser.pointer({ | ||
featureParams: Parser.offset16, | ||
lookupListIndexes: Parser.uShortList | ||
}) | ||
})); | ||
}; | ||
Parser.prototype.parseLookupList = function(lookupTableParsers) { | ||
return this.parsePointer(Parser.list(Parser.pointer(function() { | ||
var lookupType = this.parseUShort(); | ||
check.argument(1 <= lookupType && lookupType <= 8, 'GSUB lookup type ' + lookupType + ' unknown.'); | ||
var lookupFlag = this.parseUShort(); | ||
var useMarkFilteringSet = lookupFlag & 0x10; | ||
return { | ||
lookupType: lookupType, | ||
lookupFlag: lookupFlag, | ||
subtables: this.parseList(Parser.pointer(lookupTableParsers[lookupType])), | ||
markFilteringSet: useMarkFilteringSet ? this.parseUShort() : undefined | ||
}; | ||
}))); | ||
}; | ||
exports.Parser = Parser; |
105
src/path.js
@@ -5,4 +5,9 @@ // Geometric objects | ||
// A bézier path containing a set of path commands similar to a SVG path. | ||
// Paths can be drawn on a context using `draw`. | ||
/** | ||
* A bézier path containing a set of path commands similar to a SVG path. | ||
* Paths can be drawn on a context using `draw`. | ||
* @exports opentype.Path | ||
* @class | ||
* @constructor | ||
*/ | ||
function Path() { | ||
@@ -15,2 +20,6 @@ this.commands = []; | ||
/** | ||
* @param {number} x | ||
* @param {number} y | ||
*/ | ||
Path.prototype.moveTo = function(x, y) { | ||
@@ -24,2 +33,6 @@ this.commands.push({ | ||
/** | ||
* @param {number} x | ||
* @param {number} y | ||
*/ | ||
Path.prototype.lineTo = function(x, y) { | ||
@@ -33,2 +46,28 @@ this.commands.push({ | ||
/** | ||
* Draws cubic curve | ||
* @function | ||
* curveTo | ||
* @memberof opentype.Path.prototype | ||
* @param {number} x1 - x of control 1 | ||
* @param {number} y1 - y of control 1 | ||
* @param {number} x2 - x of control 2 | ||
* @param {number} y2 - y of control 2 | ||
* @param {number} x - x of path point | ||
* @param {number} y - y of path point | ||
*/ | ||
/** | ||
* Draws cubic curve | ||
* @function | ||
* bezierCurveTo | ||
* @memberof opentype.Path.prototype | ||
* @param {number} x1 - x of control 1 | ||
* @param {number} y1 - y of control 1 | ||
* @param {number} x2 - x of control 2 | ||
* @param {number} y2 - y of control 2 | ||
* @param {number} x - x of path point | ||
* @param {number} y - y of path point | ||
* @see curveTo | ||
*/ | ||
Path.prototype.curveTo = Path.prototype.bezierCurveTo = function(x1, y1, x2, y2, x, y) { | ||
@@ -46,2 +85,23 @@ this.commands.push({ | ||
/** | ||
* Draws quadratic curve | ||
* @function | ||
* quadraticCurveTo | ||
* @memberof opentype.Path.prototype | ||
* @param {number} x1 - x of control | ||
* @param {number} y1 - y of control | ||
* @param {number} x - x of path point | ||
* @param {number} y - y of path point | ||
*/ | ||
/** | ||
* Draws quadratic curve | ||
* @function | ||
* quadTo | ||
* @memberof opentype.Path.prototype | ||
* @param {number} x1 - x of control | ||
* @param {number} y1 - y of control | ||
* @param {number} x - x of path point | ||
* @param {number} y - y of path point | ||
*/ | ||
Path.prototype.quadTo = Path.prototype.quadraticCurveTo = function(x1, y1, x, y) { | ||
@@ -57,2 +117,13 @@ this.commands.push({ | ||
/** | ||
* Closes the path | ||
* @function closePath | ||
* @memberof opentype.Path.prototype | ||
*/ | ||
/** | ||
* Close the path | ||
* @function close | ||
* @memberof opentype.Path.prototype | ||
*/ | ||
Path.prototype.close = Path.prototype.closePath = function() { | ||
@@ -64,3 +135,6 @@ this.commands.push({ | ||
// Add the given path or list of commands to the commands of this path. | ||
/** | ||
* Add the given path or list of commands to the commands of this path. | ||
* @param {Array} | ||
*/ | ||
Path.prototype.extend = function(pathOrCommands) { | ||
@@ -74,3 +148,6 @@ if (pathOrCommands.commands) { | ||
// Draw the path to a 2D context. | ||
/** | ||
* Draw the path to a 2D context. | ||
* @param {CanvasRenderingContext2D} ctx - A 2D drawing context. | ||
*/ | ||
Path.prototype.draw = function(ctx) { | ||
@@ -105,6 +182,8 @@ ctx.beginPath(); | ||
// Convert the Path to a string of path data instructions | ||
// See http://www.w3.org/TR/SVG/paths.html#PathData | ||
// Parameters: | ||
// - decimalPlaces: The amount of decimal places for floating-point values (default: 2) | ||
/** | ||
* Convert the Path to a string of path data instructions | ||
* See http://www.w3.org/TR/SVG/paths.html#PathData | ||
* @param {number} [decimalPlaces=2] - The amount of decimal places for floating-point values | ||
* @return {string} | ||
*/ | ||
Path.prototype.toPathData = function(decimalPlaces) { | ||
@@ -154,5 +233,7 @@ decimalPlaces = decimalPlaces !== undefined ? decimalPlaces : 2; | ||
// Convert the path to a SVG <path> element, as a string. | ||
// Parameters: | ||
// - decimalPlaces: The amount of decimal places for floating-point values (default: 2) | ||
/** | ||
* Convert the path to an SVG <path> element, as a string. | ||
* @param {number} [decimalPlaces=2] - The amount of decimal places for floating-point values | ||
* @return {string} | ||
*/ | ||
Path.prototype.toSVG = function(decimalPlaces) { | ||
@@ -162,3 +243,3 @@ var svg = '<path d="'; | ||
svg += '"'; | ||
if (this.fill & this.fill !== 'black') { | ||
if (this.fill && this.fill !== 'black') { | ||
if (this.fill === null) { | ||
@@ -165,0 +246,0 @@ svg += ' fill="none"'; |
165
src/table.js
@@ -5,5 +5,13 @@ // Table metadata | ||
var check = require('./check'); | ||
var encode = require('./types').encode; | ||
var sizeOf = require('./types').sizeOf; | ||
/** | ||
* @exports opentype.Table | ||
* @class | ||
* @param {string} tableName | ||
* @param {Array} fields | ||
* @param {Object} options | ||
* @constructor | ||
*/ | ||
function Table(tableName, fields, options) { | ||
@@ -30,2 +38,6 @@ var i; | ||
/** | ||
* Encodes the table and returns an array of bytes | ||
* @return {Array} | ||
*/ | ||
Table.prototype.encode = function() { | ||
@@ -35,2 +47,6 @@ return encode.TABLE(this); | ||
/** | ||
* Get the size of the table. | ||
* @return {number} | ||
*/ | ||
Table.prototype.sizeOf = function() { | ||
@@ -40,2 +56,149 @@ return sizeOf.TABLE(this); | ||
/** | ||
* @private | ||
*/ | ||
function ushortList(itemName, list, count) { | ||
if (count === undefined) { | ||
count = list.length; | ||
} | ||
var fields = new Array(list.length + 1); | ||
fields[0] = {name: itemName + 'Count', type: 'USHORT', value: count}; | ||
for (var i = 0; i < list.length; i++) { | ||
fields[i + 1] = {name: itemName + i, type: 'USHORT', value: list[i]}; | ||
} | ||
return fields; | ||
} | ||
/** | ||
* @private | ||
*/ | ||
function tableList(itemName, records, itemCallback) { | ||
var count = records.length; | ||
var fields = new Array(count + 1); | ||
fields[0] = {name: itemName + 'Count', type: 'USHORT', value: count}; | ||
for (var i = 0; i < count; i++) { | ||
fields[i + 1] = {name: itemName + i, type: 'TABLE', value: itemCallback(records[i], i)}; | ||
} | ||
return fields; | ||
} | ||
/** | ||
* @private | ||
*/ | ||
function recordList(itemName, records, itemCallback) { | ||
var count = records.length; | ||
var fields = []; | ||
fields[0] = {name: itemName + 'Count', type: 'USHORT', value: count}; | ||
for (var i = 0; i < count; i++) { | ||
fields = fields.concat(itemCallback(records[i], i)); | ||
} | ||
return fields; | ||
} | ||
// Common Layout Tables | ||
/** | ||
* @exports opentype.Coverage | ||
* @class | ||
* @param {opentype.Table} | ||
* @constructor | ||
* @extends opentype.Table | ||
*/ | ||
function Coverage(coverageTable) { | ||
if (coverageTable.format === 1) { | ||
Table.call(this, 'coverageTable', | ||
[{name: 'coverageFormat', type: 'USHORT', value: 1}] | ||
.concat(ushortList('glyph', coverageTable.glyphs)) | ||
); | ||
} else { | ||
check.assert(false, 'Can\'t create coverage table format 2 yet.'); | ||
} | ||
} | ||
Coverage.prototype = Object.create(Table.prototype); | ||
Coverage.prototype.constructor = Coverage; | ||
function ScriptList(scriptListTable) { | ||
Table.call(this, 'scriptListTable', | ||
recordList('scriptRecord', scriptListTable, function(scriptRecord, i) { | ||
var script = scriptRecord.script; | ||
var defaultLangSys = script.defaultLangSys; | ||
check.assert(!!defaultLangSys, 'Unable to write GSUB: script ' + scriptRecord.tag + ' has no default language system.'); | ||
return [ | ||
{name: 'scriptTag' + i, type: 'TAG', value: scriptRecord.tag}, | ||
{name: 'script' + i, type: 'TABLE', value: new Table('scriptTable', [ | ||
{name: 'defaultLangSys', type: 'TABLE', value: new Table('defaultLangSys', [ | ||
{name: 'lookupOrder', type: 'USHORT', value: 0}, | ||
{name: 'reqFeatureIndex', type: 'USHORT', value: defaultLangSys.reqFeatureIndex}] | ||
.concat(ushortList('featureIndex', defaultLangSys.featureIndexes)))} | ||
].concat(recordList('langSys', script.langSysRecords, function(langSysRecord, i) { | ||
var langSys = langSysRecord.langSys; | ||
return [ | ||
{name: 'langSysTag' + i, type: 'TAG', value: langSysRecord.tag}, | ||
{name: 'langSys' + i, type: 'TABLE', value: new Table('langSys', [ | ||
{name: 'lookupOrder', type: 'USHORT', value: 0}, | ||
{name: 'reqFeatureIndex', type: 'USHORT', value: langSys.reqFeatureIndex} | ||
].concat(ushortList('featureIndex', langSys.featureIndexes)))} | ||
]; | ||
})))} | ||
]; | ||
}) | ||
); | ||
} | ||
ScriptList.prototype = Object.create(Table.prototype); | ||
ScriptList.prototype.constructor = ScriptList; | ||
/** | ||
* @exports opentype.FeatureList | ||
* @class | ||
* @param {opentype.Table} | ||
* @constructor | ||
* @extends opentype.Table | ||
*/ | ||
function FeatureList(featureListTable) { | ||
Table.call(this, 'featureListTable', | ||
recordList('featureRecord', featureListTable, function(featureRecord, i) { | ||
var feature = featureRecord.feature; | ||
return [ | ||
{name: 'featureTag' + i, type: 'TAG', value: featureRecord.tag}, | ||
{name: 'feature' + i, type: 'TABLE', value: new Table('featureTable', [ | ||
{name: 'featureParams', type: 'USHORT', value: feature.featureParams}, | ||
].concat(ushortList('lookupListIndex', feature.lookupListIndexes)))} | ||
]; | ||
}) | ||
); | ||
} | ||
FeatureList.prototype = Object.create(Table.prototype); | ||
FeatureList.prototype.constructor = FeatureList; | ||
/** | ||
* @exports opentype.LookupList | ||
* @class | ||
* @param {opentype.Table} | ||
* @param {Object} | ||
* @constructor | ||
* @extends opentype.Table | ||
*/ | ||
function LookupList(lookupListTable, subtableMakers) { | ||
Table.call(this, 'lookupListTable', tableList('lookup', lookupListTable, function(lookupTable) { | ||
var subtableCallback = subtableMakers[lookupTable.lookupType]; | ||
check.assert(!!subtableCallback, 'Unable to write GSUB lookup type ' + lookupTable.lookupType + ' tables.'); | ||
return new Table('lookupTable', [ | ||
{name: 'lookupType', type: 'USHORT', value: lookupTable.lookupType}, | ||
{name: 'lookupFlag', type: 'USHORT', value: lookupTable.lookupFlag} | ||
].concat(tableList('subtable', lookupTable.subtables, subtableCallback))); | ||
})); | ||
} | ||
LookupList.prototype = Object.create(Table.prototype); | ||
LookupList.prototype.constructor = LookupList; | ||
// Record = same as Table, but inlined (a Table has an offset and its data is further in the stream) | ||
// Don't use offsets inside Records (probable bug), only in Tables. | ||
exports.Record = exports.Table = Table; | ||
exports.Coverage = Coverage; | ||
exports.ScriptList = ScriptList; | ||
exports.FeatureList = FeatureList; | ||
exports.LookupList = LookupList; | ||
exports.ushortList = ushortList; | ||
exports.tableList = tableList; | ||
exports.recordList = recordList; |
@@ -10,34 +10,31 @@ // The `cmap` table stores the mappings from characters to glyphs. | ||
// Parse the `cmap` table. This table stores the mappings from characters to glyphs. | ||
// There are many available formats, but we only support the Windows format 4. | ||
// This function returns a `CmapEncoding` object or null if no supported format could be found. | ||
function parseCmapTable(data, start) { | ||
function parseCmapTableFormat12(cmap, p) { | ||
var i; | ||
var cmap = {}; | ||
cmap.version = parse.getUShort(data, start); | ||
check.argument(cmap.version === 0, 'cmap table version should be 0.'); | ||
// The cmap table can contain many sub-tables, each with their own format. | ||
// We're only interested in a "platform 3" table. This is a Windows format. | ||
cmap.numTables = parse.getUShort(data, start + 2); | ||
var offset = -1; | ||
for (i = 0; i < cmap.numTables; i += 1) { | ||
var platformId = parse.getUShort(data, start + 4 + (i * 8)); | ||
var encodingId = parse.getUShort(data, start + 4 + (i * 8) + 2); | ||
if (platformId === 3 && (encodingId === 1 || encodingId === 0)) { | ||
offset = parse.getULong(data, start + 4 + (i * 8) + 4); | ||
break; | ||
//Skip reserved. | ||
p.parseUShort(); | ||
// Length in bytes of the sub-tables. | ||
cmap.length = p.parseULong(); | ||
cmap.language = p.parseULong(); | ||
var groupCount; | ||
cmap.groupCount = groupCount = p.parseULong(); | ||
cmap.glyphIndexMap = {}; | ||
for (i = 0; i < groupCount; i += 1) { | ||
var startCharCode = p.parseULong(); | ||
var endCharCode = p.parseULong(); | ||
var startGlyphId = p.parseULong(); | ||
for (var c = startCharCode; c <= endCharCode; c += 1) { | ||
cmap.glyphIndexMap[c] = startGlyphId; | ||
startGlyphId++; | ||
} | ||
} | ||
} | ||
if (offset === -1) { | ||
// There is no cmap table in the font that we support, so return null. | ||
// This font will be marked as unsupported. | ||
return null; | ||
} | ||
function parseCmapTableFormat4(cmap, p, data, start, offset) { | ||
var i; | ||
var p = new parse.Parser(data, start + offset); | ||
cmap.format = p.parseUShort(); | ||
check.argument(cmap.format === 4, 'Only format 4 cmap tables are supported.'); | ||
// Length in bytes of the sub-tables. | ||
@@ -56,3 +53,2 @@ cmap.length = p.parseUShort(); | ||
cmap.glyphIndexMap = {}; | ||
var endCountParser = new parse.Parser(data, start + offset + 14); | ||
@@ -91,3 +87,43 @@ var startCountParser = new parse.Parser(data, start + offset + 16 + segCount * 2); | ||
} | ||
} | ||
// Parse the `cmap` table. This table stores the mappings from characters to glyphs. | ||
// There are many available formats, but we only support the Windows format 4 and 12. | ||
// This function returns a `CmapEncoding` object or null if no supported format could be found. | ||
function parseCmapTable(data, start) { | ||
var i; | ||
var cmap = {}; | ||
cmap.version = parse.getUShort(data, start); | ||
check.argument(cmap.version === 0, 'cmap table version should be 0.'); | ||
// The cmap table can contain many sub-tables, each with their own format. | ||
// We're only interested in a "platform 3" table. This is a Windows format. | ||
cmap.numTables = parse.getUShort(data, start + 2); | ||
var offset = -1; | ||
for (i = cmap.numTables - 1; i >= 0; i -= 1) { | ||
var platformId = parse.getUShort(data, start + 4 + (i * 8)); | ||
var encodingId = parse.getUShort(data, start + 4 + (i * 8) + 2); | ||
if (platformId === 3 && (encodingId === 0 || encodingId === 1 || encodingId === 10)) { | ||
offset = parse.getULong(data, start + 4 + (i * 8) + 4); | ||
break; | ||
} | ||
} | ||
if (offset === -1) { | ||
// There is no cmap table in the font that we support, so return null. | ||
// This font will be marked as unsupported. | ||
return null; | ||
} | ||
var p = new parse.Parser(data, start + offset); | ||
cmap.format = p.parseUShort(); | ||
if (cmap.format === 12) { | ||
parseCmapTableFormat12(cmap, p); | ||
} else if (cmap.format === 4) { | ||
parseCmapTableFormat4(cmap, p, data, start, offset); | ||
} else { | ||
throw new Error('Only format 4 and 12 cmap tables are supported.'); | ||
} | ||
return cmap; | ||
@@ -94,0 +130,0 @@ } |
@@ -41,6 +41,6 @@ // The `glyf` table describes the glyphs in TrueType outline format. | ||
glyph.numberOfContours = p.parseShort(); | ||
glyph.xMin = p.parseShort(); | ||
glyph.yMin = p.parseShort(); | ||
glyph.xMax = p.parseShort(); | ||
glyph.yMax = p.parseShort(); | ||
glyph._xMin = p.parseShort(); | ||
glyph._yMin = p.parseShort(); | ||
glyph._xMax = p.parseShort(); | ||
glyph._yMax = p.parseShort(); | ||
var flags; | ||
@@ -133,8 +133,21 @@ var flag; | ||
// The arguments are words | ||
component.dx = p.parseShort(); | ||
component.dy = p.parseShort(); | ||
if ((flags & 2) > 0) { | ||
// values are offset | ||
component.dx = p.parseShort(); | ||
component.dy = p.parseShort(); | ||
} else { | ||
// values are matched points | ||
component.matchedPoints = [p.parseUShort(), p.parseUShort()]; | ||
} | ||
} else { | ||
// The arguments are bytes | ||
component.dx = p.parseChar(); | ||
component.dy = p.parseChar(); | ||
if ((flags & 2) > 0) { | ||
// values are offset | ||
component.dx = p.parseChar(); | ||
component.dy = p.parseChar(); | ||
} else { | ||
// values are matched points | ||
component.matchedPoints = [p.parseByte(), p.parseByte()]; | ||
} | ||
} | ||
@@ -275,3 +288,24 @@ | ||
if (componentGlyph.points) { | ||
var transformedPoints = transformPoints(componentGlyph.points, component); | ||
var transformedPoints; | ||
if (component.matchedPoints === undefined) { | ||
// component positioned by offset | ||
transformedPoints = transformPoints(componentGlyph.points, component); | ||
} else { | ||
// component positioned by matched points | ||
if ((component.matchedPoints[0] > glyph.points.length - 1) || | ||
(component.matchedPoints[1] > componentGlyph.points.length - 1)) { | ||
throw Error('Matched points out of range in ' + glyph.name); | ||
} | ||
var firstPt = glyph.points[component.matchedPoints[0]]; | ||
var secondPt = componentGlyph.points[component.matchedPoints[1]]; | ||
var transform = { | ||
xScale: component.xScale, scale01: component.scale01, | ||
scale10: component.scale10, yScale: component.yScale, | ||
dx: 0, dy: 0 | ||
}; | ||
secondPt = transformPoints([secondPt], transform)[0]; | ||
transform.dx = firstPt.x - secondPt.x; | ||
transform.dy = firstPt.y - secondPt.y; | ||
transformedPoints = transformPoints(componentGlyph.points, transform); | ||
} | ||
glyph.points = glyph.points.concat(transformedPoints); | ||
@@ -278,0 +312,0 @@ } |
@@ -747,2 +747,7 @@ // The `name` naming table. | ||
nameID = parseInt(id); | ||
if (isNaN(nameID)) { | ||
throw new Error('Name table entry "' + key + '" does not exist, see nameTableNames for complete list.'); | ||
} | ||
namesWithNumericKeys[nameID] = names[key]; | ||
@@ -749,0 +754,0 @@ nameIDs.push(nameID); |
@@ -22,2 +22,4 @@ // The `sfnt` wrapper provides organization for the tables in the font. | ||
var post = require('./post'); | ||
var gsub = require('./gsub'); | ||
var meta = require('./meta'); | ||
@@ -302,2 +304,4 @@ function log2(v) { | ||
var metaTable = (font.metas && Object.keys(font.metas).length > 0) ? meta.make(font.metas) : undefined; | ||
// The order does not matter because makeSfntTable() will sort them. | ||
@@ -308,2 +312,9 @@ var tables = [headTable, hheaTable, maxpTable, os2Table, nameTable, cmapTable, postTable, cffTable, hmtxTable]; | ||
} | ||
// Optional tables | ||
if (font.tables.gsub) { | ||
tables.push(gsub.make(font.tables.gsub)); | ||
} | ||
if (metaTable) { | ||
tables.push(metaTable); | ||
} | ||
@@ -310,0 +321,0 @@ var sfntTable = makeSfntTable(tables); |
307
src/types.js
@@ -13,4 +13,16 @@ // Data types used in the OpenType font file. | ||
/** | ||
* @exports opentype.decode | ||
* @class | ||
*/ | ||
var decode = {}; | ||
/** | ||
* @exports opentype.encode | ||
* @class | ||
*/ | ||
var encode = {}; | ||
/** | ||
* @exports opentype.sizeOf | ||
* @class | ||
*/ | ||
var sizeOf = {}; | ||
@@ -27,3 +39,7 @@ | ||
// Convert an 8-bit unsigned integer to a list of 1 byte. | ||
/** | ||
* Convert an 8-bit unsigned integer to a list of 1 byte. | ||
* @param {number} | ||
* @returns {Array} | ||
*/ | ||
encode.BYTE = function(v) { | ||
@@ -33,6 +49,13 @@ check.argument(v >= 0 && v <= 255, 'Byte value should be between 0 and 255.'); | ||
}; | ||
/** | ||
* @constant | ||
* @type {number} | ||
*/ | ||
sizeOf.BYTE = constant(1); | ||
// Convert a 8-bit signed integer to a list of 1 byte. | ||
/** | ||
* Convert a 8-bit signed integer to a list of 1 byte. | ||
* @param {string} | ||
* @returns {Array} | ||
*/ | ||
encode.CHAR = function(v) { | ||
@@ -42,9 +65,17 @@ return [v.charCodeAt(0)]; | ||
/** | ||
* @constant | ||
* @type {number} | ||
*/ | ||
sizeOf.CHAR = constant(1); | ||
// Convert an ASCII string to a list of bytes. | ||
/** | ||
* Convert an ASCII string to a list of bytes. | ||
* @param {string} | ||
* @returns {Array} | ||
*/ | ||
encode.CHARARRAY = function(v) { | ||
var b = []; | ||
for (var i = 0; i < v.length; i += 1) { | ||
b.push(v.charCodeAt(i)); | ||
b[i] = v.charCodeAt(i); | ||
} | ||
@@ -55,2 +86,6 @@ | ||
/** | ||
* @param {Array} | ||
* @returns {number} | ||
*/ | ||
sizeOf.CHARARRAY = function(v) { | ||
@@ -60,3 +95,7 @@ return v.length; | ||
// Convert a 16-bit unsigned integer to a list of 2 bytes. | ||
/** | ||
* Convert a 16-bit unsigned integer to a list of 2 bytes. | ||
* @param {number} | ||
* @returns {Array} | ||
*/ | ||
encode.USHORT = function(v) { | ||
@@ -66,5 +105,13 @@ return [(v >> 8) & 0xFF, v & 0xFF]; | ||
/** | ||
* @constant | ||
* @type {number} | ||
*/ | ||
sizeOf.USHORT = constant(2); | ||
// Convert a 16-bit signed integer to a list of 2 bytes. | ||
/** | ||
* Convert a 16-bit signed integer to a list of 2 bytes. | ||
* @param {number} | ||
* @returns {Array} | ||
*/ | ||
encode.SHORT = function(v) { | ||
@@ -79,5 +126,13 @@ // Two's complement | ||
/** | ||
* @constant | ||
* @type {number} | ||
*/ | ||
sizeOf.SHORT = constant(2); | ||
// Convert a 24-bit unsigned integer to a list of 3 bytes. | ||
/** | ||
* Convert a 24-bit unsigned integer to a list of 3 bytes. | ||
* @param {number} | ||
* @returns {Array} | ||
*/ | ||
encode.UINT24 = function(v) { | ||
@@ -87,5 +142,13 @@ return [(v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF]; | ||
/** | ||
* @constant | ||
* @type {number} | ||
*/ | ||
sizeOf.UINT24 = constant(3); | ||
// Convert a 32-bit unsigned integer to a list of 4 bytes. | ||
/** | ||
* Convert a 32-bit unsigned integer to a list of 4 bytes. | ||
* @param {number} | ||
* @returns {Array} | ||
*/ | ||
encode.ULONG = function(v) { | ||
@@ -95,5 +158,13 @@ return [(v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF]; | ||
/** | ||
* @constant | ||
* @type {number} | ||
*/ | ||
sizeOf.ULONG = constant(4); | ||
// Convert a 32-bit unsigned integer to a list of 4 bytes. | ||
/** | ||
* Convert a 32-bit unsigned integer to a list of 4 bytes. | ||
* @param {number} | ||
* @returns {Array} | ||
*/ | ||
encode.LONG = function(v) { | ||
@@ -108,2 +179,6 @@ // Two's complement | ||
/** | ||
* @constant | ||
* @type {number} | ||
*/ | ||
sizeOf.LONG = constant(4); | ||
@@ -120,4 +195,7 @@ | ||
// FIXME Implement LONGDATETIME | ||
// Convert a 32-bit Apple Mac timestamp integer to a list of 8 bytes, 64-bit timestamp. | ||
/** | ||
* Convert a 32-bit Apple Mac timestamp integer to a list of 8 bytes, 64-bit timestamp. | ||
* @param {number} | ||
* @returns {Array} | ||
*/ | ||
encode.LONGDATETIME = function(v) { | ||
@@ -127,5 +205,13 @@ return [0, 0, 0, 0, (v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF]; | ||
/** | ||
* @constant | ||
* @type {number} | ||
*/ | ||
sizeOf.LONGDATETIME = constant(8); | ||
// Convert a 4-char tag to a list of 4 bytes. | ||
/** | ||
* Convert a 4-char tag to a list of 4 bytes. | ||
* @param {string} | ||
* @returns {Array} | ||
*/ | ||
encode.TAG = function(v) { | ||
@@ -139,2 +225,6 @@ check.argument(v.length === 4, 'Tag should be exactly 4 ASCII characters.'); | ||
/** | ||
* @constant | ||
* @type {number} | ||
*/ | ||
sizeOf.TAG = constant(4); | ||
@@ -157,2 +247,7 @@ | ||
// Convert a numeric operand or charstring number to a variable-size list of bytes. | ||
/** | ||
* Convert a numeric operand or charstring number to a variable-size list of bytes. | ||
* @param {number} | ||
* @returns {Array} | ||
*/ | ||
encode.NUMBER = function(v) { | ||
@@ -174,2 +269,6 @@ if (v >= -107 && v <= 107) { | ||
/** | ||
* @param {number} | ||
* @returns {number} | ||
*/ | ||
sizeOf.NUMBER = function(v) { | ||
@@ -179,4 +278,8 @@ return encode.NUMBER(v).length; | ||
// Convert a signed number between -32768 and +32767 to a three-byte value. | ||
// This ensures we always use three bytes, but is not the most compact format. | ||
/** | ||
* Convert a signed number between -32768 and +32767 to a three-byte value. | ||
* This ensures we always use three bytes, but is not the most compact format. | ||
* @param {number} | ||
* @returns {Array} | ||
*/ | ||
encode.NUMBER16 = function(v) { | ||
@@ -186,7 +289,15 @@ return [28, (v >> 8) & 0xFF, v & 0xFF]; | ||
/** | ||
* @constant | ||
* @type {number} | ||
*/ | ||
sizeOf.NUMBER16 = constant(3); | ||
// 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, | ||
// at the expense of wasting a few bytes for smaller numbers. | ||
/** | ||
* 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, | ||
* at the expense of wasting a few bytes for smaller numbers. | ||
* @param {number} | ||
* @returns {Array} | ||
*/ | ||
encode.NUMBER32 = function(v) { | ||
@@ -196,4 +307,12 @@ return [29, (v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF]; | ||
/** | ||
* @constant | ||
* @type {number} | ||
*/ | ||
sizeOf.NUMBER32 = constant(5); | ||
/** | ||
* @param {number} | ||
* @returns {Array} | ||
*/ | ||
encode.REAL = function(v) { | ||
@@ -235,2 +354,6 @@ var value = v.toString(); | ||
/** | ||
* @param {number} | ||
* @returns {number} | ||
*/ | ||
sizeOf.REAL = function(v) { | ||
@@ -246,2 +369,24 @@ return encode.REAL(v).length; | ||
/** | ||
* @param {DataView} data | ||
* @param {number} offset | ||
* @param {number} numBytes | ||
* @returns {string} | ||
*/ | ||
decode.UTF8 = function(data, offset, numBytes) { | ||
var codePoints = []; | ||
var numChars = numBytes; | ||
for (var j = 0; j < numChars; j++, offset += 1) { | ||
codePoints[j] = data.getUint8(offset); | ||
} | ||
return String.fromCharCode.apply(null, codePoints); | ||
}; | ||
/** | ||
* @param {DataView} data | ||
* @param {number} offset | ||
* @param {number} numBytes | ||
* @returns {string} | ||
*/ | ||
decode.UTF16 = function(data, offset, numBytes) { | ||
@@ -257,3 +402,7 @@ var codePoints = []; | ||
// Convert a JavaScript string to UTF16-BE. | ||
/** | ||
* Convert a JavaScript string to UTF16-BE. | ||
* @param {string} | ||
* @returns {Array} | ||
*/ | ||
encode.UTF16 = function(v) { | ||
@@ -263,4 +412,4 @@ var b = []; | ||
var codepoint = v.charCodeAt(i); | ||
b.push((codepoint >> 8) & 0xFF); | ||
b.push(codepoint & 0xFF); | ||
b[b.length] = (codepoint >> 8) & 0xFF; | ||
b[b.length] = codepoint & 0xFF; | ||
} | ||
@@ -271,2 +420,6 @@ | ||
/** | ||
* @param {string} | ||
* @returns {number} | ||
*/ | ||
sizeOf.UTF16 = function(v) { | ||
@@ -286,2 +439,5 @@ return v.length * 2; | ||
// print(s.encode('utf-8')) | ||
/** | ||
* @private | ||
*/ | ||
var eightBitMacEncodings = { | ||
@@ -322,6 +478,13 @@ 'x-mac-croatian': // Python: 'mac_croatian' | ||
// 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. | ||
/** | ||
* 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. | ||
* @param {DataView} dataView | ||
* @param {number} offset | ||
* @param {number} dataLength | ||
* @param {string} encoding | ||
* @returns {string} | ||
*/ | ||
decode.MACSTRING = function(dataView, offset, dataLength, encoding) { | ||
@@ -399,6 +562,11 @@ var table = eightBitMacEncodings[encoding]; | ||
// 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'. | ||
/** | ||
* 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'. | ||
* @param {string} str | ||
* @param {string} encoding | ||
* @returns {Array} | ||
*/ | ||
encode.MACSTRING = function(str, encoding) { | ||
@@ -424,4 +592,4 @@ var table = getMacEncodingTable(encoding); | ||
} | ||
result.push(c); | ||
result[i] = c; | ||
// result.push(c); | ||
} | ||
@@ -432,2 +600,7 @@ | ||
/** | ||
* @param {string} str | ||
* @param {string} encoding | ||
* @returns {number} | ||
*/ | ||
sizeOf.MACSTRING = function(str, encoding) { | ||
@@ -444,6 +617,10 @@ var b = encode.MACSTRING(str, encoding); | ||
// The values should be objects containing name / type / value. | ||
/** | ||
* @param {Array} l | ||
* @returns {Array} | ||
*/ | ||
encode.INDEX = function(l) { | ||
var i; | ||
//var offset, offsets, offsetEncoder, encodedOffsets, encodedOffset, data, | ||
// dataSize, i, v; | ||
// i, v; | ||
// Because we have to know which data type to use to encode the offsets, | ||
@@ -455,7 +632,5 @@ // we have to go through the values twice: once to encode the data and | ||
var data = []; | ||
var dataSize = 0; | ||
for (i = 0; i < l.length; i += 1) { | ||
var v = encode.OBJECT(l[i]); | ||
Array.prototype.push.apply(data, v); | ||
dataSize += v.length; | ||
offset += v.length; | ||
@@ -470,3 +645,3 @@ offsets.push(offset); | ||
var encodedOffsets = []; | ||
var offSize = (1 + Math.floor(Math.log(dataSize) / Math.log(2)) / 8) | 0; | ||
var offSize = (1 + Math.floor(Math.log(offset) / Math.log(2)) / 8) | 0; | ||
var offsetEncoder = [undefined, encode.BYTE, encode.USHORT, encode.UINT24, encode.ULONG][offSize]; | ||
@@ -484,2 +659,6 @@ for (i = 0; i < offsets.length; i += 1) { | ||
/** | ||
* @param {Array} | ||
* @returns {number} | ||
*/ | ||
sizeOf.INDEX = function(v) { | ||
@@ -489,5 +668,9 @@ return encode.INDEX(v).length; | ||
// Convert an object to a CFF DICT structure. | ||
// The keys should be numeric. | ||
// The values should be objects containing name / type / value. | ||
/** | ||
* Convert an object to a CFF DICT structure. | ||
* The keys should be numeric. | ||
* The values should be objects containing name / type / value. | ||
* @param {Object} m | ||
* @returns {Array} | ||
*/ | ||
encode.DICT = function(m) { | ||
@@ -510,2 +693,6 @@ var d = []; | ||
/** | ||
* @param {Object} | ||
* @returns {number} | ||
*/ | ||
sizeOf.DICT = function(m) { | ||
@@ -515,2 +702,6 @@ return encode.DICT(m).length; | ||
/** | ||
* @param {number} | ||
* @returns {Array} | ||
*/ | ||
encode.OPERATOR = function(v) { | ||
@@ -524,2 +715,7 @@ if (v < 1200) { | ||
/** | ||
* @param {Array} v | ||
* @param {string} | ||
* @returns {Array} | ||
*/ | ||
encode.OPERAND = function(v, type) { | ||
@@ -557,3 +753,8 @@ var d = []; | ||
var wmm = typeof WeakMap === 'function' && new WeakMap(); | ||
// Convert a list of CharString operations to bytes. | ||
/** | ||
* Convert a list of CharString operations to bytes. | ||
* @param {Array} | ||
* @returns {Array} | ||
*/ | ||
encode.CHARSTRING = function(ops) { | ||
@@ -583,2 +784,6 @@ // See encode.MACSTRING for why we don't do "if (wmm && wmm.has(ops))". | ||
/** | ||
* @param {Array} | ||
* @returns {number} | ||
*/ | ||
sizeOf.CHARSTRING = function(ops) { | ||
@@ -590,3 +795,7 @@ return encode.CHARSTRING(ops).length; | ||
// Convert an object containing name / type / value to bytes. | ||
/** | ||
* Convert an object containing name / type / value to bytes. | ||
* @param {Object} | ||
* @returns {Array} | ||
*/ | ||
encode.OBJECT = function(v) { | ||
@@ -598,2 +807,6 @@ var encodingFunction = encode[v.type]; | ||
/** | ||
* @param {Object} | ||
* @returns {number} | ||
*/ | ||
sizeOf.OBJECT = function(v) { | ||
@@ -605,5 +818,9 @@ var sizeOfFunction = sizeOf[v.type]; | ||
// Convert a table object to bytes. | ||
// A table contains a list of fields containing the metadata (name, type and default value). | ||
// The table itself has the field values set as attributes. | ||
/** | ||
* Convert a table object to bytes. | ||
* A table contains a list of fields containing the metadata (name, type and default value). | ||
* The table itself has the field values set as attributes. | ||
* @param {opentype.Table} | ||
* @returns {Array} | ||
*/ | ||
encode.TABLE = function(table) { | ||
@@ -648,2 +865,6 @@ var d = []; | ||
/** | ||
* @param {opentype.Table} | ||
* @returns {number} | ||
*/ | ||
sizeOf.TABLE = function(table) { | ||
@@ -650,0 +871,0 @@ var numBytes = 0; |
@@ -30,1 +30,4 @@ 'use strict'; | ||
exports.unhex = unhex; | ||
exports.unhexArray = function(str) { | ||
return Array.prototype.slice.call(new Uint8Array(unhex(str).buffer)); | ||
}; |
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 1 instance in 1 package
886629
72
18173
259
1
10