diff --git a/fonts.js b/fonts.js index cc353c03b..e10007c94 100755 --- a/fonts.js +++ b/fonts.js @@ -2251,7 +2251,7 @@ var Type2CFF = (function() { var strings = this.getStrings(stringIndex); - var baseDict = this.parseDict(dictIndex.get(0)); + var baseDict = this.parseDict(dictIndex.get(0).data); var topDict = this.getTopDict(baseDict, strings); var bytes = this.bytes; @@ -2276,6 +2276,33 @@ var Type2CFF = (function() { if (hasSupplement) bytes[topDict.Encoding] = 0; + // The CFF specification state that the 'dotsection' command + // (12, 0) is deprecated and treated as a no-op, but all Type2 + // charstrings processors should support them. Unfortunately + // the font sanitizer don't. As a workaround the sequence (12, 0) + // is replaced by a useless (0, hmoveto). + var count = charStrings.length; + for (var i = 0; i < count; i++) { + var charstring = charStrings.get(i); + + var start = charstring.start; + var data = charstring.data; + var length = data.length; + for (var j = 0; j <= length; j) { + var value = data[j++]; + if (value == 12 && data[j++] == 0) { + bytes[start + j - 2] = 139; + bytes[start + j - 1] = 22; + } else if (value === 28) { + j += 2; + } else if (value >= 247 && value <= 254) { + j++; + } else if (value == 255) { + j += 4; + } + } + } + // charstrings contains info about glyphs (one element per glyph // containing mappings for {unicode, width}) var charstrings = this.getCharStrings(charset, charStrings, @@ -2566,7 +2593,7 @@ var Type2CFF = (function() { } else if (value <= 254) { return -((value - 251) * 256) - dict[pos++] - 108; } else { - error('Incorrect byte'); + error('255 is not a valid DICT command'); } return -1; }; @@ -2644,7 +2671,11 @@ var Type2CFF = (function() { var start = offsets[index]; var end = offsets[index + 1]; - return bytes.subarray(start, end); + return { + start: start, + end: end, + data: bytes.subarray(start, end) + } }, length: count, endPos: end diff --git a/utils/cffStandardStrings.js b/utils/cffStandardStrings.js index 09c408ee7..7919b0f17 100644 --- a/utils/cffStandardStrings.js +++ b/utils/cffStandardStrings.js @@ -560,7 +560,7 @@ var CFFDictDataMap = { '18': { name: 'ExpansionFactor' }, - '9': { + '19': { name: 'initialRandomSeed' }, '20': { diff --git a/utils/fonts_utils.js b/utils/fonts_utils.js index 7665906a1..2c05a64ba 100644 --- a/utils/fonts_utils.js +++ b/utils/fonts_utils.js @@ -20,17 +20,27 @@ function readCharset(aStream, aCharstrings) { var charset = {}; var format = aStream.getByte(); + var count = aCharstrings.length - 1; if (format == 0) { charset['.notdef'] = readCharstringEncoding(aCharstrings[0]); - var count = aCharstrings.length - 1; for (var i = 1; i < count + 1; i++) { var sid = aStream.getByte() << 8 | aStream.getByte(); charset[CFFStrings[sid]] = readCharstringEncoding(aCharstrings[i]); //log(CFFStrings[sid] + "::" + charset[CFFStrings[sid]]); } } else if (format == 1) { - error('Charset Range are not supported'); + for (var i = 1; i < count + 1; i++) { + var first = aStream.getByte(); + first = (first << 8) | aStream.getByte(); + var numLeft = aStream.getByte(); + for (var j = 0; j <= numLeft; j++) { + var sid = first++; + if (CFFStrings[sid] == 'three') + log(aCharstrings[j]); + charset[CFFStrings[sid]] = readCharstringEncoding(aCharstrings[j]); + } + } } else { error('Invalid charset format'); } @@ -44,6 +54,9 @@ function readCharset(aStream, aCharstrings) { * chapter 3.1. */ function readCharstringEncoding(aString) { + if (!aString) + return ""; + var charstringTokens = []; var count = aString.length; @@ -71,9 +84,9 @@ function readCharstringEncoding(aString) { } else if (value < 247) { token = parseInt(value) - 139; } else if (value < 251) { - token = ((value - 247) * 256) + aString[i++] + 108; + token = (value - 247) * 256 + aString[i++] + 108; } else if (value < 255) { - token = -((value - 251) * 256) - aString[i++] - 108; + token = -(value - 251) * 256 - aString[i++] - 108; } else {// value == 255 token = aString[i++] << 24 | aString[i++] << 16 | aString[i++] << 8 | aString[i]; @@ -146,9 +159,9 @@ function readFontDictData(aString, aMap) { } else if (value <= 246) { token = parseInt(value) - 139; } else if (value <= 250) { - token = ((value - 247) * 256) + aString[i++] + 108; + token = (value - 247) * 256 + aString[i++] + 108; } else if (value <= 254) { - token = -((value - 251) * 256) - aString[i++] - 108; + token = -(value - 251) * 256 - aString[i++] - 108; } else if (value == 255) { error('255 is not a valid DICT command'); } @@ -199,7 +212,7 @@ function readFontIndexData(aStream, aIsByte) { for (var i = 0; i < count + 1; i++) offsets.push(getNextOffset()); - log('Found ' + count + ' objects at offsets :' + + dump('Found ' + count + ' objects at offsets :' + offsets + ' (offsize: ' + offsize + ')'); // Now extract the objects @@ -285,23 +298,20 @@ var Type2Parser = function(aFilePath) { font.set('hdrSize', aStream.getByte()); font.set('offsize', aStream.getByte()); - // Move the cursor after the header - aStream.skip(font.get('hdrSize') - aStream.pos); - // Read the NAME Index dump('Reading Index: Names'); font.set('Names', readFontIndexData(aStream)); - log('Names: ' + font.get('Names')); + dump('Names: ' + font.get('Names')); // Read the Top Dict Index dump('Reading Index: TopDict'); var topDict = readFontIndexData(aStream, true); - log('TopDict: ' + topDict); + dump('TopDict: ' + topDict); // Read the String Index dump('Reading Index: Strings'); var strings = readFontIndexData(aStream); - log('strings: ' + strings); + dump('strings: ' + strings); // Fill up the Strings dictionary with the new unique strings for (var i = 0; i < strings.length; i++) @@ -321,7 +331,7 @@ var Type2Parser = function(aFilePath) { // Reading Private Dict var priv = font.get('Private'); - log('Reading Private Dict (offset: ' + priv.offset + + dump('Reading Private Dict (offset: ' + priv.offset + ' size: ' + priv.size + ')'); aStream.pos = priv.offset;