opentype.js
Advanced tools
Comparing version 0.4.8 to 0.4.9
@@ -8,14 +8,3 @@ #!/usr/bin/env node | ||
var path = require('path'); | ||
var spawn = require('child_process').spawn; | ||
var watchify = spawn('./node_modules/.bin/watchify', ['src/opentype.js', '--standalone', 'opentype', '--debug', '-o', 'build/opentype.js', '-v']); | ||
watchify.stdout.on('data', function(d) { | ||
console.log('WATCH', d.toString()); | ||
}); | ||
watchify.stderr.on('data', function(d) { | ||
console.log('WATCH', d.toString()); | ||
}); | ||
var CONTENT_TYPES = { | ||
@@ -39,2 +28,5 @@ '.html': 'text/html', | ||
rewrite = ' -> ' + url; | ||
} else if (url === '../dist/opentype.js') { | ||
url = '../build/opentype.js'; | ||
rewrite = ' -> ' + url; | ||
} | ||
@@ -41,0 +33,0 @@ |
{ | ||
"name": "opentype.js", | ||
"version": "0.4.8", | ||
"version": "0.4.9", | ||
"main": "dist/opentype.js", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -35,3 +35,3 @@ # Contributing | ||
rewrites the JavaScript URL from `dist/opentype.min.js` to `build/opentype.js`. | ||
6. Make some changes | ||
@@ -42,3 +42,3 @@ | ||
npm test | ||
8. Commit your changes | ||
@@ -63,6 +63,5 @@ | ||
1. Update the version number in `package.json` and `bower.json`. | ||
2. Run `npm run dist` to update the files in the `dist` folder. | ||
3. Commit (`git commit -a`) and create a tag (e.g. `git tag 1.2.1`). Push and push tags (`git push && git push --tags`). | ||
4. Run `npm publish` to publish the package to npm. Bower updates automatically. | ||
2. Add information about the new release in `RELEASES.md`. | ||
3. Run `npm run dist` to update the files in the `dist` folder. | ||
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. |
{ | ||
"name": "opentype.js", | ||
"description": "OpenType font parser", | ||
"version": "0.4.8", | ||
"version": "0.4.9", | ||
"author": { | ||
@@ -17,8 +17,3 @@ "name": "Frederik De Bleser", | ||
], | ||
"licenses": [ | ||
{ | ||
"type": "MIT", | ||
"url": "https://raw.github.com/nodebox/opentype.js/master/LICENSE" | ||
} | ||
], | ||
"license": "MIT", | ||
"repository": { | ||
@@ -33,13 +28,16 @@ "type": "git", | ||
"scripts": { | ||
"start": "mkdir -p build && bin/server.js", | ||
"watch": "watchify src/opentype.js --standalone opentype --debug -o build/opentype.js -v", | ||
"start": "mkdirp build && parallelshell \"npm run watch\" \"node ./bin/server.js\"", | ||
"test": "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", | ||
"dist": "npm run test && npm run browserify && npm run uglify" | ||
"dist": "rimraf build && rimraf dist && mkdirp build && mkdirp dist && npm run test && npm run browserify && npm run uglify" | ||
}, | ||
"dependencies": {}, | ||
"devDependencies": { | ||
"browserify": "^9.0.3", | ||
"jscs": "^1.12.0", | ||
"jshint": "^2.6.3", | ||
"jshint": "^2.8.0", | ||
"mkdirp": "^0.5.1", | ||
"parallelshell": "^1.1.1", | ||
"rimraf": "^2.4.0", | ||
"uglifyify": "^3.0.1", | ||
@@ -46,0 +44,0 @@ "watchify": "^2.6.0" |
@@ -0,1 +1,6 @@ | ||
0.4.9 (June 23, 2015) | ||
===================== | ||
* Improve memory usage by deferring glyph / path loading. Thanks @Pomax! | ||
* Put examples in the "examples" directory. Use the local web server to see them. | ||
0.4.8 (June 3, 2015) | ||
@@ -2,0 +7,0 @@ ==================== |
@@ -136,3 +136,3 @@ // Glyph encoding | ||
for (var i = 0; i < glyphs.length; i += 1) { | ||
var glyph = glyphs[i]; | ||
var glyph = glyphs.get(i); | ||
for (var j = 0; j < glyph.unicodes.length; j += 1) { | ||
@@ -210,6 +210,7 @@ if (glyph.unicodes[j] === code) { | ||
var charCodes = Object.keys(glyphIndexMap); | ||
for (var i = 0; i < charCodes.length; i += 1) { | ||
var c = charCodes[i]; | ||
var glyphIndex = glyphIndexMap[c]; | ||
glyph = font.glyphs[glyphIndex]; | ||
glyph = font.glyphs.get(glyphIndex); | ||
glyph.addUnicode(parseInt(c)); | ||
@@ -219,3 +220,3 @@ } | ||
for (i = 0; i < font.glyphs.length; i += 1) { | ||
glyph = font.glyphs[i]; | ||
glyph = font.glyphs.get(i); | ||
if (font.cffEncoding) { | ||
@@ -222,0 +223,0 @@ glyph.name = font.cffEncoding.charset[i]; |
@@ -8,2 +8,3 @@ // The Font object | ||
var encoding = require('./encoding'); | ||
var glyphset = require('./glyphset'); | ||
@@ -33,3 +34,3 @@ // A Font represents a loaded OpenType font file. | ||
this.supported = true; | ||
this.glyphs = options.glyphs || []; | ||
this.glyphs = new glyphset.GlyphSet(this, options.glyphs || []); | ||
this.encoding = new encoding.DefaultEncoding(this); | ||
@@ -56,6 +57,6 @@ this.tables = {}; | ||
var glyphIndex = this.charToGlyphIndex(c); | ||
var glyph = this.glyphs[glyphIndex]; | ||
var glyph = this.glyphs.get(glyphIndex); | ||
if (!glyph) { | ||
// .notdef | ||
glyph = this.glyphs[0]; | ||
glyph = this.glyphs.get(0); | ||
} | ||
@@ -86,6 +87,6 @@ | ||
var glyphIndex = this.nametoGlyphIndex(name); | ||
var glyph = this.glyphs[glyphIndex]; | ||
var glyph = this.glyphs.get(glyphIndex); | ||
if (!glyph) { | ||
// .notdef | ||
glyph = this.glyphs[0]; | ||
glyph = this.glyphs.get(0); | ||
} | ||
@@ -92,0 +93,0 @@ |
@@ -9,2 +9,21 @@ // The Glyph object | ||
function getPathDefinition(glyph, path) { | ||
var _path = path || { commands: [] }; | ||
return { | ||
configurable: true, | ||
get: function() { | ||
if (typeof _path === 'function') { | ||
_path = _path(); | ||
} | ||
return _path; | ||
}, | ||
set: function(p) { | ||
_path = p; | ||
} | ||
}; | ||
} | ||
// A Glyph is an individual mark that often corresponds to a character. | ||
@@ -16,15 +35,43 @@ // Some glyphs, such as ligatures, are a combination of many characters. | ||
function Glyph(options) { | ||
this.font = options.font || null; | ||
// By putting all the code on a prototype function (which is only declared once) | ||
// we reduce the memory requirements for larger fonts by some 2% | ||
this.bindConstructorValues(options); | ||
} | ||
Glyph.prototype.bindConstructorValues = function(options) { | ||
this.index = options.index || 0; | ||
// These three values cannnot be deferred for memory optimization: | ||
this.name = options.name || null; | ||
this.unicode = options.unicode || undefined; | ||
this.unicodes = options.unicodes || options.unicode !== undefined ? [options.unicode] : []; | ||
this.xMin = options.xMin || 0; | ||
this.yMin = options.yMin || 0; | ||
this.xMax = options.xMax || 0; | ||
this.yMax = options.yMax || 0; | ||
this.advanceWidth = options.advanceWidth || 0; | ||
this.path = options.path || null; | ||
} | ||
// But by binding these values only when necessary, we reduce can | ||
// the memory requirements by almost 3% for larger fonts. | ||
if (options.xMin) { | ||
this.xMin = options.xMin; | ||
} | ||
if (options.yMin) { | ||
this.yMin = options.yMin; | ||
} | ||
if (options.xMax) { | ||
this.xMax = options.xMax; | ||
} | ||
if (options.yMax) { | ||
this.yMax = options.yMax; | ||
} | ||
if (options.advanceWidth) { | ||
this.advanceWidth = options.advanceWidth; | ||
} | ||
// The path for a glyph is the most memory intensive, and is bound as a value | ||
// with a getter/setter to ensure we actually do path parsing only once the | ||
// path is actually needed by anything. | ||
Object.defineProperty(this, 'path', getPathDefinition(this, options.path)); | ||
}; | ||
Glyph.prototype.addUnicode = function(unicode) { | ||
@@ -47,3 +94,3 @@ if (this.unicodes.length === 0) { | ||
fontSize = fontSize !== undefined ? fontSize : 72; | ||
var scale = 1 / this.font.unitsPerEm * fontSize; | ||
var scale = 1 / this.path.unitsPerEm * fontSize; | ||
var p = new path.Path(); | ||
@@ -163,3 +210,3 @@ var commands = this.path.commands; | ||
fontSize = fontSize !== undefined ? fontSize : 24; | ||
var scale = 1 / this.font.unitsPerEm * fontSize; | ||
var scale = 1 / this.path.unitsPerEm * fontSize; | ||
@@ -204,3 +251,3 @@ var blueCircles = []; | ||
fontSize = fontSize !== undefined ? fontSize : 24; | ||
scale = 1 / this.font.unitsPerEm * fontSize; | ||
scale = 1 / this.path.unitsPerEm * fontSize; | ||
ctx.lineWidth = 1; | ||
@@ -213,14 +260,22 @@ | ||
// This code is here due to memory optimization: by not using | ||
// defaults in the constructor, we save a notable amount of memory. | ||
var xMin = this.xMin || 0; | ||
var yMin = this.yMin || 0; | ||
var xMax = this.xMax || 0; | ||
var yMax = this.yMax || 0; | ||
var advanceWidth = this.advanceWidth || 0; | ||
// Draw the glyph box | ||
ctx.strokeStyle = 'blue'; | ||
draw.line(ctx, x + (this.xMin * scale), -10000, x + (this.xMin * scale), 10000); | ||
draw.line(ctx, x + (this.xMax * scale), -10000, x + (this.xMax * scale), 10000); | ||
draw.line(ctx, -10000, y + (-this.yMin * scale), 10000, y + (-this.yMin * scale)); | ||
draw.line(ctx, -10000, y + (-this.yMax * scale), 10000, y + (-this.yMax * scale)); | ||
draw.line(ctx, x + (xMin * scale), -10000, x + (xMin * scale), 10000); | ||
draw.line(ctx, x + (xMax * scale), -10000, x + (xMax * scale), 10000); | ||
draw.line(ctx, -10000, y + (-yMin * scale), 10000, y + (-yMin * scale)); | ||
draw.line(ctx, -10000, y + (-yMax * scale), 10000, y + (-yMax * scale)); | ||
// Draw the advance width | ||
ctx.strokeStyle = 'green'; | ||
draw.line(ctx, x + (this.advanceWidth * scale), -10000, x + (this.advanceWidth * scale), 10000); | ||
draw.line(ctx, x + (advanceWidth * scale), -10000, x + (advanceWidth * scale), 10000); | ||
}; | ||
exports.Glyph = Glyph; |
// opentype.js | ||
// https://github.com/nodebox/opentype.js | ||
// (c) 2014 Frederik De Bleser | ||
// (c) 2015 Frederik De Bleser | ||
// opentype.js may be freely distributed under the MIT license. | ||
@@ -5,0 +5,0 @@ |
@@ -9,3 +9,3 @@ // The `CFF` table contains the glyph outlines in PostScript format. | ||
var encoding = require('../encoding'); | ||
var _glyph = require('../glyph'); | ||
var glyphset = require('../glyphset'); | ||
var parse = require('../parse'); | ||
@@ -366,3 +366,3 @@ var path = require('../path'); | ||
// https://www.microsoft.com/typography/OTSPEC/charstr2.htm | ||
function parseCFFCharstring(code, font, index) { | ||
function parseCFFCharstring(font, glyph, code) { | ||
var c1x; | ||
@@ -571,3 +571,3 @@ var c1y; | ||
default: | ||
console.log('Glyph ' + index + ': unknown operator ' + 1200 + v); | ||
console.log('Glyph ' + glyph.index + ': unknown operator ' + 1200 + v); | ||
stack.length = 0; | ||
@@ -742,3 +742,3 @@ } | ||
if (v < 32) { | ||
console.log('Glyph ' + index + ': unknown operator ' + v); | ||
console.log('Glyph ' + glyph.index + ': unknown operator ' + v); | ||
} else if (v < 247) { | ||
@@ -767,6 +767,5 @@ stack.push(v - 139); | ||
parse(code); | ||
var glyph = new _glyph.Glyph({font: font, index: index}); | ||
glyph.path = p; | ||
glyph.advanceWidth = width; | ||
return glyph; | ||
return p; | ||
} | ||
@@ -835,6 +834,6 @@ | ||
font.glyphs = []; | ||
font.glyphs = new glyphset.GlyphSet(font); | ||
for (var i = 0; i < font.nGlyphs; i += 1) { | ||
var charString = charStringsIndex.objects[i]; | ||
font.glyphs.push(parseCFFCharstring(charString, font, i)); | ||
font.glyphs.push(i, glyphset.cffGlyphLoader(font, i, parseCFFCharstring, charString)); | ||
} | ||
@@ -1027,4 +1026,5 @@ } | ||
]); | ||
for (var i = 0; i < glyphs.length; i += 1) { | ||
var glyph = glyphs[i]; | ||
var glyph = glyphs.get(i); | ||
var ops = glyphToOps(glyph); | ||
@@ -1084,6 +1084,8 @@ t.charStrings.push({name: glyph.name, type: 'CHARSTRING', value: ops}); | ||
var glyphNames = []; | ||
var glyph; | ||
// Skip first glyph (.notdef) | ||
for (var i = 1; i < glyphs.length; i += 1) { | ||
glyphNames.push(glyphs[i].name); | ||
glyph = glyphs.get(i); | ||
glyphNames.push(glyph.name); | ||
} | ||
@@ -1090,0 +1092,0 @@ |
@@ -130,3 +130,3 @@ // The `cmap` table stores the mappings from characters to glyphs. | ||
for (i = 0; i < glyphs.length; i += 1) { | ||
var glyph = glyphs[i]; | ||
var glyph = glyphs.get(i); | ||
for (var j = 0; j < glyph.unicodes.length; j += 1) { | ||
@@ -133,0 +133,0 @@ addSegment(t, glyph.unicodes[j], i); |
@@ -7,3 +7,3 @@ // The `glyf` table describes the glyphs in TrueType outline format. | ||
var check = require('../check'); | ||
var _glyph = require('../glyph'); | ||
var glyphset = require('../glyphset'); | ||
var parse = require('../parse'); | ||
@@ -39,8 +39,4 @@ var path = require('../path'); | ||
// Parse a TrueType glyph. | ||
function parseGlyph(data, start, index, font) { | ||
//var p, glyph, flag, i, j, flags, | ||
// endPointIndices, numberOfCoordinates, repeatCount, points, point, px, py, | ||
// component, moreComponents; | ||
function parseGlyph(glyph, data, start) { | ||
var p = new parse.Parser(data, start); | ||
var glyph = new _glyph.Glyph({font: font, index: index}); | ||
glyph.numberOfContours = p.parseShort(); | ||
@@ -165,4 +161,2 @@ glyph.xMin = p.parseShort(); | ||
} | ||
return glyph; | ||
} | ||
@@ -274,6 +268,22 @@ | ||
function buildPath(glyphs, glyph) { | ||
if (glyph.isComposite) { | ||
for (var j = 0; j < glyph.components.length; j += 1) { | ||
var component = glyph.components[j]; | ||
var componentGlyph = glyphs.get(component.glyphIndex); | ||
if (componentGlyph.points) { | ||
var transformedPoints = transformPoints(componentGlyph.points, component); | ||
glyph.points = glyph.points.concat(transformedPoints); | ||
} | ||
} | ||
} | ||
return getPath(glyph.points); | ||
} | ||
// Parse all the glyphs according to the offsets from the `loca` table. | ||
function parseGlyfTable(data, start, loca, font) { | ||
var glyphs = []; | ||
var glyphs = new glyphset.GlyphSet(font); | ||
var i; | ||
// The last element of the loca table is invalid. | ||
@@ -284,24 +294,8 @@ for (i = 0; i < loca.length - 1; i += 1) { | ||
if (offset !== nextOffset) { | ||
glyphs.push(parseGlyph(data, start + offset, i, font)); | ||
glyphs.push(i, glyphset.ttfGlyphLoader(font, i, parseGlyph, data, start + offset, buildPath)); | ||
} else { | ||
glyphs.push(new _glyph.Glyph({font: font, index: i})); | ||
glyphs.push(i, glyphset.glyphLoader(font, i)); | ||
} | ||
} | ||
// Go over the glyphs again, resolving the composite glyphs. | ||
for (i = 0; i < glyphs.length; i += 1) { | ||
var glyph = glyphs[i]; | ||
if (glyph.isComposite) { | ||
for (var j = 0; j < glyph.components.length; j += 1) { | ||
var component = glyph.components[j]; | ||
var componentGlyph = glyphs[component.glyphIndex]; | ||
if (componentGlyph.points) { | ||
var transformedPoints = transformPoints(componentGlyph.points, component); | ||
glyph.points = glyph.points.concat(transformedPoints); | ||
} | ||
} | ||
} | ||
glyph.path = getPath(glyph.points); | ||
} | ||
return glyphs; | ||
@@ -308,0 +302,0 @@ } |
@@ -22,3 +22,3 @@ // The `hmtx` table contains the horizontal metrics for all glyphs. | ||
var glyph = glyphs[i]; | ||
var glyph = glyphs.get(i); | ||
glyph.advanceWidth = advanceWidth; | ||
@@ -32,3 +32,3 @@ glyph.leftSideBearing = leftSideBearing; | ||
for (var i = 0; i < glyphs.length; i += 1) { | ||
var glyph = glyphs[i]; | ||
var glyph = glyphs.get(i); | ||
var advanceWidth = glyph.advanceWidth || 0; | ||
@@ -35,0 +35,0 @@ var leftSideBearing = glyph.leftSideBearing || 0; |
@@ -112,3 +112,3 @@ // The `sfnt` wrapper provides organization for the tables in the font. | ||
if (glyphIndex > 0) { | ||
var glyph = font.glyphs[glyphIndex]; | ||
var glyph = font.glyphs.get(glyphIndex); | ||
return glyph.getMetrics(); | ||
@@ -140,3 +140,3 @@ } | ||
var rightSideBearings = []; | ||
var firstCharIndex = null; | ||
var firstCharIndex; | ||
var lastCharIndex = 0; | ||
@@ -147,4 +147,5 @@ var ulUnicodeRange1 = 0; | ||
var ulUnicodeRange4 = 0; | ||
for (var i = 0; i < font.glyphs.length; i += 1) { | ||
var glyph = font.glyphs[i]; | ||
var glyph = font.glyphs.get(i); | ||
var unicode = glyph.unicode | 0; | ||
@@ -151,0 +152,0 @@ if (firstCharIndex > unicode || firstCharIndex === null) { |
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
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
52
9
1
492353
8
9125