From e26b5b3b00b8f3c54c6fc7cd029ab4cfa03e624c Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 1 Sep 2011 19:50:04 +0200 Subject: [PATCH 1/8] Show Type1 glyphs below 0x20, fix a bug in readNumberArray, read lenIV --- fonts.js | 42 ++++++++++++++++++++++++++---------------- pdf.js | 6 +++++- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/fonts.js b/fonts.js index 20f99932d..f17fdfc56 100755 --- a/fonts.js +++ b/fonts.js @@ -1439,7 +1439,6 @@ var Type1Parser = function() { var charstring = []; var lsb = 0; var width = 0; - var used = false; var value = ''; var count = array.length; @@ -1477,7 +1476,7 @@ var Type1Parser = function() { command = charStringDictionary['12'][escape]; } else { // TODO Clean this code - if (value == 13) { + if (value == 13) { //hsbw if (charstring.length == 2) { lsb = charstring[0]; width = charstring[1]; @@ -1509,7 +1508,7 @@ var Type1Parser = function() { } else if (command == -1) { error('Support for Type1 command ' + value + ' (' + escape + ') is not implemented in charstring: ' + - charString); + charstring); } value = command; @@ -1535,7 +1534,11 @@ var Type1Parser = function() { * array extracted from and eexec encrypted block of data */ function readNumberArray(str, index) { - var start = ++index; + var start = index; + while (str[index++] != '[') + start++; + start++; + var count = 0; while (str[index++] != ']') count++; @@ -1569,7 +1572,9 @@ var Type1Parser = function() { subrs: [], charstrings: [], properties: { - 'private': {} + 'private': { + 'lenIV': 4 + } } }; @@ -1592,9 +1597,12 @@ var Type1Parser = function() { }; var c = eexecStr[i]; - if ((glyphsSection || subrsSection) && c == 'R') { - var data = eexec.slice(i + 3, i + 3 + length); - var encoded = decrypt(data, kCharStringsEncryptionKey, 4); + if ((glyphsSection || subrsSection) && + (token == 'RD' || token == '-|')) { + i++; + var data = eexec.slice(i, i + length); + var lenIV = program.properties.private['lenIV']; + var encoded = decrypt(data, kCharStringsEncryptionKey, lenIV); var str = decodeCharString(encoded); if (glyphsSection) { @@ -1607,7 +1615,8 @@ var Type1Parser = function() { } else { program.subrs.push(str.charstring); } - i += length + 3; + i += length; + token = ''; } else if (c == ' ' || c == '\n') { length = parseInt(token); token = ''; @@ -1624,7 +1633,7 @@ var Type1Parser = function() { getToken(); // read in 'array' for (var j = 0; j < num; ++j) { var t = getToken(); // read in 'dup' - if (t == 'ND') + if (t == 'ND' || t == '|-') break; var index = parseInt(getToken()); if (index > j) @@ -1646,7 +1655,7 @@ var Type1Parser = function() { case '/StemSnapH': case '/StemSnapV': program.properties.private[token.substring(1)] = - readNumberArray(eexecStr, i + 2); + readNumberArray(eexecStr, i + 1); break; case '/StdHW': case '/StdVW': @@ -1654,6 +1663,7 @@ var Type1Parser = function() { readNumberArray(eexecStr, i + 2)[0]; break; case '/BlueShift': + case '/lenIV': case '/BlueFuzz': case '/BlueScale': case '/LanguageGroup': @@ -1821,7 +1831,7 @@ var CFF = function(name, file, properties) { // Decrypt the data blocks and retrieve it's content var eexecBlock = file.getBytes(length2); - var data = type1Parser.extractFontProgram(eexecBlock, properties); + var data = type1Parser.extractFontProgram(eexecBlock); for (var info in data.properties) properties[info] = data.properties[info]; @@ -1987,11 +1997,10 @@ CFF.prototype = { var cmd = map[command]; assert(cmd, 'Unknow command: ' + command); - if (IsArray(cmd)) { + if (IsArray(cmd)) charstring.splice(i++, 1, cmd[0], cmd[1]); - } else { + else charstring[i] = cmd; - } } else { // Type1 charstring use a division for number above 32000 if (command > 32000) { @@ -2110,7 +2119,8 @@ CFF.prototype = { ExpansionFactor: '\x0c\x18' }; for (var field in fieldMap) { - if (!properties.private.hasOwnProperty(field)) continue; + if (!properties.private.hasOwnProperty(field)) + continue; var value = properties.private[field]; if (IsArray(value)) { diff --git a/pdf.js b/pdf.js index ec3cb0d75..2feade07e 100644 --- a/pdf.js +++ b/pdf.js @@ -4300,8 +4300,12 @@ var PartialEvaluator = (function() { var glyphsMap = {}; for (var i = firstChar; i <= lastChar; i++) { var glyph = diffEncoding[i] || baseEncoding[i]; - if (glyph) + if (glyph) { glyphsMap[glyph] = encodingMap[i] = GlyphsUnicode[glyph] || i; + if (glyphsMap[glyph] <= 0x1f) + glyphsMap[glyph] = encodingMap[i] += 0xE000; + + } } if (fontType == 'TrueType' && fontDict.has('ToUnicode') && differences) { From 18661debdc1e01e1c386ece52e0dfce69fb5c476 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 2 Sep 2011 13:37:39 +0200 Subject: [PATCH 2/8] Use lenIV to read the subrs section --- fonts.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fonts.js b/fonts.js index f17fdfc56..5aa549e65 100755 --- a/fonts.js +++ b/fonts.js @@ -1457,7 +1457,7 @@ var Type1Parser = function() { for (var j = 0; j < argc; j++) charstring.push('drop'); - // If the flex mechanishm is not used in a font program, Adobe + // If the flex mechanism is not used in a font program, Adobe // state that that entries 0, 1 and 2 can simply be replace by // {}, which means that we can simply ignore them. if (index < 3) { @@ -1641,7 +1641,8 @@ var Type1Parser = function() { var length = parseInt(getToken()); getToken(); // read in 'RD' var data = eexec.slice(i + 1, i + 1 + length); - var encoded = decrypt(data, kCharStringsEncryptionKey, 4); + var lenIV = program.properties.private['lenIV']; + var encoded = decrypt(data, kCharStringsEncryptionKey, lenIV); var str = decodeCharString(encoded); i = i + 1 + length; getToken(); //read in 'NP' From 5f99e398f469ab6bbe9631b7fe6a2ab12fa77aba Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 2 Sep 2011 14:21:48 +0200 Subject: [PATCH 3/8] Be more flexible about Subrs parsing --- fonts.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fonts.js b/fonts.js index 5aa549e65..4b119dc20 100755 --- a/fonts.js +++ b/fonts.js @@ -1633,7 +1633,7 @@ var Type1Parser = function() { getToken(); // read in 'array' for (var j = 0; j < num; ++j) { var t = getToken(); // read in 'dup' - if (t == 'ND' || t == '|-') + if (t == 'ND' || t == '|-' || t == 'noaccess') break; var index = parseInt(getToken()); if (index > j) @@ -1645,7 +1645,9 @@ var Type1Parser = function() { var encoded = decrypt(data, kCharStringsEncryptionKey, lenIV); var str = decodeCharString(encoded); i = i + 1 + length; - getToken(); //read in 'NP' + t = getToken(); //read in 'NP' + if (t == 'noaccess') + getToken(); //read in 'put' program.subrs[index] = str.charstring; } break; From e1f7edfae8c6de2dcfa1a4481496189e04fd1115 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 2 Sep 2011 15:26:16 +0200 Subject: [PATCH 4/8] Add a comment about supporting hint replacement --- fonts.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fonts.js b/fonts.js index 4b119dc20..90e70a302 100755 --- a/fonts.js +++ b/fonts.js @@ -1466,6 +1466,7 @@ var Type1Parser = function() { // This is the same things about hint replacement, if it is not used // entry 3 can be replaced by {3} + // TODO support hint replacment if (index == 3) { charstring.push(3); i++; @@ -1942,7 +1943,7 @@ CFF.prototype = { return type2Charstrings; }, - getType2Subrs: function cff_getType2Charstrings(type1Subrs) { + getType2Subrs: function cff_getType2Subrs(type1Subrs) { var bias = 0; var count = type1Subrs.length; if (count < 1240) From cd930d9248f323c1ec622098ed3b6420e23f4ca1 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Fri, 2 Sep 2011 15:47:34 +0200 Subject: [PATCH 5/8] Ensure the characters between 127 and 255 are shown --- pdf.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pdf.js b/pdf.js index 2feade07e..631496481 100644 --- a/pdf.js +++ b/pdf.js @@ -4301,9 +4301,12 @@ var PartialEvaluator = (function() { for (var i = firstChar; i <= lastChar; i++) { var glyph = diffEncoding[i] || baseEncoding[i]; if (glyph) { - glyphsMap[glyph] = encodingMap[i] = GlyphsUnicode[glyph] || i; - if (glyphsMap[glyph] <= 0x1f) - glyphsMap[glyph] = encodingMap[i] += 0xE000; + var index = GlyphsUnicode[glyph] || i; + glyphsMap[glyph] = encodingMap[i] = index; + + var kCmapGlyphOffset = 0xE000; + if (index <= 0x1f || (index >= 127 && index <= 255)) + glyphsMap[glyph] = encodingMap[i] += kCmapGlyphOffset; } } From 0f4b2437529976f077ab4921776772de018ecd0b Mon Sep 17 00:00:00 2001 From: Kalervo Kujala Date: Sat, 3 Sep 2011 20:47:58 +0300 Subject: [PATCH 6/8] Small corrections to pdf.js. Also fix some lint errors. --- pdf.js | 72 ++++++++++++++++++++++++++++------------------------------ 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/pdf.js b/pdf.js index 631496481..71a734f63 100644 --- a/pdf.js +++ b/pdf.js @@ -1,4 +1,4 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ 'use strict'; @@ -18,6 +18,16 @@ function warn(msg) { log('Warning: ' + msg); } +function backtrace() { + var stackStr; + try { + throw new Error(); + } catch (e) { + stackStr = e.stack; + } + return stackStr.split('\n').slice(1).join('\n'); +} + function error(msg) { log(backtrace()); throw new Error(msg); @@ -44,23 +54,13 @@ function assertWellFormed(cond, msg) { malformed(msg); } -function backtrace() { - var stackStr; - try { - throw new Error(); - } catch (e) { - stackStr = e.stack; - } - return stackStr.split('\n').slice(1).join('\n'); -} - function shadow(obj, prop, value) { try { Object.defineProperty(obj, prop, { value: value, enumerable: true, configurable: true, writable: false }); - } catch(e) { + } catch (e) { obj.__defineGetter__(prop, function() { return value; }); @@ -185,7 +185,7 @@ var DecodeStream = (function() { var buffer2 = new Uint8Array(size); for (var i = 0; i < current; ++i) buffer2[i] = buffer[i]; - return this.buffer = buffer2; + return (this.buffer = buffer2); }, getByte: function decodestream_getByte() { var pos = this.pos; @@ -197,11 +197,11 @@ var DecodeStream = (function() { return this.buffer[this.pos++]; }, getBytes: function decodestream_getBytes(length) { - var pos = this.pos; + var end, pos = this.pos; if (length) { this.ensureBuffer(pos + length); - var end = pos + length; + end = pos + length; while (!this.eof && this.bufferLength < end) this.readBlock(); @@ -213,7 +213,7 @@ var DecodeStream = (function() { while (!this.eof) this.readBlock(); - var end = this.bufferLength; + end = this.bufferLength; // checking if bufferLength is still 0 then // the buffer has to be initialized @@ -265,7 +265,7 @@ var FakeStream = (function() { function constructor(stream) { this.dict = stream.dict; DecodeStream.call(this); - }; + } constructor.prototype = Object.create(DecodeStream.prototype); constructor.prototype.readBlock = function() { @@ -532,8 +532,8 @@ var FlateStream = (function() { constructor.prototype.readBlock = function() { function repeat(stream, array, len, offset, what) { - var repeat = stream.getBits(len) + offset; - while (repeat-- > 0) + var repeatLength = stream.getBits(len) + offset; + while (repeatLength-- > 0) array[i++] = what; } @@ -821,8 +821,8 @@ var PredictorStream = (function() { currentRow[i] = up + c; else currentRow[i] = upLeft + c; - break; } + break; default: error('Unsupported predictor: ' + predictor); break; @@ -1621,6 +1621,7 @@ var CCITTFaxStream = (function() { this.err = false; + var code1, code2, code3; if (this.nextLine2D) { for (var i = 0; codingLine[i] < columns; ++i) refLine[i] = codingLine[i]; @@ -1633,7 +1634,7 @@ var CCITTFaxStream = (function() { blackPixels = 0; while (codingLine[this.codingPos] < columns) { - var code1 = this.getTwoDimCode(); + code1 = this.getTwoDimCode(); switch (code1) { case twoDimPass: this.addPixels(refLine[refPos + 1], blackPixels); @@ -1641,9 +1642,8 @@ var CCITTFaxStream = (function() { refPos += 2; break; case twoDimHoriz: - var code1 = 0, code2 = 0; + code1 = code2 = 0; if (blackPixels) { - var code3; do { code1 += (code3 = this.getBlackCode()); } while (code3 >= 64); @@ -1651,7 +1651,6 @@ var CCITTFaxStream = (function() { code2 += (code3 = this.getWhiteCode()); } while (code3 >= 64); } else { - var code3; do { code1 += (code3 = this.getWhiteCode()); } while (code3 >= 64); @@ -1831,7 +1830,6 @@ var CCITTFaxStream = (function() { this.eof = true; } } else if (this.err && this.eoline) { - var code1; while (true) { code1 = this.lookBits(13); if (code1 == EOF) { @@ -2403,7 +2401,7 @@ var Lexer = (function() { var floating = false; var str = ch; var stream = this.stream; - do { + for (;;) { ch = stream.lookChar(); if (ch == '.' && !floating) { str += ch; @@ -2421,7 +2419,7 @@ var Lexer = (function() { break; } stream.skip(); - } while (true); + } var value = parseFloat(str); if (isNaN(value)) error('Invalid floating point number: ' + value); @@ -2541,7 +2539,7 @@ var Lexer = (function() { getHexString: function(ch) { var str = ''; var stream = this.stream; - while (1) { + for (;;) { ch = stream.getChar(); if (ch == '>') { break; @@ -3378,15 +3376,15 @@ var Page = (function() { rotatePoint: function(x, y) { var rotate = this.rotate; switch (rotate) { - default: - case 0: - return {x: x, y: this.height - y}; case 180: return {x: this.width - x, y: y}; case 90: return {x: this.width - y, y: this.height - x}; case 270: return {x: y, y: x}; + case 0: + default: + return {x: x, y: this.height - y}; } }, getLinks: function() { @@ -4268,11 +4266,11 @@ var PartialEvaluator = (function() { } else if (IsName(encoding)) { baseEncoding = Encodings[encoding.name].slice(); } else { - error("Encoding is not a Name nor a Dict"); + error('Encoding is not a Name nor a Dict'); } } - var fontType = subType.name; + var fontType = subType.name; if (!baseEncoding) { switch (fontType) { case 'TrueType': @@ -4307,11 +4305,11 @@ var PartialEvaluator = (function() { var kCmapGlyphOffset = 0xE000; if (index <= 0x1f || (index >= 127 && index <= 255)) glyphsMap[glyph] = encodingMap[i] += kCmapGlyphOffset; - } } - if (fontType == 'TrueType' && fontDict.has('ToUnicode') && differences) { + if (fontType == 'TrueType' && fontDict.has('ToUnicode') && + differences) { var cmapObj = xref.fetchIfRef(fontDict.get('ToUnicode')); if (IsName(cmapObj)) { error('ToUnicode file cmap translation not implemented'); @@ -4810,8 +4808,8 @@ var CanvasGraphics = (function() { size = (size <= kRasterizerMin) ? size * kScalePrecision : size; - var bold = fontObj.black ? (fontObj.bold ? 'bolder' : 'bold') - : (fontObj.bold ? 'bold' : 'normal'); + var bold = fontObj.black ? (fontObj.bold ? 'bolder' : 'bold') : + (fontObj.bold ? 'bold' : 'normal'); var italic = fontObj.italic ? 'italic' : 'normal'; var rule = italic + ' ' + bold + ' ' + size + 'px "' + name + '"'; From 5ab01e2cd0e67949d795224449d8a8d581f9c94f Mon Sep 17 00:00:00 2001 From: Kalervo Kujala Date: Sat, 3 Sep 2011 21:41:50 +0300 Subject: [PATCH 7/8] Fix xref bug. Use this.xref instead of xref in fetchDestinations function. --- pdf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index 71a734f63..cf9615875 100644 --- a/pdf.js +++ b/pdf.js @@ -3547,7 +3547,7 @@ var Catalog = (function() { }, get destinations() { function fetchDestination(ref) { - var dest = xref.fetchIfRef(ref); + var dest = this.xref.fetchIfRef(ref); return IsDict(dest) ? dest.get('D') : dest; } From 2b5ed9b0fc943a6ad5529004b00d8a4aa511d958 Mon Sep 17 00:00:00 2001 From: Kalervo Kujala Date: Sat, 3 Sep 2011 22:28:45 +0300 Subject: [PATCH 8/8] Address comments for xref bug. --- pdf.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pdf.js b/pdf.js index cf9615875..8303bb650 100644 --- a/pdf.js +++ b/pdf.js @@ -3546,8 +3546,8 @@ var Catalog = (function() { } }, get destinations() { - function fetchDestination(ref) { - var dest = this.xref.fetchIfRef(ref); + function fetchDestination(xref, ref) { + var dest = xref.fetchIfRef(ref); return IsDict(dest) ? dest.get('D') : dest; } @@ -3564,7 +3564,7 @@ var Catalog = (function() { obj = xref.fetchIfRef(nameDictionaryRef); obj.forEach(function(key, value) { if (!value) return; - dests[key] = fetchDestination(value); + dests[key] = fetchDestination(xref, value); }); } if (nameTreeRef) { @@ -3588,7 +3588,7 @@ var Catalog = (function() { } var names = obj.get('Names'); for (i = 0, n = names.length; i < n; i += 2) { - dests[names[i]] = fetchDestination(names[i + 1]); + dests[names[i]] = fetchDestination(xref, names[i + 1]); } } }