From 688d7f28f85fa609db8a47a5984f5d4ac4d41217 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Mon, 4 Jul 2011 03:42:48 +0200 Subject: [PATCH 01/20] Fix a few warnings --- fonts.js | 181 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 96 insertions(+), 85 deletions(-) diff --git a/fonts.js b/fonts.js index 12d7ce82e..23c7699dd 100644 --- a/fonts.js +++ b/fonts.js @@ -67,7 +67,7 @@ var Fonts = (function Fonts() { markLoaded(fontName); }, lookup: function fonts_lookup(fontName) { - return fonts[fontName]; + return (fontName in fonts) ? fonts[fontName] : null; }, setActive: function fonts_setActive(fontName, size) { current = fonts[fontName]; @@ -126,7 +126,7 @@ var Fonts = (function Fonts() { var FontLoader = { listeningForFontLoad: false, - bind: function(fonts, callback) { + bind: function font_bind(fonts, callback) { function checkFontsLoaded() { for (var i = 0; i < fonts.length; i++) { var font = fonts[i]; @@ -178,7 +178,7 @@ var FontLoader = { // loaded in a subdocument. It's expected that the load of |rules| // has already started in this (outer) document, so that they should // be ordered before the load in the subdocument. - prepareFontLoadEvent: function(rules, names) { + prepareFontLoadEvent: function prepareFontLoadEvent(rules, names) { /** Hack begin */ // There's no event when a font has finished downloading so the // following code is a dirty hack to 'guess' when a font is @@ -412,7 +412,7 @@ function getUnicodeRangeFor(value) { * var type1Font = new Font("MyFontName", binaryFile, propertiesObject); * type1Font.bind(); */ -var Font = (function () { +var Font = (function Font() { var constructor = function font_constructor(name, file, properties) { this.name = name; this.encoding = properties.encoding; @@ -543,7 +543,11 @@ var Font = (function () { for (var i = 0; i < length; i+=4) checksum += int16([data[i], data[i+1], data[i+2], data[i+3]]); - var tableEntry = tag + string32(checksum) + string32(offset) + string32(length); + var tableEntry = tag + + string32(checksum) + + string32(offset) + + string32(length); + tableEntry = stringToArray(tableEntry); file.set(tableEntry, offsets.currentOffset); @@ -783,7 +787,7 @@ var Font = (function () { (format == 6 && numTables == 1 && !properties.encoding.empty)) { // Format 0 alone is not allowed by the sanitizer so let's rewrite // that to a 3-1-4 Unicode BMP table - TODO("Use an other source of informations than charset here, it is not reliable"); + TODO("Charset is not reliable, use somethin else"); var charset = properties.charset; var glyphs = []; for (var j = 0; j < charset.length; j++) { @@ -823,8 +827,9 @@ var Font = (function () { for (var j = 0; j < glyphs.length; j++) glyphs[j] = { unicode: glyphs[j] + firstCode }; - var ranges= getRanges(glyphs); - assert(ranges.length == 1, "Got " + ranges.length + " ranges in a dense array"); + var ranges = getRanges(glyphs); + assert(ranges.length == 1, + "Got " + ranges.length + " ranges in a dense array"); var encoding = properties.encoding; var denseRange = ranges[0]; @@ -1041,7 +1046,7 @@ var Font = (function () { "cmap": createCMapTable(charstrings.slice()), // Font header - "head": (function() { + "head": (function convert_fields_head() { return stringToArray( "\x00\x01\x00\x00" + // Version number "\x00\x00\x10\x00" + // fontRevision @@ -1063,7 +1068,7 @@ var Font = (function () { })(), // Horizontal header - "hhea": (function() { + "hhea": (function convert_fields_hhea() { return stringToArray( "\x00\x01\x00\x00" + // Version number string16(properties.ascent) + // Typographic Ascent @@ -1085,7 +1090,7 @@ var Font = (function () { })(), // Horizontal metrics - "hmtx": (function() { + "hmtx": (function convert_fields_hmtx() { var hmtx = "\x00\x00\x00\x00"; // Fake .notdef for (var i = 0; i < charstrings.length; i++) { hmtx += string16(charstrings[i].width) + string16(0); @@ -1094,7 +1099,7 @@ var Font = (function () { })(), // Maximum profile - "maxp": (function() { + "maxp": (function convert_fields_maxp() { return stringToArray( "\x00\x00\x50\x00" + // Version number string16(charstrings.length + 1)); // Num of glyphs @@ -1134,14 +1139,11 @@ var Font = (function () { }, bindDOM: function font_bindDom(data) { - var fontName = this.name; - - // Add the @font-face rule to the document var url = "url(data:" + this.mimetype + ";base64," + window.btoa(data) + ");"; - var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}"; + var rule = "@font-face { font-family:'" + this.name + "';src:" + url + "}"; + var styleSheet = document.styleSheets[0]; styleSheet.insertRule(rule, styleSheet.cssRules.length); - return rule; } }; @@ -1154,7 +1156,7 @@ var Font = (function () { * program. * Some of its logic depends on the Type2 charstrings structure. */ -var Type1Parser = function() { +var Type1Parser = function Type1Parser() { /* * Decrypt a Sequence of Ciphertext Bytes to Produce the Original Sequence * of Plaintext Bytes. The function took a key as a parameter which can be @@ -1344,7 +1346,9 @@ var Type1Parser = function() { } else if (!command) { break; } else if (command == -1) { - error("Support for Type1 command " + value + " (" + escape + ") is not implemented in charstring: " + charString); + error("Support for Type1 command " + + value + " (" + escape + ")" + + " is not implemented in charstring: " + charString); } value = command; @@ -1369,7 +1373,7 @@ var Type1Parser = function() { * Returns an object containing a Subrs array and a CharStrings array * extracted from and eexec encrypted block of data */ - function readNumberArray(str, index) { + function readNumbers(str, index) { var start = ++index; var count = 0; while (str[index++] != "]") @@ -1436,16 +1440,16 @@ var Type1Parser = function() { subrsSection = true; break; case "/StdHW": - extracted.properties.stdHW = readNumberArray(eexecString, i + 2)[0]; + extracted.properties.stdHW = readNumbers(eexecString, i + 2)[0]; break; case "/StdVW": - extracted.properties.stdVW = readNumberArray(eexecString, i + 2)[0]; + extracted.properties.stdVW = readNumbers(eexecString, i + 2)[0]; break; case "/StemSnapH": - extracted.properties.stemSnapH = readNumberArray(eexecString, i + 2); + extracted.properties.stemSnapH = readNumbers(eexecString, i + 2); break; case "/StemSnapV": - extracted.properties.stemSnapV = readNumberArray(eexecString, i + 2); + extracted.properties.stemSnapV = readNumbers(eexecString, i + 2); break; } } else if (c == "/") { @@ -1475,7 +1479,7 @@ var Type1Parser = function() { if (c == " " || c == "\n") { switch (token) { case "/FontMatrix": - var matrix = readNumberArray(headerString, i + 1); + var matrix = readNumbers(headerString, i + 1); // The FontMatrix is in unitPerEm, so make it pixels for (var j = 0; j < matrix.length; j++) @@ -1502,66 +1506,70 @@ var Type1Parser = function() { * which itself embed Type2 charstrings. */ var CFFStrings = [ - ".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", + ".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", + "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", + "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","206 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 type1Parser = new Type1Parser(); -var CFF = function(name, file, properties) { +var CFF = function CFF(name, file, properties) { // Get the data block containing glyphs and subrs informations var length1 = file.dict.get("Length1"); var length2 = file.dict.get("Length2"); @@ -1582,7 +1590,8 @@ var CFF = function(name, file, properties) { var subrs = this.getType2Subrs(data.subrs); this.charstrings = charstrings; - this.data = this.wrap(name, type2Charstrings, this.charstrings, subrs, properties); + this.data = this.wrap(name, type2Charstrings, + this.charstrings, subrs, properties); }; CFF.prototype = { @@ -1643,7 +1652,7 @@ CFF.prototype = { var unicode = GlyphsUnicode[glyph.glyph]; if (!unicode) { if (glyph.glyph != ".notdef") - warn(glyph + " does not have an entry in the glyphs unicode dictionary"); + warn(glyph + " has no entry in the glyphs unicode dictionary"); } else { charstrings.push({ glyph: glyph, @@ -1666,7 +1675,8 @@ CFF.prototype = { var count = type1Charstrings.length; for (var i = 0; i < count; i++) { var charstring = type1Charstrings[i].charstring; - type2Charstrings.push(this.flattenCharstring(charstring.slice(), this.commandsMap)); + var flate = this.flattenCharstring(charstring.slice(), this.commandsMap); + type2Charstrings.push(flate); } return type2Charstrings; }, @@ -1738,12 +1748,13 @@ CFF.prototype = { wrap: function wrap(name, glyphs, charstrings, subrs, properties) { var fields = { - "header": "\x01\x00\x04\x04", // major version, minor version, header size, offset size + // major version, minor version, header size, offset size + "header": "\x01\x00\x04\x04", "names": this.createCFFIndexHeader([name]), "topDict": (function topDict(self) { - return function() { + return function wrap_inner_topDict() { var dict = "\x00\x01\x01\x01\x30" + "\xf8\x1b\x00" + // version @@ -1795,9 +1806,9 @@ CFF.prototype = { var count = glyphs.length; for (var i = 0; i < count; i++) { var index = CFFStrings.indexOf(charstrings[i].glyph.glyph); - // Some characters like asterikmath && circlecopyrt are missing from the - // original strings, for the moment let's map them to .notdef and see - // later if it cause any problems + // Some characters like asterikmath && circlecopyrt are missing from + // the original strings, for the moment let's map them to .notdef and + // see later if it cause any problems if (index == -1) index = 0; @@ -1808,7 +1819,7 @@ CFF.prototype = { "charstrings": this.createCFFIndexHeader([[0x8B, 0x0E]].concat(glyphs), true), - "private": (function(self) { + "private": (function wrap_private(self) { var data = "\x8b\x14" + // defaultWidth "\x8b\x15" + // nominalWidth From 17803049a9636608e88a78d3a04f36930a3fd849 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Mon, 4 Jul 2011 03:57:25 +0200 Subject: [PATCH 02/20] Make 'cmap' declare the correct header size --- fonts.js | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/fonts.js b/fonts.js index 23c7699dd..8bee706b2 100644 --- a/fonts.js +++ b/fonts.js @@ -573,7 +573,7 @@ var Font = (function Font() { ++end; ++n; } - ranges.push([start, end]); + ranges.push({ start: start, end: end }); } return ranges; }; @@ -589,11 +589,11 @@ var Font = (function Font() { "\x00\x01" + // encodingID string32(4 + numTables * 8); // start of the table record - var headerSize = (12 * 2 + (ranges.length * 5 * 2)); + var headerSize = ((7 * 2) + (ranges.length * 4 * 2) + (4 * 2) + (glyphs.length * 2)); var segCount = ranges.length + 1; - var segCount2 = segCount * 2; - var searchRange = getMaxPower2(segCount) * 2; - var searchEntry = Math.log(segCount) / Math.log(2); + var segCount2 = 2 * segCount; + var searchRange = 2 * getMaxPower2(segCount); + var entrySelector = Math.log(segCount) / Math.log(2); var rangeShift = 2 * segCount - searchRange; var format314 = "\x00\x04" + // format @@ -601,7 +601,7 @@ var Font = (function Font() { "\x00\x00" + // language string16(segCount2) + string16(searchRange) + - string16(searchEntry) + + string16(entrySelector) + string16(rangeShift); // Fill up the 4 parallel arrays describing the segments. @@ -613,8 +613,8 @@ var Font = (function Font() { var bias = 0; for (var i = 0; i < segCount - 1; i++) { var range = ranges[i]; - var start = range[0]; - var end = range[1]; + var start = range.start; + var end = range.end; var delta = (bias - start) % 0xffff; bias += (end - start + 1); @@ -622,16 +622,15 @@ var Font = (function Font() { endCount += string16(end); idDeltas += string16(delta); idRangeOffsets += string16(0); - - for (var j = start; j <= end; j++) { - glyphsIds += string16(j); - } } - endCount += "\xFF\xFF"; startCount += "\xFF\xFF"; idDeltas += "\x00\x01"; idRangeOffsets += "\x00\x00"; + + for (var i = 0; i < glyphs.length; i++) + glyphsIds += string16(i); + format314 += endCount + "\x00\x00" + startCount + idDeltas + idRangeOffsets + glyphsIds; @@ -833,11 +832,12 @@ var Font = (function Font() { var encoding = properties.encoding; var denseRange = ranges[0]; - var start = denseRange[0]; - var end = denseRange[1]; + var start = denseRange.start; + var end = denseRange.end; var index = firstCode; for (var j = start; j <= end; j++) encoding[index++] = glyphs[j - firstCode - 1].unicode; + cmap.data = createCMapTable(glyphs); } } From 1037fdf2ada515ee46c6f63fe4e9d8f7a4df0a28 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Mon, 4 Jul 2011 04:39:58 +0200 Subject: [PATCH 03/20] Fix a small issue with the 'name' table --- fonts.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fonts.js b/fonts.js index 8bee706b2..dceda2cdd 100644 --- a/fonts.js +++ b/fonts.js @@ -988,7 +988,7 @@ var Font = (function Font() { var nameTable = "\x00\x00" + // format string16(namesRecordCount) + // Number of names Record - string16(namesRecordCount * 12 + 6); // Storage + string16(namesRecordCount * 12 + 6); // Offset to start of storage // Build the name records field var strOffset = 0; @@ -1000,7 +1000,7 @@ var Font = (function Font() { platforms[i] + // platform ID encodings[i] + // encoding ID languages[i] + // language ID - string16(i) + // name ID + string16(j) + // name ID string16(str.length) + string16(strOffset); nameTable += nameRecord; @@ -1008,9 +1008,9 @@ var Font = (function Font() { } } - nameTable += strings.join("") + stringsUnicode.join(""); + nameTable += strings.join("") + stringsUnicode.join(""); return nameTable; - } + }; function isFixedPitch(glyphs) { for (var i = 0; i < glyphs.length - 1; i++) { From 9b1d6a5e25571188a34b14d2d9a0b96c92051a2b Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Mon, 4 Jul 2011 06:07:49 +0200 Subject: [PATCH 04/20] Calculate the checksumAdjustement for the file --- fonts.js | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/fonts.js b/fonts.js index dceda2cdd..1964121c4 100644 --- a/fonts.js +++ b/fonts.js @@ -1024,14 +1024,14 @@ var Font = (function Font() { // to write the table entry information about a table and another offset // representing the offset where to draw the actual data of a particular // table - var kRequiredTablesCount = 9; + var tablesCount = 9; var offsets = { currentOffset: 0, - virtualOffset: 9 * (4 * 4) + virtualOffset: tablesCount * (4 * 4) }; var otf = new Uint8Array(kMaxFontFileSize); - createOpenTypeHeader("\x4F\x54\x54\x4F", otf, offsets, 9); + createOpenTypeHeader("\x4F\x54\x54\x4F", otf, offsets, tablesCount); var charstrings = font.charstrings; properties.fixedPitch = isFixedPitch(charstrings); @@ -1115,12 +1115,26 @@ var Font = (function Font() { for (var field in fields) createTableEntry(otf, offsets, field, fields[field]); + var headPosition = 0; for (var field in fields) { var table = fields[field]; + if (field == "head") + headPosition = offsets.currentOffset; + otf.set(table, offsets.currentOffset); offsets.currentOffset += table.length; } + // Now calculate the checksumAdjustement for all the file and put it into + // head. This will make the head checksum incorrect but per spec that's + // the way it works. + var checksumAdjustement = 0; + for (var i = 0; i < offsets.currentOffset; i+=4) + checksumAdjustement += int16([otf[i], otf[i+1], otf[i+2], otf[i+3]]); + checksumAdjustement = 0xB1B0AFBA - checksumAdjustement; + otf.set(stringToArray(string32(checksumAdjustement)), headPosition + (2 * 4)); + + var fontData = []; for (var i = 0; i < offsets.currentOffset; i++) fontData.push(otf[i]); From 8738b72f30f157392bcaf5c947f887fa22a8d6f8 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Mon, 4 Jul 2011 10:24:31 +0200 Subject: [PATCH 05/20] Use int32 instead of int16 for checksums --- fonts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fonts.js b/fonts.js index 1964121c4..e61a8f666 100644 --- a/fonts.js +++ b/fonts.js @@ -541,7 +541,7 @@ var Font = (function Font() { // checksum var checksum = 0; for (var i = 0; i < length; i+=4) - checksum += int16([data[i], data[i+1], data[i+2], data[i+3]]); + checksum += int32([data[i], data[i+1], data[i+2], data[i+3]]); var tableEntry = tag + string32(checksum) + From 2271f7df7fd31c2f15bfbcc4e24ff1a724995a44 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Wed, 6 Jul 2011 02:51:17 +0200 Subject: [PATCH 06/20] Fix some indentations issues --- fonts.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/fonts.js b/fonts.js index e61a8f666..5abc13fd3 100644 --- a/fonts.js +++ b/fonts.js @@ -643,17 +643,16 @@ var Font = (function Font() { var ulUnicodeRange3 = 0; var ulUnicodeRange4 = 0; - var charset = properties.charset; + var charset = properties.charset; if (charset && charset.length) { - var firstCharIndex = null; - var lastCharIndex = 0; + var firstCharIndex = null; + var lastCharIndex = 0; - for (var i = 1; i < charset.length; i++) { - var code = GlyphsUnicode[charset[i]]; - if (firstCharIndex > code || !firstCharIndex) + for (var i = 1; i < charset.length; i++) {var code = GlyphsUnicode[charset[i]]; + if (firstCharIndex > code || !firstCharIndex) firstCharIndex = code; - if (lastCharIndex < code) - lastCharIndex = code; + if (lastCharIndex < code) + lastCharIndex = code; var position = getUnicodeRangeFor(code); if (position < 32) { From 10e96941350a83fccf31e49a6fe5a6cd814bded2 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 15 Jul 2011 14:58:14 +0200 Subject: [PATCH 07/20] Support font with characters below 0x20 declared in format 1 cmap and be more general about the TrueType rewritting cases --- fonts.js | 295 +++++++++++++++++++++++++++--------------------- web/viewer.html | 1 + 2 files changed, 165 insertions(+), 131 deletions(-) diff --git a/fonts.js b/fonts.js index 607e2aab9..b3961c8fc 100755 --- a/fonts.js +++ b/fonts.js @@ -372,7 +372,7 @@ function getUnicodeRangeFor(value) { * var type1Font = new Font("MyFontName", binaryFile, propertiesObject); * type1Font.bind(); */ -var Font = (function() { +var Font = (function Font() { var constructor = function font_constructor(name, file, properties) { this.name = name; this.textMatrix = properties.textMatrix || IDENTITY_MATRIX; @@ -531,6 +531,19 @@ var Font = (function() { } ranges.push([start, end]); } + + // Removes duplicate ranges + for (var i = ranges.length - 1; i > 0; i--) { + var range = []; + var range1 = ranges[i]; + var range2 = ranges[i - 1]; + if (range1[0] == range2[1]) { + range2[0] = range2[0] - 1; + range2[1] = range1[1]; + ranges.splice(i, 1); + } + } + return ranges; }; @@ -790,21 +803,57 @@ var Font = (function() { }; function replaceCMapTable(cmap, font, properties) { - font.pos = (font.start ? font.start : 0) + cmap.length; + var start = (font.start ? font.start : 0) + cmap.length; + font.pos = start; var version = int16(font.getBytes(2)); - var numTables = int16(font.getBytes(2)); + var numRecords = int16(font.getBytes(2)); - for (var i = 0; i < numTables; i++) { - var platformID = int16(font.getBytes(2)); - var encodingID = int16(font.getBytes(2)); - var offset = int32(font.getBytes(4)); + var records = []; + for (var i = 0; i < numRecords; i++) { + records.push({ + platformID: int16(font.getBytes(2)), + encodingID: int16(font.getBytes(2)), + offset: int32(font.getBytes(4)) + }); + }; + + + for (var i = 0; i < numRecords; i++) { + var table = records[i]; + font.pos = start + table.offset; + var format = int16(font.getBytes(2)); var length = int16(font.getBytes(2)); var language = int16(font.getBytes(2)); - - if ((format == 0 && numTables == 1) || - (format == 6 && numTables == 1 && !properties.encoding.empty)) { + + if (format == 0 && numRecords > 1) { + // Characters below 0x20 are controls characters that are hardcoded + // into the platform so if some characters in the font are assigned + // under this limit they will not be displayed so let's rewrite the + // CMap. + var map = []; + var rewrite = false; + for (var j = 0; j < 256; j++) { + var index = font.getByte(); + if (index != 0) { + map.push(index); + if (j < 0x20) + rewrite = true; + } + } + + if (rewrite) { + var glyphs = []; + for (var j = 0x20; j < 256; j++) { + // TODO do not hardcode WinAnsiEncoding + var unicode = GlyphsUnicode[Encodings["WinAnsiEncoding"][j]]; + glyphs.push({ unicode: unicode }); + } + cmap.data = createCMapTable(glyphs, true); + } + } else if ((format == 0 && numRecords == 1) || + (format == 6 && numRecords == 1 && !properties.encoding.empty)) { // Format 0 alone is not allowed by the sanitizer so let's rewrite // that to a 3-1-4 Unicode BMP table TODO('Use an other source of informations than ' + @@ -818,7 +867,7 @@ var Font = (function() { } cmap.data = createCMapTable(glyphs); - } else if (format == 6 && numTables == 1) { + } else if (format == 6 && numRecords == 1) { // Format 6 is a 2-bytes dense mapping, which means the font data // lives glue together even if they are pretty far in the unicode // table. (This looks weird, so I can have missed something), this @@ -871,10 +920,7 @@ var Font = (function() { var header = readOpenTypeHeader(font); var numTables = header.numTables; - // This keep a reference to the CMap and the post tables since they can - // be rewritted - var cmap, post, nameTable, maxp; - + var cmap, maxp; var tables = []; for (var i = 0; i < numTables; i++) { var table = readTableEntry(font); @@ -882,10 +928,6 @@ var Font = (function() { if (index != -1) { if (table.tag == 'cmap') cmap = table; - else if (table.tag == 'post') - post = table; - else if (table.tag == 'name') - nameTable = table; else if (table.tag == 'maxp') maxp = table; @@ -894,136 +936,127 @@ var Font = (function() { tables.push(table); } - // If any tables are still in the array this means some required - // tables are missing, which means that we need to rebuild the - // font in order to pass the sanitizer. - if (requiredTables.length && requiredTables[0] == 'OS/2') { - // Create a new file to hold the new version of our truetype with a new - // header and new offsets - var ttf = new Uint8Array(kMaxFontFileSize); + // Create a new file to hold the new version of our truetype with a new + // header and new offsets + var ttf = new Uint8Array(kMaxFontFileSize); - // The offsets object holds at the same time a representation of where - // to write the table entry information about a table and another offset - // representing the offset where to put the actual data of a particular - // table - var numTables = header.numTables + requiredTables.length; - var offsets = { - currentOffset: 0, - virtualOffset: numTables * (4 * 4) - }; + // The offsets object holds at the same time a representation of where + // to write the table entry information about a table and another offset + // representing the offset where to put the actual data of a particular + // table + var numTables = header.numTables + requiredTables.length; + var offsets = { + currentOffset: 0, + virtualOffset: numTables * (4 * 4) + }; - // The new numbers of tables will be the last one plus the num - // of missing tables - createOpenTypeHeader('\x00\x01\x00\x00', ttf, offsets, numTables); + // The new numbers of tables will be the last one plus the num + // of missing tables + createOpenTypeHeader('\x00\x01\x00\x00', ttf, offsets, numTables); - // Insert the missing table + if (requiredTables.indexOf('OS/2') != -1) { tables.push({ tag: 'OS/2', data: stringToArray(createOS2Table(properties)) }); + } - // Replace the old CMAP table with a shiny new one - if (properties.type == 'CIDFontType2') { - // Type2 composite fonts map characters directly to glyphs so the cmap - // table must be replaced. + // Replace the old CMAP table with a shiny new one + if (properties.type == 'CIDFontType2') { + // Type2 composite fonts map characters directly to glyphs so the cmap + // table must be replaced. - var glyphs = []; - var charset = properties.charset; - if (!charset.length) { - // PDF did not contain a GIDMap for the font so create an identity cmap + var glyphs = []; + var charset = properties.charset; + if (!charset.length) { + // PDF did not contain a GIDMap for the font so create an identity cmap - // First get the number of glyphs from the maxp table - font.pos = (font.start ? font.start : 0) + maxp.length; - var version = int16(font.getBytes(4)); - var numGlyphs = int16(font.getBytes(2)); + // First get the number of glyphs from the maxp table + font.pos = (font.start ? font.start : 0) + maxp.length; + var version = int16(font.getBytes(4)); + var numGlyphs = int16(font.getBytes(2)); - // Now create an identity mapping - for (var i = 1; i < numGlyphs; i++) { - glyphs.push({ - unicode: i - }); - } - } else { - for (var i = 1; i < charset.length; i++) { - var index = charset.indexOf(i); - if (index != -1) { - glyphs.push({ - unicode: index - }); - } else { - break; - } - } - } - - if (!cmap) { - // Font did not contain a cmap - tables.push({ - tag: 'cmap', - data: createCMapTable(glyphs) - }) - } else { - cmap.data = createCMapTable(glyphs); + // Now create an identity mapping + for (var i = 1; i < numGlyphs; i++) { + glyphs.push({ + unicode: i + }); } } else { - replaceCMapTable(cmap, font, properties); + for (var i = 1; i < charset.length; i++) { + var index = charset.indexOf(i); + if (index != -1) { + glyphs.push({ + unicode: index + }); + } else { + break; + } + } } - - // Rewrite the 'post' table if needed - if (!post) { + + if (!cmap) { + // Font did not contain a cmap tables.push({ - tag: 'post', - data: stringToArray(createPostTable(properties)) - }); + tag: 'cmap', + data: createCMapTable(glyphs) + }) + } else { + cmap.data = createCMapTable(glyphs); } - - // Rewrite the 'name' table if needed - if (!nameTable) { - tables.push({ - tag: 'name', - data: stringToArray(createNameTable(this.name)) - }); - } - - // Tables needs to be written by ascendant alphabetic order - tables.sort(function tables_sort(a, b) { - return (a.tag > b.tag) - (a.tag < b.tag); - }); - - // rewrite the tables but tweak offsets - for (var i = 0; i < tables.length; i++) { - var table = tables[i]; - var data = []; - - var tableData = table.data; - for (var j = 0; j < tableData.length; j++) - data.push(tableData[j]); - createTableEntry(ttf, offsets, table.tag, data); - } - - // Add the table datas - for (var i = 0; i < tables.length; i++) { - var table = tables[i]; - var tableData = table.data; - ttf.set(tableData, offsets.currentOffset); - offsets.currentOffset += tableData.length; - - // 4-byte aligned data - while (offsets.currentOffset & 3) - offsets.currentOffset++; - } - - var fontData = []; - for (var i = 0; i < offsets.currentOffset; i++) - fontData.push(ttf[i]); - - return fontData; - } else if (requiredTables.length) { - error('Table ' + requiredTables[0] + - ' is missing from the TrueType font'); + } else { + replaceCMapTable(cmap, font, properties); } - return font.getBytes(); + // Rewrite the 'post' table if needed + if (requiredTables.indexOf('post') != -1) { + tables.push({ + tag: 'post', + data: stringToArray(createPostTable(properties)) + }); + } + + // Rewrite the 'name' table if needed + if (requiredTables.indexOf('name') != -1) { + tables.push({ + tag: 'name', + data: stringToArray(createNameTable(this.name)) + }); + } + + // Tables needs to be written by ascendant alphabetic order + tables.sort(function tables_sort(a, b) { + return (a.tag > b.tag) - (a.tag < b.tag); + }); + + // rewrite the tables but tweak offsets + for (var i = 0; i < tables.length; i++) { + var table = tables[i]; + var data = []; + + var tableData = table.data; + for (var j = 0; j < tableData.length; j++) + data.push(tableData[j]); + createTableEntry(ttf, offsets, table.tag, data); + } + + // Add the table datas + for (var i = 0; i < tables.length; i++) { + var table = tables[i]; + var tableData = table.data; + ttf.set(tableData, offsets.currentOffset); + offsets.currentOffset += tableData.length; + + // 4-byte aligned data + while (offsets.currentOffset & 3) + offsets.currentOffset++; + } + + var fontData = []; + for (var i = 0; i < offsets.currentOffset; i++) + fontData.push(ttf[i]); + + return fontData; }, convert: function font_convert(fontName, font, properties) { diff --git a/web/viewer.html b/web/viewer.html index df9604db4..8caa40f3e 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -8,6 +8,7 @@ + From b8fc365fffac342f99a155d6082630a0cfdcb1a8 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 15 Jul 2011 15:41:30 +0200 Subject: [PATCH 08/20] Fix the ranges duplication cleanup features --- fonts.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/fonts.js b/fonts.js index b3961c8fc..4eb9406ed 100755 --- a/fonts.js +++ b/fonts.js @@ -534,13 +534,11 @@ var Font = (function Font() { // Removes duplicate ranges for (var i = ranges.length - 1; i > 0; i--) { - var range = []; - var range1 = ranges[i]; - var range2 = ranges[i - 1]; - if (range1[0] == range2[1]) { - range2[0] = range2[0] - 1; - range2[1] = range1[1]; - ranges.splice(i, 1); + var range = ranges[i]; + var prevRange = ranges[i - 1]; + if (range[0] <= prevRange[1]) { + range[0] = prevRange[0] - 2; + ranges.splice(i - 1, 1); } } @@ -850,7 +848,7 @@ var Font = (function Font() { var unicode = GlyphsUnicode[Encodings["WinAnsiEncoding"][j]]; glyphs.push({ unicode: unicode }); } - cmap.data = createCMapTable(glyphs, true); + cmap.data = createCMapTable(glyphs); } } else if ((format == 0 && numRecords == 1) || (format == 6 && numRecords == 1 && !properties.encoding.empty)) { From e2d808a60f88c69b20ea9c8e8fba38d62922ed15 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 15 Jul 2011 16:02:32 +0200 Subject: [PATCH 09/20] Switch length versus offset mistake in readTableEntry --- fonts.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fonts.js b/fonts.js index 4eb9406ed..eb3b25d50 100755 --- a/fonts.js +++ b/fonts.js @@ -784,8 +784,8 @@ var Font = (function Font() { return { tag: tag, checksum: checksum, - length: offset, - offset: length, + length: length, + offset: offset, data: data }; }; @@ -801,7 +801,7 @@ var Font = (function Font() { }; function replaceCMapTable(cmap, font, properties) { - var start = (font.start ? font.start : 0) + cmap.length; + var start = (font.start ? font.start : 0) + cmap.offset; font.pos = start; var version = int16(font.getBytes(2)); @@ -970,7 +970,7 @@ var Font = (function Font() { // PDF did not contain a GIDMap for the font so create an identity cmap // First get the number of glyphs from the maxp table - font.pos = (font.start ? font.start : 0) + maxp.length; + font.pos = (font.start ? font.start : 0) + maxp.offset; var version = int16(font.getBytes(4)); var numGlyphs = int16(font.getBytes(2)); From aea63a70519113811a92b1d72d31692fb924928f Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 15 Jul 2011 16:22:45 +0200 Subject: [PATCH 10/20] Fix missing sidebearings from the hmtx table (see canvas.pdf) --- fonts.js | 77 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 30 deletions(-) diff --git a/fonts.js b/fonts.js index eb3b25d50..ac8da119d 100755 --- a/fonts.js +++ b/fonts.js @@ -816,7 +816,6 @@ var Font = (function Font() { }); }; - for (var i = 0; i < numRecords; i++) { var table = records[i]; font.pos = start + table.offset; @@ -824,7 +823,7 @@ var Font = (function Font() { var format = int16(font.getBytes(2)); var length = int16(font.getBytes(2)); var language = int16(font.getBytes(2)); - + if (format == 0 && numRecords > 1) { // Characters below 0x20 are controls characters that are hardcoded // into the platform so if some characters in the font are assigned @@ -840,7 +839,7 @@ var Font = (function Font() { rewrite = true; } } - + if (rewrite) { var glyphs = []; for (var j = 0x20; j < 256; j++) { @@ -918,7 +917,7 @@ var Font = (function Font() { var header = readOpenTypeHeader(font); var numTables = header.numTables; - var cmap, maxp; + var cmap, maxp, hhea, hmtx; var tables = []; for (var i = 0; i < numTables; i++) { var table = readTableEntry(font); @@ -928,6 +927,10 @@ var Font = (function Font() { cmap = table; else if (table.tag == 'maxp') maxp = table; + else if (table.tag == 'hhea') + hhea = table; + else if (table.tag == 'hmtx') + hmtx = table; requiredTables.splice(index, 1); } @@ -944,7 +947,7 @@ var Font = (function Font() { // table var numTables = header.numTables + requiredTables.length; var offsets = { - currentOffset: 0, + currentOffset: 0, virtualOffset: numTables * (4 * 4) }; @@ -952,29 +955,45 @@ var Font = (function Font() { // of missing tables createOpenTypeHeader('\x00\x01\x00\x00', ttf, offsets, numTables); - if (requiredTables.indexOf('OS/2') != -1) { + if (requiredTables.indexOf('OS/2') != -1) { tables.push({ tag: 'OS/2', data: stringToArray(createOS2Table(properties)) }); - } + } + + // Ensure the hmtx tables contains an advance width and a sidebearing + // for the number of glyphs declared in the maxp table + font.pos = (font.start ? font.start : 0) + maxp.offset; + var version = int16(font.getBytes(4)); + var numGlyphs = int16(font.getBytes(2)); + + font.pos = (font.start ? font.start : 0) + hhea.offset; + font.pos += hhea.length - 2; + var numOfHMetrics = int16(font.getBytes(2)); + + var numOfSidebearings = numGlyphs - numOfHMetrics; + var numMissing = numOfSidebearings - (hmtx.length - numOfHMetrics * 4); + if (numMissing > 0) { + font.pos = (font.start ? font.start : 0) + hmtx.offset; + var metrics = ""; + for (var i = 0; i < hmtx.length; i++) + metrics += String.fromCharCode(font.getByte()); + for (var i = 0; i < numMissing; i++) + metrics += "\x00\x00"; + hmtx.data = stringToArray(metrics); + } + // Replace the old CMAP table with a shiny new one if (properties.type == 'CIDFontType2') { - // Type2 composite fonts map characters directly to glyphs so the cmap + // Type2 composite fonts map characters directly to glyphs so the cmap // table must be replaced. var glyphs = []; var charset = properties.charset; if (!charset.length) { - // PDF did not contain a GIDMap for the font so create an identity cmap - - // First get the number of glyphs from the maxp table - font.pos = (font.start ? font.start : 0) + maxp.offset; - var version = int16(font.getBytes(4)); - var numGlyphs = int16(font.getBytes(2)); - - // Now create an identity mapping + // Type2 composite fonts map characters directly to glyphs so the cmap for (var i = 1; i < numGlyphs; i++) { glyphs.push({ unicode: i @@ -983,27 +1002,25 @@ var Font = (function Font() { } else { for (var i = 1; i < charset.length; i++) { var index = charset.indexOf(i); - if (index != -1) { - glyphs.push({ - unicode: index - }); - } else { + if (index == -1) break; - } + + glyphs.push({ + unicode: index + }); } } - + if (!cmap) { - // Font did not contain a cmap - tables.push({ + cmap = { tag: 'cmap', - data: createCMapTable(glyphs) - }) - } else { - cmap.data = createCMapTable(glyphs); + data: null + }; + tables.push(cmap); } + cmap.data = createCMapTable(glyphs); } else { - replaceCMapTable(cmap, font, properties); + replaceCMapTable(cmap, font, properties); } // Rewrite the 'post' table if needed From 42653edf9a47e281ddbf210d2723e69884a79807 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 15 Jul 2011 19:14:07 +0200 Subject: [PATCH 11/20] Add support for beginfbchar --- fonts.js | 38 +++++++++++++++++++++----------------- pdf.js | 14 ++++++++------ 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/fonts.js b/fonts.js index ac8da119d..a54168a1e 100755 --- a/fonts.js +++ b/fonts.js @@ -816,6 +816,8 @@ var Font = (function Font() { }); }; + var encoding = properties.encoding; + var charset = properties.charset; for (var i = 0; i < numRecords; i++) { var table = records[i]; font.pos = start + table.offset; @@ -824,38 +826,41 @@ var Font = (function Font() { var length = int16(font.getBytes(2)); var language = int16(font.getBytes(2)); - if (format == 0 && numRecords > 1) { + if (format == 0) { // Characters below 0x20 are controls characters that are hardcoded // into the platform so if some characters in the font are assigned // under this limit they will not be displayed so let's rewrite the // CMap. - var map = []; - var rewrite = false; - for (var j = 0; j < 256; j++) { - var index = font.getByte(); - if (index != 0) { - map.push(index); - if (j < 0x20) - rewrite = true; + var glyphs = []; + if (encoding.empty) { + var orderedGlyphs= []; + for ( var j = 0; j < charset.length; j++) { + var unicode = GlyphsUnicode[charset[font.getByte()]] || 0; + glyphs.push({ unicode: unicode }); + orderedGlyphs.push(unicode); } - } - if (rewrite) { - var glyphs = []; + orderedGlyphs.sort(function(a, b) { + return a - b; + }); + + for (var p in encoding) { + if (p != "empty") + properties.encoding[p] = orderedGlyphs[p - 1]; + } + } else { for (var j = 0x20; j < 256; j++) { // TODO do not hardcode WinAnsiEncoding var unicode = GlyphsUnicode[Encodings["WinAnsiEncoding"][j]]; glyphs.push({ unicode: unicode }); } - cmap.data = createCMapTable(glyphs); } - } else if ((format == 0 && numRecords == 1) || - (format == 6 && numRecords == 1 && !properties.encoding.empty)) { + cmap.data = createCMapTable(glyphs); + } else if (format == 6 && numRecords == 1 && !encoding.empty) { // Format 0 alone is not allowed by the sanitizer so let's rewrite // that to a 3-1-4 Unicode BMP table TODO('Use an other source of informations than ' + 'charset here, it is not reliable'); - var charset = properties.charset; var glyphs = []; for (var j = 0; j < charset.length; j++) { glyphs.push({ @@ -898,7 +903,6 @@ var Font = (function Font() { assert(ranges.length == 1, 'Got ' + ranges.length + ' ranges in a dense array'); - var encoding = properties.encoding; var denseRange = ranges[0]; var start = denseRange[0]; var end = denseRange[1]; diff --git a/pdf.js b/pdf.js index a3179406c..19d7dbece 100644 --- a/pdf.js +++ b/pdf.js @@ -3763,6 +3763,7 @@ var PartialEvaluator = (function() { error('useCMap is not implemented'); break; + case 'beginbfchar': case 'beginbfrange': case 'begincodespacerange': token = ''; @@ -3780,17 +3781,18 @@ var PartialEvaluator = (function() { var code = parseInt('0x' + tokens[j + 2]); for (var k = startRange; k <= endRange; k++) { - // The encoding mapping table will be filled - // later during the building phase - //encodingMap[k] = GlyphsUnicode[encoding[code]]; charset.push(encoding[code++] || '.notdef'); } } break; - case 'beginfbchar': - case 'endfbchar': - error('fbchar parsing is not implemented'); + case 'endbfchar': + for (var j = 0; j < tokens.length; j += 2) { + var index = parseInt('0x' + tokens[j]); + var code = parseInt('0x' + tokens[j + 1]); + encodingMap[index] = GlyphsUnicode[encoding[code]]; + charset.push(encoding[code] || '.notdef'); + } break; default: From c6c72291d99524383debf4b71f5a945792f3a6d2 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Tue, 19 Jul 2011 14:22:51 +0200 Subject: [PATCH 12/20] Do not rasterize below 14px --- fonts.js | 3 ++- pdf.js | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/fonts.js b/fonts.js index a54168a1e..edd54b0a1 100755 --- a/fonts.js +++ b/fonts.js @@ -22,7 +22,7 @@ var kMaxWaitForFontFace = 1000; */ var Fonts = (function Fonts() { - var kScalePrecision = 40; + var kScalePrecision = 50; var fonts = []; if (!isWorker) { @@ -404,6 +404,7 @@ var Font = (function Font() { // Repair the TrueType file if it is can be damaged in the point of // view of the sanitizer data = this.checkAndRepair(name, file, properties); + writeToFile(data, "/tmp/file." + this.name + ".ttf"); break; default: diff --git a/pdf.js b/pdf.js index f164dbd68..03cb16126 100644 --- a/pdf.js +++ b/pdf.js @@ -3898,6 +3898,9 @@ function ScratchCanvas(width, height) { } var CanvasGraphics = (function() { + var kScalePrecision = 50; + var kRasterizerMin = 14; + function constructor(canvasCtx, imageCanvas) { this.ctx = canvasCtx; this.current = new CanvasExtraState(); @@ -4113,8 +4116,10 @@ var CanvasGraphics = (function() { if (this.ctx.$setFont) { this.ctx.$setFont(fontName, size); } else { - this.ctx.font = size + 'px "' + fontName + '"'; Fonts.setActive(fontName, fontObj, size); + + size = (size <= kRasterizerMin) ? size * kScalePrecision : size; + this.ctx.font = size + 'px "' + fontName + '"'; } }, setTextRenderingMode: function(mode) { @@ -4162,6 +4167,8 @@ var CanvasGraphics = (function() { ctx.translate(current.x, -1 * current.y); var font = this.current.font; if (font) { + if (this.current.fontSize < kRasterizerMin) + ctx.transform(1 / kScalePrecision, 0, 0, 1 / kScalePrecision, 0, 0); ctx.transform.apply(ctx, font.textMatrix); text = font.charsToUnicode(text); } From 913504a9378b69dbb52f75729914ca9e615f8f24 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Tue, 19 Jul 2011 14:23:57 +0200 Subject: [PATCH 13/20] Remover leftover --- fonts.js | 1 - 1 file changed, 1 deletion(-) diff --git a/fonts.js b/fonts.js index edd54b0a1..9a064f4c5 100755 --- a/fonts.js +++ b/fonts.js @@ -404,7 +404,6 @@ var Font = (function Font() { // Repair the TrueType file if it is can be damaged in the point of // view of the sanitizer data = this.checkAndRepair(name, file, properties); - writeToFile(data, "/tmp/file." + this.name + ".ttf"); break; default: From 776c10d4e61fb8ce5103c235afaba4becdd66975 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Tue, 19 Jul 2011 14:29:05 +0200 Subject: [PATCH 14/20] Fix a regression on the application of the textMatrix extracted from a CFF font --- fonts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fonts.js b/fonts.js index 9a064f4c5..d08d43a7c 100755 --- a/fonts.js +++ b/fonts.js @@ -375,7 +375,6 @@ function getUnicodeRangeFor(value) { var Font = (function Font() { var constructor = function font_constructor(name, file, properties) { this.name = name; - this.textMatrix = properties.textMatrix || IDENTITY_MATRIX; this.encoding = properties.encoding; // If the font is to be ignored, register it like an already loaded font @@ -411,6 +410,7 @@ var Font = (function Font() { break; } this.data = data; + this.textMatrix = properties.textMatrix || IDENTITY_MATRIX; this.type = properties.type; this.id = Fonts.registerFont(name, data, properties); this.loadedName = 'pdfFont' + this.id; From 6600e747e5e48a6acff3d8d140ac6d478f977327 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Tue, 19 Jul 2011 15:04:22 +0200 Subject: [PATCH 15/20] Fix next line since we already invert the position of the viewport by doing a negative scale --- pdf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index 03cb16126..63a948df1 100644 --- a/pdf.js +++ b/pdf.js @@ -4136,7 +4136,7 @@ var CanvasGraphics = (function() { } }, setLeadingMoveText: function(x, y) { - this.setLeading(-y); + this.setLeading(y); this.moveText(x, y); }, setTextMatrix: function(a, b, c, d, e, f) { From 4275a68e2982840c201e3a5a43839603ca034d13 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Tue, 19 Jul 2011 16:52:29 +0200 Subject: [PATCH 16/20] Filter more characters on font name --- pdf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index 63a948df1..33e554310 100644 --- a/pdf.js +++ b/pdf.js @@ -3674,7 +3674,7 @@ var PartialEvaluator = (function() { var fontName = descriptor.get('FontName'); assertWellFormed(IsName(fontName), 'invalid font name'); - fontName = fontName.name.replace('+', '_'); + fontName = fontName.name.replace(/[\+,\-]/g, '_'); var fontFile = descriptor.get('FontFile', 'FontFile2', 'FontFile3'); if (!fontFile) From 3cc9912acd970ed10593dd1e957ccb0d52c0985f Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Wed, 20 Jul 2011 14:29:07 +0200 Subject: [PATCH 17/20] Add a simpler path for cmap format 0 to cmap format 4 --- fonts.js | 47 ++++++++++++++++------------------------------- pdf.js | 3 +-- 2 files changed, 17 insertions(+), 33 deletions(-) diff --git a/fonts.js b/fonts.js index d08d43a7c..44f81442c 100755 --- a/fonts.js +++ b/fonts.js @@ -533,6 +533,7 @@ var Font = (function Font() { } // Removes duplicate ranges +/* for (var i = ranges.length - 1; i > 0; i--) { var range = ranges[i]; var prevRange = ranges[i - 1]; @@ -541,12 +542,12 @@ var Font = (function Font() { ranges.splice(i - 1, 1); } } +*/ return ranges; }; - function createCMapTable(glyphs) { - glyphs.push({ unicode: 0x0000 }); + function createCMapTable(glyphs, deltas) { var ranges = getRanges(glyphs); var numTables = 1; @@ -573,19 +574,18 @@ var Font = (function Font() { var range = ranges[i]; var start = range[0]; var end = range[1]; - var delta = (bias - start) & 0xffff; + var offset = (segCount - i) * 2 + bias * 2; bias += (end - start + 1); startCount += string16(start); endCount += string16(end); - idDeltas += string16(delta); - idRangeOffsets += string16(0); - - for (var j = start; j <= end; j++) { - glyphsIds += string16(j); - } + idDeltas += string16(0); + idRangeOffsets += string16(offset); } + for (var i = 0; i < glyphs.length; i++) + glyphsIds += string16(deltas ? deltas[i] : i + 1); + endCount += '\xFF\xFF'; startCount += '\xFF\xFF'; idDeltas += '\x00\x01'; @@ -832,30 +832,15 @@ var Font = (function Font() { // under this limit they will not be displayed so let's rewrite the // CMap. var glyphs = []; - if (encoding.empty) { - var orderedGlyphs= []; - for ( var j = 0; j < charset.length; j++) { - var unicode = GlyphsUnicode[charset[font.getByte()]] || 0; - glyphs.push({ unicode: unicode }); - orderedGlyphs.push(unicode); - } - - orderedGlyphs.sort(function(a, b) { - return a - b; - }); - - for (var p in encoding) { - if (p != "empty") - properties.encoding[p] = orderedGlyphs[p - 1]; - } - } else { - for (var j = 0x20; j < 256; j++) { - // TODO do not hardcode WinAnsiEncoding - var unicode = GlyphsUnicode[Encodings["WinAnsiEncoding"][j]]; - glyphs.push({ unicode: unicode }); + var deltas = []; + for (var j = 0; j < 256; j++) { + var index = font.getByte(); + if (index) { + deltas.push(index); + glyphs.push({ unicode : j }); } } - cmap.data = createCMapTable(glyphs); + cmap.data = createCMapTable(glyphs, deltas); } else if (format == 6 && numRecords == 1 && !encoding.empty) { // Format 0 alone is not allowed by the sanitizer so let's rewrite // that to a 3-1-4 Unicode BMP table diff --git a/pdf.js b/pdf.js index 33e554310..62e9dac4f 100644 --- a/pdf.js +++ b/pdf.js @@ -3722,9 +3722,8 @@ var PartialEvaluator = (function() { var baseName = encoding.get('BaseEncoding'); if (baseName) { var base = Encodings[baseName.name]; - var index = 0; for (var j = 0, end = base.length; j < end; j++) - encodingMap[index++] = GlyphsUnicode[base[j]]; + encodingMap[j] = GlyphsUnicode[base[j]] || 0; } else { TODO('need to load default encoding'); } From 6311977fee60f3b6e5ef492db59206b02e271583 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Wed, 20 Jul 2011 15:18:44 +0200 Subject: [PATCH 18/20] Merge with upstream --- fonts.js | 27 +++++++++++++++------------ pdf.js | 6 +++++- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/fonts.js b/fonts.js index 44f81442c..8770c8d06 100755 --- a/fonts.js +++ b/fonts.js @@ -532,18 +532,6 @@ var Font = (function Font() { ranges.push([start, end]); } - // Removes duplicate ranges -/* - for (var i = ranges.length - 1; i > 0; i--) { - var range = ranges[i]; - var prevRange = ranges[i - 1]; - if (range[0] <= prevRange[1]) { - range[0] = prevRange[0] - 2; - ranges.splice(i - 1, 1); - } - } -*/ - return ranges; }; @@ -840,6 +828,21 @@ var Font = (function Font() { glyphs.push({ unicode : j }); } } + + var rewrite = false; + for (var code in encoding) { + if (code < 0x20 && encoding[code]) + rewrite = true; + + if (rewrite) + encoding[code] = parseInt(code) + 0x1F; + } + + if (rewrite) { + for (var j = 0; j < glyphs.length; j++) { + glyphs[j].unicode += 0x1F; + } + } cmap.data = createCMapTable(glyphs, deltas); } else if (format == 6 && numRecords == 1 && !encoding.empty) { // Format 0 alone is not allowed by the sanitizer so let's rewrite diff --git a/pdf.js b/pdf.js index 62e9dac4f..32779f5d1 100644 --- a/pdf.js +++ b/pdf.js @@ -3733,7 +3733,11 @@ var PartialEvaluator = (function() { var index = 0; for (var j = 0; j < differences.length; j++) { var data = differences[j]; - IsNum(data) ? index = data : encodingMap[index++] = data; + if (subType.name == 'TrueType') { + IsNum(data) ? index = data : encodingMap[index++] = j; + } else { + IsNum(data) ? index = data : encodingMap[index++] = GlyphsUnicode[data.name]; + } } // Get the font charset if any From 1d59de6c12f1a75455a087d98fd4f7e4f256f706 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 21 Jul 2011 11:01:38 +0200 Subject: [PATCH 19/20] Fix a > 32000 conversion error in type1 to type2 charstring --- fonts.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/fonts.js b/fonts.js index 8770c8d06..5a64a645a 100755 --- a/fonts.js +++ b/fonts.js @@ -1786,8 +1786,10 @@ CFF.prototype = { String.fromCharCode((value >> 8) & 0xFF) + String.fromCharCode(value & 0xFF); } else if (value >= (-2147483648) && value <= 2147483647) { + value ^= 0xffffffff; + value += 1; return '\xff' + - String.fromCharCode((value >>> 24) & 0xFF) + + String.fromCharCode((value >> 24) & 0xFF) + String.fromCharCode((value >> 16) & 0xFF) + String.fromCharCode((value >> 8) & 0xFF) + String.fromCharCode(value & 0xFF); @@ -1893,7 +1895,14 @@ CFF.prototype = { charstring[i] = cmd; } } else { - charstring.splice(i, 1, 28, command >> 8, command & 0xff); + // Type1 charstring use a division for number above 32000 + if (command > 32000) { + var divisor = charstring[i + 1]; + command /= divisor; + charstring.splice(i, 3, 28, command >> 8, command & 0xff); + } else { + charstring.splice(i, 1, 28, command >> 8, command & 0xff); + } i += 2; } } From f5b9a9355b982b7ac76ac954b3a8086cfd6e468a Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 21 Jul 2011 20:14:50 +0200 Subject: [PATCH 20/20] Get rid of the inclusion of fonts_utils --- web/viewer.html | 1 - 1 file changed, 1 deletion(-) diff --git a/web/viewer.html b/web/viewer.html index 8caa40f3e..df9604db4 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -8,7 +8,6 @@ -