UNPKG

vesh-vj

Version:

VESH's JavaScript Framework

1,244 lines (1,112 loc) 170 kB
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.opentype = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ // Run-time checking of preconditions. 'use strict'; // Precondition function that checks if the given predicate is true. // If not, it will throw an error. exports.argument = function (predicate, message) { if (!predicate) { throw new Error(message); } }; // Precondition function that checks if the given assertion is true. // If not, it will throw an error. exports.assert = exports.argument; },{}],2:[function(require,module,exports){ // Drawing utility functions. 'use strict'; // Draw a line on the given context from point `x1,y1` to point `x2,y2`. function line(ctx, x1, y1, x2, y2) { ctx.beginPath(); ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.stroke(); } exports.line = line; },{}],3:[function(require,module,exports){ // Glyph encoding 'use strict'; var cffStandardStrings = [ '.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl', 'periodcentered', 'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', 'questiondown', 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine', 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae', 'dotlessi', 'lslash', 'oslash', 'oe', 'germandbls', 'onesuperior', 'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', 'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters', 'twosuperior', 'registered', 'minus', 'eth', 'multiply', 'threesuperior', 'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', 'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', 'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', 'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', 'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla', 'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex', 'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis', 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis', 'ugrave', 'yacute', 'ydieresis', 'zcaron', 'exclamsmall', 'Hungarumlautsmall', 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', '266 ff', 'onedotenleader', 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'commasuperior', 'threequartersemdash', 'periodsuperior', 'questionsmall', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'ffi', 'ffl', 'parenleftinferior', 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall', 'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'foursuperior', 'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall', 'Ydieresissmall', '001.000', '001.001', '001.002', '001.003', 'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman', 'Semibold']; var cffStandardEncoding = [ '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'exclamdown', 'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', '', 'endash', 'dagger', 'daggerdbl', 'periodcentered', '', 'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', '', 'questiondown', '', 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', '', 'ring', 'cedilla', '', 'hungarumlaut', 'ogonek', 'caron', 'emdash', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'AE', '', 'ordfeminine', '', '', '', '', 'Lslash', 'Oslash', 'OE', 'ordmasculine', '', '', '', '', '', 'ae', '', '', '', 'dotlessi', '', '', 'lslash', 'oslash', 'oe', 'germandbls']; var cffExpertEncoding = [ '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'space', 'exclamsmall', 'Hungarumlautsmall', '', 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma', 'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', 'commasuperior', 'threequartersemdash', 'periodsuperior', 'questionsmall', '', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', '', '', 'isuperior', '', '', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', '', '', 'rsuperior', 'ssuperior', 'tsuperior', '', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', '', 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall', '', '', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall', 'Caronsmall', '', 'Dotaccentsmall', '', '', 'Macronsmall', '', '', 'figuredash', 'hypheninferior', '', '', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', '', '', '', 'onequarter', 'onehalf', 'threequarters', 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds', '', '', 'zerosuperior', 'onesuperior', 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall', 'Ydieresissmall']; var standardNames = [ '.notdef', '.null', 'nonmarkingreturn', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', 'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', 'Adieresis', 'Aring', 'Ccedilla', 'Eacute', 'Ntilde', 'Odieresis', 'Udieresis', 'aacute', 'agrave', 'acircumflex', 'adieresis', 'atilde', 'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex', 'edieresis', 'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde', 'oacute', 'ograve', 'ocircumflex', 'odieresis', 'otilde', 'uacute', 'ugrave', 'ucircumflex', 'udieresis', 'dagger', 'degree', 'cent', 'sterling', 'section', 'bullet', 'paragraph', 'germandbls', 'registered', 'copyright', 'trademark', 'acute', 'dieresis', 'notequal', 'AE', 'Oslash', 'infinity', 'plusminus', 'lessequal', 'greaterequal', 'yen', 'mu', 'partialdiff', 'summation', 'product', 'pi', 'integral', 'ordfeminine', 'ordmasculine', 'Omega', 'ae', 'oslash', 'questiondown', 'exclamdown', 'logicalnot', 'radical', 'florin', 'approxequal', 'Delta', 'guillemotleft', 'guillemotright', 'ellipsis', 'nonbreakingspace', 'Agrave', 'Atilde', 'Otilde', 'OE', 'oe', 'endash', 'emdash', 'quotedblleft', 'quotedblright', 'quoteleft', 'quoteright', 'divide', 'lozenge', 'ydieresis', 'Ydieresis', 'fraction', 'currency', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'daggerdbl', 'periodcentered', 'quotesinglbase', 'quotedblbase', 'perthousand', 'Acircumflex', 'Ecircumflex', 'Aacute', 'Edieresis', 'Egrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Oacute', 'Ocircumflex', 'apple', 'Ograve', 'Uacute', 'Ucircumflex', 'Ugrave', 'dotlessi', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron', 'Lslash', 'lslash', 'Scaron', 'scaron', 'Zcaron', 'zcaron', 'brokenbar', 'Eth', 'eth', 'Yacute', 'yacute', 'Thorn', 'thorn', 'minus', 'multiply', 'onesuperior', 'twosuperior', 'threesuperior', 'onehalf', 'onequarter', 'threequarters', 'franc', 'Gbreve', 'gbreve', 'Idotaccent', 'Scedilla', 'scedilla', 'Cacute', 'cacute', 'Ccaron', 'ccaron', 'dcroat']; // 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. function DefaultEncoding(font) { this.font = font; } DefaultEncoding.prototype.charToGlyphIndex = function (c) { var code, glyphs, i, glyph, j; code = c.charCodeAt(0); glyphs = this.font.glyphs; if (glyphs) { for (i = 0; i < glyphs.length; i += 1) { glyph = glyphs[i]; for (j = 0; j < glyph.unicodes.length; j += 1) { if (glyph.unicodes[j] === code) { return i; } } } } else { return null; } }; function CmapEncoding(cmap) { this.cmap = cmap; } CmapEncoding.prototype.charToGlyphIndex = function (c) { return this.cmap.glyphIndexMap[c.charCodeAt(0)] || 0; }; function CffEncoding(encoding, charset) { this.encoding = encoding; this.charset = charset; } CffEncoding.prototype.charToGlyphIndex = function (s) { var code, charName; code = s.charCodeAt(0); charName = this.encoding[code]; return this.charset.indexOf(charName); }; function GlyphNames(post) { var i; switch (post.version) { case 1: this.names = exports.standardNames.slice(); break; case 2: this.names = new Array(post.numberOfGlyphs); for (i = 0; i < post.numberOfGlyphs; i++) { if (post.glyphNameIndex[i] < exports.standardNames.length) { this.names[i] = exports.standardNames[post.glyphNameIndex[i]]; } else { this.names[i] = post.names[post.glyphNameIndex[i] - exports.standardNames.length]; } } break; case 2.5: this.names = new Array(post.numberOfGlyphs); for (i = 0; i < post.numberOfGlyphs; i++) { this.names[i] = exports.standardNames[i + post.glyphNameIndex[i]]; } break; case 3: this.names = []; break; } } GlyphNames.prototype.nameToGlyphIndex = function (name) { return this.names.indexOf(name); }; GlyphNames.prototype.glyphIndexToName = function (gid) { return this.names[gid]; }; function addGlyphNames(font) { var glyphIndexMap, charCodes, i, c, glyphIndex, glyph; glyphIndexMap = font.tables.cmap.glyphIndexMap; charCodes = Object.keys(glyphIndexMap); for (i = 0; i < charCodes.length; i += 1) { c = charCodes[i]; glyphIndex = glyphIndexMap[c]; glyph = font.glyphs[glyphIndex]; glyph.addUnicode(parseInt(c)); } for (i = 0; i < font.glyphs.length; i += 1) { glyph = font.glyphs[i]; if (font.cffEncoding) { glyph.name = font.cffEncoding.charset[i]; } else { glyph.name = font.glyphNames.glyphIndexToName(i); } } } exports.cffStandardStrings = cffStandardStrings; exports.cffStandardEncoding = cffStandardEncoding; exports.cffExpertEncoding = cffExpertEncoding; exports.standardNames = standardNames; exports.DefaultEncoding = DefaultEncoding; exports.CmapEncoding = CmapEncoding; exports.CffEncoding = CffEncoding; exports.GlyphNames = GlyphNames; exports.addGlyphNames = addGlyphNames; },{}],4:[function(require,module,exports){ // The Font object 'use strict'; var path = require('./path'); var sfnt = require('./tables/sfnt'); var encoding = require('./encoding'); // 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. function Font(options) { options = options || {}; // OS X will complain if the names are empty, so we put a single space everywhere by default. this.familyName = options.familyName || ' '; this.styleName = options.styleName || ' '; this.designer = options.designer || ' '; this.designerURL = options.designerURL || ' '; this.manufacturer = options.manufacturer || ' '; this.manufacturerURL = options.manufacturerURL || ' '; this.license = options.license || ' '; this.licenseURL = options.licenseURL || ' '; this.version = options.version || 'Version 0.1'; this.description = options.description || ' '; this.copyright = options.copyright || ' '; this.trademark = options.trademark || ' '; this.unitsPerEm = options.unitsPerEm || 1000; this.supported = true; this.glyphs = options.glyphs || []; this.encoding = new encoding.DefaultEncoding(this); this.tables = {}; } // Check if the font has a glyph for the given character. Font.prototype.hasChar = function (c) { 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. Font.prototype.charToGlyphIndex = function (s) { 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. Font.prototype.charToGlyph = function (c) { var glyphIndex, glyph; glyphIndex = this.charToGlyphIndex(c); glyph = this.glyphs[glyphIndex]; if (!glyph) { glyph = this.glyphs[0]; // .notdef } return glyph; }; // 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. Font.prototype.stringToGlyphs = function (s) { var i, c, glyphs; glyphs = []; for (i = 0; i < s.length; i += 1) { c = s[i]; glyphs.push(this.charToGlyph(c)); } return glyphs; }; Font.prototype.nameToGlyphIndex = function (name) { return this.glyphNames.nameToGlyphIndex(name); }; Font.prototype.nameToGlyph = function (name) { var glyphIndex, glyph; glyphIndex = this.nametoGlyphIndex(name); glyph = this.glyphs[glyphIndex]; if (!glyph) { glyph = this.glyphs[0]; // .notdef } return glyph; }; Font.prototype.glyphIndexToName = function (gid) { if (!this.glyphNames.glyphIndexToName) { return ''; } return this.glyphNames.glyphIndexToName(gid); }; // 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. Font.prototype.getKerningValue = function (leftGlyph, rightGlyph) { leftGlyph = leftGlyph.index || leftGlyph; rightGlyph = rightGlyph.index || rightGlyph; var gposKerning = this.getGposKerningValue; return gposKerning ? gposKerning(leftGlyph, rightGlyph) : (this.kerningPairs[leftGlyph + ',' + rightGlyph] || 0); }; // Helper function that invokes the given callback for each glyph in the given text. // The callback gets `(glyph, x, y, fontSize, options)`. Font.prototype.forEachGlyph = function (text, x, y, fontSize, options, callback) { var kerning, fontScale, glyphs, i, glyph, kerningValue; if (!this.supported) { return; } x = x !== undefined ? x : 0; y = y !== undefined ? y : 0; fontSize = fontSize !== undefined ? fontSize : 72; options = options || {}; kerning = options.kerning === undefined ? true : options.kerning; fontScale = 1 / this.unitsPerEm * fontSize; glyphs = this.stringToGlyphs(text); for (i = 0; i < glyphs.length; i += 1) { glyph = glyphs[i]; callback(glyph, x, y, fontSize, options); if (glyph.advanceWidth) { x += glyph.advanceWidth * fontScale; } if (kerning && i < glyphs.length - 1) { kerningValue = this.getKerningValue(glyph, glyphs[i + 1]); x += kerningValue * fontScale; } } }; // 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. Font.prototype.getPath = function (text, x, y, fontSize, options) { var fullPath = new path.Path(); this.forEachGlyph(text, x, y, fontSize, options, function (glyph, gX, gY, gFontSize) { var glyphPath = glyph.getPath(gX, gY, gFontSize); fullPath.extend(glyphPath); }); return fullPath; }; // 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) Font.prototype.draw = function (ctx, text, x, y, fontSize, options) { 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) Font.prototype.drawPoints = function (ctx, text, x, y, fontSize, options) { this.forEachGlyph(text, x, y, fontSize, options, function (glyph, gX, gY, gFontSize) { glyph.drawPoints(ctx, 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) Font.prototype.drawMetrics = function (ctx, text, x, y, fontSize, options) { this.forEachGlyph(text, x, y, fontSize, options, function (glyph, gX, gY, gFontSize) { glyph.drawMetrics(ctx, gX, gY, gFontSize); }); }; // Validate Font.prototype.validate = function () { var warnings = []; var font = this; function assert(predicate, message) { if (!predicate) { warnings.push(message); } } function assertStringAttribute(attrName) { assert(font[attrName] && font[attrName].trim().length > 0, 'No ' + attrName + ' specified.'); } // Identification information assertStringAttribute('familyName'); assertStringAttribute('weightName'); assertStringAttribute('manufacturer'); assertStringAttribute('copyright'); assertStringAttribute('version'); // Dimension information assert(this.unitsPerEm > 0, 'No unitsPerEm specified.'); }; // Convert the font object to a SFNT data structure. // This structure contains all the necessary tables and metadata to create a binary OTF file. Font.prototype.toTables = function () { return sfnt.fontToTable(this); }; Font.prototype.toBuffer = function () { var sfntTable = this.toTables(); var bytes = sfntTable.encode(); var buffer = new ArrayBuffer(bytes.length); var intArray = new Uint8Array(buffer); for (var i = 0; i < bytes.length; i++) { intArray[i] = bytes[i]; } return buffer; }; // Initiate a download of the OpenType font. Font.prototype.download = function () { var fileName = this.familyName.replace(/\s/g, '') + '-' + this.styleName + '.otf'; var buffer = this.toBuffer(); window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem; window.requestFileSystem(window.TEMPORARY, buffer.byteLength, function (fs) { fs.root.getFile(fileName, {create: true}, function (fileEntry) { fileEntry.createWriter(function (writer) { var dataView = new DataView(buffer); var blob = new Blob([dataView], {type: 'font/opentype'}); writer.write(blob); writer.addEventListener('writeend', function () { // Navigating to the file will download it. location.href = fileEntry.toURL(); }, false); }); }); }, function (err) { throw err; }); }; exports.Font = Font; },{"./encoding":3,"./path":8,"./tables/sfnt":23}],5:[function(require,module,exports){ // The Glyph object 'use strict'; var check = require('./check'); var draw = require('./draw'); var path = require('./path'); // A Glyph is an individual mark that often corresponds to a character. // Some glyphs, such as ligatures, are a combination of many characters. // Glyphs are the basic building blocks of a font. // // The `Glyph` class contains utility methods for drawing the path and its points. function Glyph(options) { this.font = options.font || null; this.index = options.index || 0; 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; } Glyph.prototype.addUnicode = function (unicode) { if (this.unicodes.length === 0) { this.unicode = unicode; } this.unicodes.push(unicode); }; // 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). Glyph.prototype.getPath = function (x, y, fontSize) { var scale, p, commands, cmd; x = x !== undefined ? x : 0; y = y !== undefined ? y : 0; fontSize = fontSize !== undefined ? fontSize : 72; scale = 1 / this.font.unitsPerEm * fontSize; p = new path.Path(); commands = this.path.commands; for (var i = 0; i < commands.length; i += 1) { cmd = commands[i]; if (cmd.type === 'M') { p.moveTo(x + (cmd.x * scale), y + (-cmd.y * scale)); } else if (cmd.type === 'L') { p.lineTo(x + (cmd.x * scale), y + (-cmd.y * scale)); } else if (cmd.type === 'Q') { p.quadraticCurveTo(x + (cmd.x1 * scale), y + (-cmd.y1 * scale), x + (cmd.x * scale), y + (-cmd.y * scale)); } else if (cmd.type === 'C') { p.curveTo(x + (cmd.x1 * scale), y + (-cmd.y1 * scale), x + (cmd.x2 * scale), y + (-cmd.y2 * scale), x + (cmd.x * scale), y + (-cmd.y * scale)); } else if (cmd.type === 'Z') { p.closePath(); } } return p; }; // Split the glyph into contours. // This function is here for backwards compatibility, and to // provide raw access to the TrueType glyph outlines. Glyph.prototype.getContours = function () { var contours, currentContour, i, pt; if (this.points === undefined) { return []; } contours = []; currentContour = []; for (i = 0; i < this.points.length; i += 1) { pt = this.points[i]; currentContour.push(pt); if (pt.lastPointOfContour) { contours.push(currentContour); currentContour = []; } } check.argument(currentContour.length === 0, 'There are still points left in the current contour.'); return contours; }; // Calculate the xMin/yMin/xMax/yMax/lsb/rsb for a Glyph. Glyph.prototype.getMetrics = function () { var commands = this.path.commands; var xCoords = []; var yCoords = []; for (var i = 0; i < commands.length; i += 1) { var cmd = commands[i]; if (cmd.type !== 'Z') { xCoords.push(cmd.x); yCoords.push(cmd.y); } if (cmd.type === 'Q' || cmd.type === 'C') { xCoords.push(cmd.x1); yCoords.push(cmd.y1); } if (cmd.type === 'C') { xCoords.push(cmd.x2); yCoords.push(cmd.y2); } } var metrics = { xMin: Math.min.apply(null, xCoords), yMin: Math.min.apply(null, yCoords), xMax: Math.max.apply(null, xCoords), yMax: Math.max.apply(null, yCoords), leftSideBearing: 0 }; metrics.rightSideBearing = this.advanceWidth - metrics.leftSideBearing - (metrics.xMax - metrics.xMin); return metrics; }; // 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). Glyph.prototype.draw = function (ctx, x, y, fontSize) { this.getPath(x, y, fontSize).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). Glyph.prototype.drawPoints = function (ctx, x, y, fontSize) { function drawCircles(l, x, y, scale) { var j, PI_SQ = Math.PI * 2; ctx.beginPath(); for (j = 0; j < l.length; j += 1) { ctx.moveTo(x + (l[j].x * scale), y + (l[j].y * scale)); ctx.arc(x + (l[j].x * scale), y + (l[j].y * scale), 2, 0, PI_SQ, false); } ctx.closePath(); ctx.fill(); } var scale, i, blueCircles, redCircles, path, cmd; x = x !== undefined ? x : 0; y = y !== undefined ? y : 0; fontSize = fontSize !== undefined ? fontSize : 24; scale = 1 / this.font.unitsPerEm * fontSize; blueCircles = []; redCircles = []; path = this.path; for (i = 0; i < path.commands.length; i += 1) { cmd = path.commands[i]; if (cmd.x !== undefined) { blueCircles.push({x: cmd.x, y: -cmd.y}); } if (cmd.x1 !== undefined) { redCircles.push({x: cmd.x1, y: -cmd.y1}); } if (cmd.x2 !== undefined) { redCircles.push({x: cmd.x2, y: -cmd.y2}); } } ctx.fillStyle = 'blue'; drawCircles(blueCircles, x, y, scale); ctx.fillStyle = 'red'; drawCircles(redCircles, x, y, scale); }; // 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). Glyph.prototype.drawMetrics = function (ctx, x, y, fontSize) { var scale; x = x !== undefined ? x : 0; y = y !== undefined ? y : 0; fontSize = fontSize !== undefined ? fontSize : 24; scale = 1 / this.font.unitsPerEm * fontSize; ctx.lineWidth = 1; // Draw the origin ctx.strokeStyle = 'black'; draw.line(ctx, x, -10000, x, 10000); draw.line(ctx, -10000, y, 10000, y); // 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 the advance width ctx.strokeStyle = 'green'; draw.line(ctx, x + (this.advanceWidth * scale), -10000, x + (this.advanceWidth * scale), 10000); }; exports.Glyph = Glyph; },{"./check":1,"./draw":2,"./path":8}],6:[function(require,module,exports){ // opentype.js // https://github.com/nodebox/opentype.js // (c) 2014 Frederik De Bleser // opentype.js may be freely distributed under the MIT license. /* global ArrayBuffer, DataView, Uint8Array, XMLHttpRequest */ 'use strict'; var encoding = require('./encoding'); var _font = require('./font'); var glyph = require('./glyph'); var parse = require('./parse'); var path = require('./path'); var cmap = require('./tables/cmap'); var cff = require('./tables/cff'); var glyf = require('./tables/glyf'); var gpos = require('./tables/gpos'); var head = require('./tables/head'); var hhea = require('./tables/hhea'); var hmtx = require('./tables/hmtx'); var kern = require('./tables/kern'); var loca = require('./tables/loca'); var maxp = require('./tables/maxp'); var _name = require('./tables/name'); var os2 = require('./tables/os2'); var post = require('./tables/post'); // File loaders ///////////////////////////////////////////////////////// // Convert a Node.js Buffer to an ArrayBuffer function toArrayBuffer(buffer) { var i, arrayBuffer = new ArrayBuffer(buffer.length), data = new Uint8Array(arrayBuffer); for (i = 0; i < buffer.length; i += 1) { data[i] = buffer[i]; } return arrayBuffer; } function loadFromFile(path, callback) { var fs = require('fs'); fs.readFile(path, function (err, buffer) { if (err) { return callback(err.message); } callback(null, toArrayBuffer(buffer)); }); } function loadFromUrl(url, callback) { var request = new XMLHttpRequest(); request.open('get', url, true); request.responseType = 'arraybuffer'; request.onload = function () { if (request.status !== 200) { return callback('Font could not be loaded: ' + request.statusText); } return callback(null, request.response); }; request.send(); } // Public API /////////////////////////////////////////////////////////// // Parse the OpenType file data (as an ArrayBuffer) and return a Font object. // If the file could not be parsed (most likely because it contains Postscript outlines) // we return an empty Font object with the `supported` flag set to `false`. function parseBuffer(buffer) { var font, data, version, numTables, i, p, tag, offset, hmtxOffset, glyfOffset, locaOffset, cffOffset, kernOffset, gposOffset, indexToLocFormat, numGlyphs, locaTable, shortVersion; // OpenType fonts use big endian byte ordering. // We can't rely on typed array view types, because they operate with the endianness of the host computer. // Instead we use DataViews where we can specify endianness. font = new _font.Font(); data = new DataView(buffer, 0); version = parse.getFixed(data, 0); if (version === 1.0) { font.outlinesFormat = 'truetype'; } else { version = parse.getTag(data, 0); if (version === 'OTTO') { font.outlinesFormat = 'cff'; } else { throw new Error('Unsupported OpenType version ' + version); } } numTables = parse.getUShort(data, 4); // Offset into the table records. p = 12; for (i = 0; i < numTables; i += 1) { tag = parse.getTag(data, p); offset = parse.getULong(data, p + 8); switch (tag) { case 'cmap': font.tables.cmap = cmap.parse(data, offset); font.encoding = new encoding.CmapEncoding(font.tables.cmap); if (!font.encoding) { font.supported = false; } break; case 'head': font.tables.head = head.parse(data, offset); font.unitsPerEm = font.tables.head.unitsPerEm; indexToLocFormat = font.tables.head.indexToLocFormat; break; case 'hhea': font.tables.hhea = hhea.parse(data, offset); font.ascender = font.tables.hhea.ascender; font.descender = font.tables.hhea.descender; font.numberOfHMetrics = font.tables.hhea.numberOfHMetrics; break; case 'hmtx': hmtxOffset = offset; break; case 'maxp': font.tables.maxp = maxp.parse(data, offset); font.numGlyphs = numGlyphs = font.tables.maxp.numGlyphs; break; case 'name': font.tables.name = _name.parse(data, offset); font.familyName = font.tables.name.fontFamily; font.styleName = font.tables.name.fontSubfamily; break; case 'OS/2': font.tables.os2 = os2.parse(data, offset); break; case 'post': font.tables.post = post.parse(data, offset); font.glyphNames = new encoding.GlyphNames(font.tables.post); break; case 'glyf': glyfOffset = offset; break; case 'loca': locaOffset = offset; break; case 'CFF ': cffOffset = offset; break; case 'kern': kernOffset = offset; break; case 'GPOS': gposOffset = offset; break; } p += 16; } if (glyfOffset && locaOffset) { shortVersion = indexToLocFormat === 0; locaTable = loca.parse(data, locaOffset, numGlyphs, shortVersion); font.glyphs = glyf.parse(data, glyfOffset, locaTable, font); hmtx.parse(data, hmtxOffset, font.numberOfHMetrics, font.numGlyphs, font.glyphs); encoding.addGlyphNames(font); } else if (cffOffset) { cff.parse(data, cffOffset, font); encoding.addGlyphNames(font); } else { font.supported = false; } if (font.supported) { if (kernOffset) { font.kerningPairs = kern.parse(data, kernOffset); } else { font.kerningPairs = {}; } if (gposOffset) { gpos.parse(data, gposOffset, font); } } 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. function load(url, callback) { var isNode = typeof window === 'undefined'; var loadFn = isNode ? loadFromFile : loadFromUrl; loadFn(url, function (err, arrayBuffer) { if (err) { return callback(err); } var font = parseBuffer(arrayBuffer); if (!font.supported) { return callback('Font is not supported (is this a Postscript font?)'); } return callback(null, font); }); } exports._parse = parse; exports.Font = _font.Font; exports.Glyph = glyph.Glyph; exports.Path = path.Path; exports.parse = parseBuffer; exports.load = load; },{"./encoding":3,"./font":4,"./glyph":5,"./parse":7,"./path":8,"./tables/cff":10,"./tables/cmap":11,"./tables/glyf":12,"./tables/gpos":13,"./tables/head":14,"./tables/hhea":15,"./tables/hmtx":16,"./tables/kern":17,"./tables/loca":18,"./tables/maxp":19,"./tables/name":20,"./tables/os2":21,"./tables/post":22,"fs":undefined}],7:[function(require,module,exports){ // Parsing utility functions 'use strict'; // Retrieve an unsigned byte from the DataView. exports.getByte = function getByte(dataView, offset) { return dataView.getUint8(offset); }; exports.getCard8 = exports.getByte; // Retrieve an unsigned 16-bit short from the DataView. // The value is stored in big endian. exports.getUShort = function (dataView, offset) { return dataView.getUint16(offset, false); }; exports.getCard16 = exports.getUShort; // Retrieve a signed 16-bit short from the DataView. // The value is stored in big endian. exports.getShort = function (dataView, offset) { return dataView.getInt16(offset, false); }; // Retrieve an unsigned 32-bit long from the DataView. // The value is stored in big endian. exports.getULong = function (dataView, offset) { return dataView.getUint32(offset, false); }; // Retrieve a 32-bit signed fixed-point number (16.16) from the DataView. // The value is stored in big endian. exports.getFixed = function (dataView, offset) { var decimal, fraction; decimal = dataView.getInt16(offset, false); fraction = dataView.getUint16(offset + 2, false); return decimal + fraction / 65535; }; // Retrieve a 4-character tag from the DataView. // Tags are used to identify tables. exports.getTag = function (dataView, offset) { var tag = '', i; for (i = offset; i < offset + 4; i += 1) { tag += String.fromCharCode(dataView.getInt8(i)); } return tag; }; // Retrieve an offset from the DataView. // Offsets are 1 to 4 bytes in length, depending on the offSize argument. exports.getOffset = function (dataView, offset, offSize) { var i, v; v = 0; for (i = 0; i < offSize; i += 1) { v <<= 8; v += dataView.getUint8(offset + i); } return v; }; // Retrieve a number of bytes from start offset to the end offset from the DataView. exports.getBytes = function (dataView, startOffset, endOffset) { var bytes, i; bytes = []; for (i = startOffset; i < endOffset; i += 1) { bytes.push(dataView.getUint8(i)); } return bytes; }; // Convert the list of bytes to a string. exports.bytesToString = function (bytes) { var s, i; s = ''; for (i = 0; i < bytes.length; i += 1) { s += String.fromCharCode(bytes[i]); } return s; }; var typeOffsets = { byte: 1, uShort: 2, short: 2, uLong: 4, fixed: 4, longDateTime: 8, tag: 4 }; // A stateful parser that changes the offset whenever a value is retrieved. // The data is a DataView. function Parser(data, offset) { this.data = data; this.offset = offset; this.relativeOffset = 0; } Parser.prototype.parseByte = function () { var v = this.data.getUint8(this.offset + this.relativeOffset); this.relativeOffset += 1; return v; }; Parser.prototype.parseChar = function () { var v = this.data.getInt8(this.offset + this.relativeOffset); this.relativeOffset += 1; return v; }; Parser.prototype.parseCard8 = Parser.prototype.parseByte; Parser.prototype.parseUShort = function () { var v = this.data.getUint16(this.offset + this.relativeOffset); this.relativeOffset += 2; return v; }; Parser.prototype.parseCard16 = Parser.prototype.parseUShort; Parser.prototype.parseSID = Parser.prototype.parseUShort; Parser.prototype.parseOffset16 = Parser.prototype.parseUShort; Parser.prototype.parseShort = function () { var v = this.data.getInt16(this.offset + this.relativeOffset); this.relativeOffset += 2; return v; }; Parser.prototype.parseF2Dot14 = function () { var v = this.data.getInt16(this.offset + this.relativeOffset) / 16384; this.relativeOffset += 2; return v; }; Parser.prototype.parseULong = function () { var v = exports.getULong(this.data, this.offset + this.relativeOffset); this.relativeOffset += 4; return v; }; Parser.prototype.parseFixed = function () { var v = exports.getFixed(this.data, this.offset + this.relativeOffset); this.relativeOffset += 4; return v; }; Parser.prototype.parseOffset16List = Parser.prototype.parseUShortList = function (count) { var offsets = new Array(count), dataView = this.data, 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) { var dataView = this.data, offset = this.offset + this.relativeOffset, string = ''; this.relativeOffset += length; for (var i = 0; i < length; i++) { string += String.fromCharCode(dataView.getUint8(offset + i)); } return string; }; Parser.prototype.parseTag = function () { return this.parseString(4); }; // LONGDATETIME is a 64-bit integer. // JavaScript and unix timestamps traditionally use 32 bits, so we // only take the last 32 bits. Parser.prototype.parseLongDateTime = function() { var v = exports.getULong(this.data, this.offset + this.relativeOffset + 4); this.relativeOffset += 8; return v; }; 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); // 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); this.relativeOffset += 4; return major + minor / 0x1000 / 10; }; Parser.prototype.skip = function (type, amount) { if (amount === undefined) { amount = 1; } this.relativeOffset += typeOffsets[type] * amount; }; exports.Parser = Parser; },{}],8:[function(require,module,exports){ // Geometric objects 'use strict'; // A bézier path containing a set of path commands similar to a SVG path. // Paths can be drawn on a context using `draw`. function Path() { this.commands = []; this.fill = 'black'; this.stroke = null; this.strokeWidth = 1; } Path.prototype.moveTo = function (x, y) { this.commands.push({ type: 'M', x: x, y: y }); }; Path.prototype.lineTo = function (x, y) { this.commands.push({ type: 'L', x: x, y: y }); }; Path.prototype.curveTo = Path.prototype.bezierCurveTo = function (x1, y1, x2, y2, x, y) { this.commands.push({ type: 'C', x1: x1, y1: y1, x2: x2, y2: y2, x: x, y: y }); }; Path.prototype.quadTo = Path.prototype.quadraticCurveTo = function (x1, y1, x, y) { this.commands.push({ type: 'Q', x1: x1, y1: y1, x: x, y: y }); }; Path.prototype.close = Path.prototype.closePath = function () { this.commands.push({ type: 'Z' }); }; // Add the given path or list of commands to the commands of this path. Path.prototype.extend = function (pathOrCommands) { if (pathOrCommands.commands) { pathOrCommands = pathOrCommands.commands; } Array.prototype.push.apply(this.commands, pathOrCommands); }; // Draw the path to a 2D context. Path.prototype.draw = function (ctx) { var i, cmd; ctx.beginPath(); for (i = 0; i < this.commands.length; i += 1) { cmd =