diff --git a/crypto.js b/crypto.js index 652f53b2c..4aaca9520 100644 --- a/crypto.js +++ b/crypto.js @@ -543,7 +543,7 @@ var CipherTransformFactory = (function() { key[i++] = 0x54; } var hash = md5(key, 0, i); - return hash.subarray(0, Math.min(key.length, 16)); + return hash.subarray(0, Math.min(encryptionKey.length + 5, 16)); } function buildCipherConstructor(cf, name, num, gen, key) { diff --git a/fonts.js b/fonts.js index 9049255e7..b81f4a2ed 100755 --- a/fonts.js +++ b/fonts.js @@ -1284,8 +1284,6 @@ var Font = (function Font() { var charcode = chars.charCodeAt(i); var unicode = encoding[charcode]; if ('undefined' == typeof(unicode)) { - // FIXME/issue 233: we're hitting this in test/pdf/sizes.pdf - // at the moment, for unknown reasons. warn('Unencoded charcode ' + charcode); unicode = charcode; } @@ -1485,16 +1483,22 @@ var Type1Parser = function() { // TODO Clean this code if (value == 13) { if (charstring.length == 2) { + lsb = charstring[0]; width = charstring[1]; + charstring.splice(0, 1); } else if (charstring.length == 4 && charstring[3] == 'div') { + lsb = charstring[0]; width = charstring[1] / charstring[2]; + charstring.splice(0, 1); + } else if (charstring.length == 4 && charstring[2] == 'div') { + lsb = charstring[0] / charstring[1]; + width = charstring[3]; + charstring.splice(0, 3); } else { error('Unsupported hsbw format: ' + charstring); } - lsb = charstring[0]; charstring.push(lsb, 'hmoveto'); - charstring.splice(0, 1); continue; } command = charStringDictionary[value]; @@ -1584,13 +1588,12 @@ var Type1Parser = function() { while (i < count && (eexecStr[i] == ' ' || eexecStr[i] == '\n')) ++i; - var t = ''; + var token = ''; while (i < count && !(eexecStr[i] == ' ' || eexecStr[i] == '\n')) - t += eexecStr[i++]; - - return t; - } + token += eexecStr[i++]; + return token; + }; var c = eexecStr[i]; if ((glyphsSection || subrsSection) && c == 'R') { @@ -1674,18 +1677,28 @@ var Type1Parser = function() { return program; }, - this.extractFontHeader = function t1_extractFontProgram(stream) { + this.extractFontHeader = function t1_extractFontHeader(stream, properties) { var headerString = ''; for (var i = 0; i < stream.length; i++) headerString += String.fromCharCode(stream[i]); - var info = { - textMatrix: null - }; - var token = ''; var count = headerString.length; for (var i = 0; i < count; i++) { + var getToken = function() { + var char = headerString[i]; + while (i < count && (char == ' ' || char == '\n' || char == '/')) + char = headerString[++i]; + + var token = ''; + while (i < count && !(char == ' ' || char == '\n' || char == '/')) { + token += char; + char = headerString[++i]; + } + + return token; + }; + var c = headerString[i]; if (c == ' ' || c == '\n') { switch (token) { @@ -1699,7 +1712,25 @@ var Type1Parser = function() { // Make the angle into the right direction matrix[2] *= -1; - info.textMatrix = matrix; + properties.textMatrix = matrix; + break; + case '/Encoding': + if (!properties.builtInEncoding) + break; + + var size = parseInt(getToken()); + getToken(); // read in 'array' + + for (var j = 0; j < size; j++) { + var token = getToken(); + if (token == 'dup') { + var index = parseInt(getToken()); + var glyph = getToken(); + properties.encoding[index] = GlyphsUnicode[glyph]; + getToken(); // read the in 'put' + j = index; + } + } break; } token = ''; @@ -1707,8 +1738,6 @@ var Type1Parser = function() { token += c; } } - - return info; }; }; @@ -1792,13 +1821,11 @@ var CFF = function(name, file, properties) { var length2 = file.dict.get('Length2'); var headerBlock = file.getBytes(length1); - var header = type1Parser.extractFontHeader(headerBlock); - for (var info in header) - properties[info] = header[info]; + type1Parser.extractFontHeader(headerBlock, properties); // Decrypt the data blocks and retrieve it's content var eexecBlock = file.getBytes(length2); - var data = type1Parser.extractFontProgram(eexecBlock); + var data = type1Parser.extractFontProgram(eexecBlock, properties); for (var info in data.properties) properties[info] = data.properties[info]; @@ -1868,15 +1895,14 @@ CFF.prototype = { getOrderedCharStrings: function cff_getOrderedCharStrings(glyphs) { var charstrings = []; + var missings = []; for (var i = 0; i < glyphs.length; i++) { var glyph = glyphs[i]; var unicode = GlyphsUnicode[glyph.glyph]; if (!unicode) { - if (glyph.glyph != '.notdef') { - warn(glyph.glyph + - ' does not have an entry in the glyphs unicode dictionary'); - } + if (glyph.glyph != '.notdef') + missings.push(glyph.glyph); } else { charstrings.push({ glyph: glyph, @@ -1888,6 +1914,9 @@ CFF.prototype = { } } + if (missings.length) + warn(missings + ' does not have unicode in the glyphs dictionary'); + charstrings.sort(function charstrings_sort(a, b) { return a.unicode - b.unicode; }); diff --git a/pdf.js b/pdf.js index 4408bc49e..e4ef1b63e 100644 --- a/pdf.js +++ b/pdf.js @@ -208,6 +208,11 @@ var DecodeStream = (function() { this.readBlock(); var end = this.bufferLength; + + // checking if bufferLength is still 0 then + // the buffer has to be initialized + if (!end) + this.buffer = new Uint8Array(0); } this.pos = end; @@ -3340,11 +3345,11 @@ var Page = (function() { var xref = this.xref; var content = xref.fetchIfRef(this.content); var resources = xref.fetchIfRef(this.resources); - if (IsArray(this.content)) { + if (IsArray(content)) { // fetching items var i, n = content.length; for (i = 0; i < n; ++i) - content[i] = xref.fetchIfRef(this.content[i]); + content[i] = xref.fetchIfRef(content[i]); content = new StreamsSequenceStream(content); } this.code = gfx.compile(content, xref, resources, fonts, images); @@ -4191,6 +4196,7 @@ var PartialEvaluator = (function() { fd = fontDict.get('FontDescriptor'); } + var builtInEncoding = false; var encodingMap = {}; var glyphMap = {}; var charset = []; @@ -4261,9 +4267,11 @@ var PartialEvaluator = (function() { if (!baseEncoding) { var type = subType.name; if (type == 'TrueType') { - baseEncoding = Encodings.WinAnsiEncoding.slice(0); + baseEncoding = Encodings.WinAnsiEncoding.slice(); } else if (type == 'Type1') { - baseEncoding = Encodings.StandardEncoding.slice(0); + baseEncoding = Encodings.StandardEncoding.slice(); + if (!diffEncoding.length) + builtInEncoding = true; } else { error('Unknown type of font'); } @@ -4285,6 +4293,7 @@ var PartialEvaluator = (function() { } if (fontDict.has('ToUnicode')) { + encodingMap['empty'] = true; var cmapObj = xref.fetchIfRef(fontDict.get('ToUnicode')); if (IsName(cmapObj)) { error('ToUnicode file cmap translation not implemented'); @@ -4419,6 +4428,7 @@ var PartialEvaluator = (function() { subtype: fileType, widths: glyphWidths, encoding: encodingMap, + builtInEncoding: builtInEncoding, charset: charset, firstChar: fontDict.get('FirstChar'), lastChar: fontDict.get('LastChar'), @@ -5102,15 +5112,18 @@ var CanvasGraphics = (function() { var tmpCanvas = new this.ScratchCanvas(w, h); var tmpCtx = tmpCanvas.getContext('2d'); + if (imageObj.imageMask) { + var fillColor = this.current.fillColor; + tmpCtx.fillStyle = (fillColor && fillColor.type === 'Pattern') ? + fillColor.getPattern(tmpCtx) : fillColor; + tmpCtx.fillRect(0, 0, w, h); + } var imgData = tmpCtx.getImageData(0, 0, w, h); var pixels = imgData.data; if (imageObj.imageMask) { - var inverseDecode = imageObj.decode && imageObj.decode[0] > 0; - // TODO fillColor pattern support - var fillColor = this.current.fillColor; - imageObj.fillUsingStencilMask(pixels, fillColor, - inverseDecode); + var inverseDecode = !!imageObj.decode && imageObj.decode[0] > 0; + imageObj.applyStencilMask(pixels, inverseDecode); } else imageObj.fillRgbaBuffer(pixels); @@ -5990,26 +6003,26 @@ var PDFImage = (function() { } return buf; }, - fillUsingStencilMask: function fillUsingStencilMask(buffer, - cssRgb, inverseDecode) { - var m = /rgb\((\d+),(\d+),(\d+)\)/.exec(cssRgb); // parse CSS color - var r = m[1] | 0, g = m[2] | 0, b = m[3] | 0; - var bufferLength = this.width * this.height; - var imgArray = this.image.getBytes((bufferLength + 7) >> 3); - var i, mask; - var bufferPos = 0, imgArrayPos = 0; - for (i = 0; i < bufferLength; i++) { - var buf = imgArray[imgArrayPos++]; - for (mask = 128; mask > 0; mask >>= 1) { - if (!(buf & mask) != inverseDecode) { - buffer[bufferPos++] = r; - buffer[bufferPos++] = g; - buffer[bufferPos++] = b; - buffer[bufferPos++] = 255; - } else { - buffer[bufferPos + 3] = 0; - bufferPos += 4; + applyStencilMask: function applyStencilMask(buffer, inverseDecode) { + var width = this.width, height = this.height; + var bitStrideLength = (width + 7) >> 3; + var imgArray = this.image.getBytes(bitStrideLength * height); + var imgArrayPos = 0; + var i, j, mask, buf; + // removing making non-masked pixels transparent + var bufferPos = 3; // alpha component offset + for (i = 0; i < height; i++) { + mask = 0; + for (j = 0; j < width; j++) { + if (!mask) { + buf = imgArray[imgArrayPos++]; + mask = 128; } + if (!(buf & mask) == inverseDecode) { + buffer[bufferPos] = 0; + } + bufferPos += 4; + mask >>= 1; } } },