From: Artur Adib Date: Wed, 26 Oct 2011 19:10:58 +0000 (-0400) Subject: Merge branch 'refs/heads/master' into filesplit X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=41caf5018d455969f437b1dbcb86ef34b371234f;p=pdf.js.git Merge branch 'refs/heads/master' into filesplit Conflicts: pdf.js --- 41caf5018d455969f437b1dbcb86ef34b371234f diff --cc src/evaluator.js index 1327b3a,0000000..5007394 mode 100644,000000..100644 --- a/src/evaluator.js +++ b/src/evaluator.js @@@ -1,917 -1,0 +1,920 @@@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ + +'use strict'; + +var PartialEvaluator = (function partialEvaluator() { + function constructor(xref, handler, uniquePrefix) { + this.state = new EvalState(); + this.stateStack = []; + + this.xref = xref; + this.handler = handler; + this.uniquePrefix = uniquePrefix; + this.objIdCounter = 0; + } + + var OP_MAP = { + // Graphics state + w: 'setLineWidth', + J: 'setLineCap', + j: 'setLineJoin', + M: 'setMiterLimit', + d: 'setDash', + ri: 'setRenderingIntent', + i: 'setFlatness', + gs: 'setGState', + q: 'save', + Q: 'restore', + cm: 'transform', + + // Path + m: 'moveTo', + l: 'lineTo', + c: 'curveTo', + v: 'curveTo2', + y: 'curveTo3', + h: 'closePath', + re: 'rectangle', + S: 'stroke', + s: 'closeStroke', + f: 'fill', + F: 'fill', + 'f*': 'eoFill', + B: 'fillStroke', + 'B*': 'eoFillStroke', + b: 'closeFillStroke', + 'b*': 'closeEOFillStroke', + n: 'endPath', + + // Clipping + W: 'clip', + 'W*': 'eoClip', + + // Text + BT: 'beginText', + ET: 'endText', + Tc: 'setCharSpacing', + Tw: 'setWordSpacing', + Tz: 'setHScale', + TL: 'setLeading', + Tf: 'setFont', + Tr: 'setTextRenderingMode', + Ts: 'setTextRise', + Td: 'moveText', + TD: 'setLeadingMoveText', + Tm: 'setTextMatrix', + 'T*': 'nextLine', + Tj: 'showText', + TJ: 'showSpacedText', + "'": 'nextLineShowText', + '"': 'nextLineSetSpacingShowText', + + // Type3 fonts + d0: 'setCharWidth', + d1: 'setCharWidthAndBounds', + + // Color + CS: 'setStrokeColorSpace', + cs: 'setFillColorSpace', + SC: 'setStrokeColor', + SCN: 'setStrokeColorN', + sc: 'setFillColor', + scn: 'setFillColorN', + G: 'setStrokeGray', + g: 'setFillGray', + RG: 'setStrokeRGBColor', + rg: 'setFillRGBColor', + K: 'setStrokeCMYKColor', + k: 'setFillCMYKColor', + + // Shading + sh: 'shadingFill', + + // Images + BI: 'beginInlineImage', + ID: 'beginImageData', + EI: 'endInlineImage', + + // XObjects + Do: 'paintXObject', + + // Marked content + MP: 'markPoint', + DP: 'markPointProps', + BMC: 'beginMarkedContent', + BDC: 'beginMarkedContentProps', + EMC: 'endMarkedContent', + + // Compatibility + BX: 'beginCompat', + EX: 'endCompat' + }; + + constructor.prototype = { + getIRQueue: function partialEvaluatorGetIRQueue(stream, resources, + queue, dependency) { + + var self = this; + var xref = this.xref; + var handler = this.handler; + var uniquePrefix = this.uniquePrefix; + + function insertDependency(depList) { + fnArray.push('dependency'); + argsArray.push(depList); + for (var i = 0; i < depList.length; i++) { + var dep = depList[i]; + if (dependency.indexOf(dep) == -1) { + dependency.push(depList[i]); + } + } + } + + function handleSetFont(fontName, fontRef) { + var loadedName = null; + + var fontRes = resources.get('Font'); + + // TODO: TOASK: Is it possible to get here? If so, what does + // args[0].name should be like??? + assert(fontRes, 'fontRes not available'); + + fontRes = xref.fetchIfRef(fontRes); + fontRef = fontRef || fontRes.get(fontName); + var font = xref.fetchIfRef(fontRef); + assertWellFormed(isDict(font)); + if (!font.translated) { + font.translated = self.translateFont(font, xref, resources, handler, + uniquePrefix, dependency); + if (font.translated) { + // keep track of each font we translated so the caller can + // load them asynchronously before calling display on a page + loadedName = 'font_' + uniquePrefix + ++self.objIdCounter; + font.translated.properties.loadedName = loadedName; + font.loadedName = loadedName; + + var translated = font.translated; + handler.send('obj', [ + loadedName, + 'Font', + translated.name, + translated.file, + translated.properties + ]); + } + } + loadedName = loadedName || font.loadedName; + + // Ensure the font is ready before the font is set + // and later on used for drawing. + // TODO: This should get insert to the IRQueue only once per + // page. + insertDependency([loadedName]); + return loadedName; + } + + function buildPaintImageXObject(image, inline) { + var dict = image.dict; + var w = dict.get('Width', 'W'); + var h = dict.get('Height', 'H'); + + if (image instanceof JpegStream) { + var objId = 'img_' + uniquePrefix + ++self.objIdCounter; + handler.send('obj', [objId, 'JpegStream', image.getIR()]); + + // Add the dependency on the image object. + insertDependency([objId]); + + // The normal fn. + fn = 'paintJpegXObject'; + args = [objId, w, h]; + + return; + } + + // Needs to be rendered ourself. + + // Figure out if the image has an imageMask. + var imageMask = dict.get('ImageMask', 'IM') || false; + + // If there is no imageMask, create the PDFImage and a lot + // of image processing can be done here. + if (!imageMask) { + var imageObj = new PDFImage(xref, resources, image, inline); + + if (imageObj.imageMask) { + throw 'Can\'t handle this in the web worker :/'; + } + + var imgData = { + width: w, + height: h, + data: new Uint8Array(w * h * 4) + }; + var pixels = imgData.data; + imageObj.fillRgbaBuffer(pixels, imageObj.decode); + + fn = 'paintImageXObject'; + args = [imgData]; + return; + } + + // This depends on a tmpCanvas beeing filled with the + // current fillStyle, such that processing the pixel + // data can't be done here. Instead of creating a + // complete PDFImage, only read the information needed + // for later. + fn = 'paintImageMaskXObject'; + + var width = dict.get('Width', 'W'); + var height = dict.get('Height', 'H'); + var bitStrideLength = (width + 7) >> 3; + var imgArray = image.getBytes(bitStrideLength * height); + var decode = dict.get('Decode', 'D'); + var inverseDecode = !!decode && decode[0] > 0; + + args = [imgArray, inverseDecode, width, height]; + } + + uniquePrefix = uniquePrefix || ''; + if (!queue.argsArray) { + queue.argsArray = []; + } + if (!queue.fnArray) { + queue.fnArray = []; + } + + var fnArray = queue.fnArray, argsArray = queue.argsArray; - var dependency = dependency || []; ++ var dependencyArray = dependency || []; + + resources = xref.fetchIfRef(resources) || new Dict(); + var xobjs = xref.fetchIfRef(resources.get('XObject')) || new Dict(); + var patterns = xref.fetchIfRef(resources.get('Pattern')) || new Dict(); + var parser = new Parser(new Lexer(stream), false); + var res = resources; + var args = [], obj; + var getObjBt = function getObjBt() { + parser = this.oldParser; + return { name: 'BT' }; + }; + var TILING_PATTERN = 1, SHADING_PATTERN = 2; + + while (!isEOF(obj = parser.getObj())) { + if (isCmd(obj)) { + var cmd = obj.cmd; + var fn = OP_MAP[cmd]; + if (!fn) { + // invalid content command, trying to recover + if (cmd.substr(-2) == 'BT') { + fn = OP_MAP[cmd.substr(0, cmd.length - 2)]; + // feeding 'BT' on next interation + parser = { + getObj: getObjBt, + oldParser: parser + }; + } + } + assertWellFormed(fn, 'Unknown command "' + cmd + '"'); + // TODO figure out how to type-check vararg functions + + if ((cmd == 'SCN' || cmd == 'scn') && !args[args.length - 1].code) { + // Use the IR version for setStroke/FillColorN. + fn += '_IR'; + + // compile tiling patterns + var patternName = args[args.length - 1]; + // SCN/scn applies patterns along with normal colors + if (isName(patternName)) { + var pattern = xref.fetchIfRef(patterns.get(patternName.name)); + if (pattern) { + var dict = isStream(pattern) ? pattern.dict : pattern; + var typeNum = dict.get('PatternType'); + + if (typeNum == TILING_PATTERN) { + // Create an IR of the pattern code. - var depIdx = dependency.length; - var codeIR = this.getIRQueue(pattern, - dict.get('Resources'), {}, dependency); ++ var depIdx = dependencyArray.length; ++ var queueObj = {}; ++ var codeIR = this.getIRQueue(pattern, dict.get('Resources'), ++ queueObj, dependencyArray); + + // Add the dependencies that are required to execute the + // codeIR. - insertDependency(dependency.slice(depIdx)); ++ insertDependency(dependencyArray.slice(depIdx)); + + args = TilingPattern.getIR(codeIR, dict, args); + } + else if (typeNum == SHADING_PATTERN) { + var shading = xref.fetchIfRef(dict.get('Shading')); + var matrix = dict.get('Matrix'); + var pattern = Pattern.parseShading(shading, matrix, xref, res, + null /*ctx*/); + args = pattern.getIR(); + } else { + error('Unkown PatternType ' + typeNum); + } + } + } + } else if (cmd == 'Do' && !args[0].code) { + // eagerly compile XForm objects + var name = args[0].name; + var xobj = xobjs.get(name); + if (xobj) { + xobj = xref.fetchIfRef(xobj); + assertWellFormed(isStream(xobj), 'XObject should be a stream'); + + var type = xobj.dict.get('Subtype'); + assertWellFormed( + isName(type), + 'XObject should have a Name subtype' + ); + + if ('Form' == type.name) { + var matrix = xobj.dict.get('Matrix'); + var bbox = xobj.dict.get('BBox'); + + fnArray.push('paintFormXObjectBegin'); + argsArray.push([matrix, bbox]); + + // This adds the IRQueue of the xObj to the current queue. - var depIdx = dependency.length; ++ var depIdx = dependencyArray.length; + + this.getIRQueue(xobj, xobj.dict.get('Resources'), queue, - dependency); ++ dependencyArray); + + // Add the dependencies that are required to execute the + // codeIR. - insertDependency(dependency.slice(depIdx)); ++ insertDependency(dependencyArray.slice(depIdx)); + + fn = 'paintFormXObjectEnd'; + args = []; + } else if ('Image' == type.name) { + buildPaintImageXObject(xobj, false); + } else { + error('Unhandled XObject subtype ' + type.name); + } + } + } else if (cmd == 'Tf') { // eagerly collect all fonts + args[0] = handleSetFont(args[0].name); + } else if (cmd == 'EI') { + buildPaintImageXObject(args[0], true); + } + + switch (fn) { + // Parse the ColorSpace data to a raw format. + case 'setFillColorSpace': + case 'setStrokeColorSpace': + args = [ColorSpace.parseToIR(args[0], xref, resources)]; + break; + case 'shadingFill': + var shadingRes = xref.fetchIfRef(res.get('Shading')); + if (!shadingRes) + error('No shading resource found'); + + var shading = xref.fetchIfRef(shadingRes.get(args[0].name)); + if (!shading) + error('No shading object found'); + + var shadingFill = Pattern.parseShading(shading, null, xref, res, + null); + var patternIR = shadingFill.getIR(); + args = [patternIR]; + fn = 'shadingFill'; + break; + case 'setGState': + var dictName = args[0]; + var extGState = xref.fetchIfRef(resources.get('ExtGState')); + + if (!isDict(extGState) || !extGState.has(dictName.name)) + break; + + var gsState = xref.fetchIfRef(extGState.get(dictName.name)); + + // This array holds the converted/processed state data. + var gsStateObj = []; + + gsState.forEach( + function canvasGraphicsSetGStateForEach(key, value) { + switch (key) { + case 'Type': + break; + case 'LW': + case 'LC': + case 'LJ': + case 'ML': + case 'D': + case 'RI': + case 'FL': + gsStateObj.push([key, value]); + break; + case 'Font': + gsStateObj.push([ + 'Font', + handleSetFont(null, value[0]), + value[1] + ]); + break; + case 'OP': + case 'op': + case 'OPM': + case 'BG': + case 'BG2': + case 'UCR': + case 'UCR2': + case 'TR': + case 'TR2': + case 'HT': + case 'SM': + case 'SA': + case 'BM': + case 'SMask': + case 'CA': + case 'ca': + case 'AIS': + case 'TK': + TODO('graphic state operator ' + key); + break; + default: + warn('Unknown graphic state operator ' + key); + break; + } + } + ); + args = [gsStateObj]; + break; + } // switch + + fnArray.push(fn); + argsArray.push(args); + args = []; + } else if (obj != null) { + assertWellFormed(args.length <= 33, 'Too many arguments'); + args.push(obj); + } + } + + return { + fnArray: fnArray, + argsArray: argsArray + }; + }, + + extractEncoding: function partialEvaluatorExtractEncoding(dict, + xref, + properties) { + var type = properties.type, encoding; + if (properties.composite) { + var defaultWidth = xref.fetchIfRef(dict.get('DW')) || 1000; + properties.defaultWidth = defaultWidth; + + var glyphsWidths = {}; + var widths = xref.fetchIfRef(dict.get('W')); + if (widths) { + var start = 0, end = 0; + for (var i = 0; i < widths.length; i++) { + var code = widths[i]; + if (isArray(code)) { + for (var j = 0; j < code.length; j++) + glyphsWidths[start++] = code[j]; + start = 0; + } else if (start) { + var width = widths[++i]; + for (var j = start; j <= code; j++) + glyphsWidths[j] = width; + start = 0; + } else { + start = code; + } + } + } + properties.widths = glyphsWidths; + + // Glyph ids are big-endian 2-byte values + encoding = properties.encoding; + + // CIDSystemInfo might help to match width and glyphs + var cidSystemInfo = dict.get('CIDSystemInfo'); + if (isDict(cidSystemInfo)) { + properties.cidSystemInfo = { + registry: cidSystemInfo.get('Registry'), + ordering: cidSystemInfo.get('Ordering'), + supplement: cidSystemInfo.get('Supplement') + }; + } + + var cidToGidMap = dict.get('CIDToGIDMap'); + if (!cidToGidMap || !isRef(cidToGidMap)) { + + + return Object.create(GlyphsUnicode); + } + + // Extract the encoding from the CIDToGIDMap + var glyphsStream = xref.fetchIfRef(cidToGidMap); + var glyphsData = glyphsStream.getBytes(0); + + // Set encoding 0 to later verify the font has an encoding + encoding[0] = { unicode: 0, width: 0 }; + for (var j = 0; j < glyphsData.length; j++) { + var glyphID = (glyphsData[j++] << 8) | glyphsData[j]; + if (glyphID == 0) + continue; + + var code = j >> 1; + var width = glyphsWidths[code]; + encoding[code] = { + unicode: glyphID, + width: isNum(width) ? width : defaultWidth + }; + } + + return Object.create(GlyphsUnicode); + } + + var differences = properties.differences; + var map = properties.encoding; + var baseEncoding = null; + if (dict.has('Encoding')) { + encoding = xref.fetchIfRef(dict.get('Encoding')); + if (isDict(encoding)) { + var baseName = encoding.get('BaseEncoding'); + if (baseName) + baseEncoding = Encodings[baseName.name].slice(); + + // Load the differences between the base and original + if (encoding.has('Differences')) { + var diffEncoding = encoding.get('Differences'); + var index = 0; + for (var j = 0; j < diffEncoding.length; j++) { + var data = diffEncoding[j]; + if (isNum(data)) + index = data; + else + differences[index++] = data.name; + } + } + } else if (isName(encoding)) { + baseEncoding = Encodings[encoding.name].slice(); + } else { + error('Encoding is not a Name nor a Dict'); + } + } + + if (!baseEncoding) { + switch (type) { + case 'TrueType': + baseEncoding = Encodings.WinAnsiEncoding.slice(); + break; + case 'Type1': + case 'Type3': + baseEncoding = Encodings.StandardEncoding.slice(); + break; + default: + warn('Unknown type of font: ' + type); + baseEncoding = []; + break; + } + } + + // merge in the differences + var firstChar = properties.firstChar; + var lastChar = properties.lastChar; + var widths = properties.widths || []; + var glyphs = {}; + for (var i = firstChar; i <= lastChar; i++) { + var glyph = differences[i]; + var replaceGlyph = true; + if (!glyph) { + glyph = baseEncoding[i] || i; + replaceGlyph = false; + } + var index = GlyphsUnicode[glyph] || i; + var width = widths[i] || widths[glyph]; + map[i] = { + unicode: index, + width: isNum(width) ? width : properties.defaultWidth + }; + + if (replaceGlyph || !glyphs[glyph]) + glyphs[glyph] = map[i]; + if (replaceGlyph || !glyphs[index]) + glyphs[index] = map[i]; + + // If there is no file, the character mapping can't be modified + // but this is unlikely that there is any standard encoding with + // chars below 0x1f, so that's fine. + if (!properties.file) + continue; + + if (index <= 0x1f || (index >= 127 && index <= 255)) + map[i].unicode += kCmapGlyphOffset; + } + + if (type == 'TrueType' && dict.has('ToUnicode') && differences) { + var cmapObj = dict.get('ToUnicode'); + if (isRef(cmapObj)) { + cmapObj = xref.fetch(cmapObj); + } + if (isName(cmapObj)) { + error('ToUnicode file cmap translation not implemented'); + } else if (isStream(cmapObj)) { + var tokens = []; + var token = ''; + var beginArrayToken = {}; + + var cmap = cmapObj.getBytes(cmapObj.length); + for (var i = 0; i < cmap.length; i++) { + var byte = cmap[i]; + if (byte == 0x20 || byte == 0x0D || byte == 0x0A || + byte == 0x3C || byte == 0x5B || byte == 0x5D) { + switch (token) { + case 'usecmap': + error('usecmap is not implemented'); + break; + + case 'beginbfchar': + case 'beginbfrange': + case 'begincidchar': + case 'begincidrange': + token = ''; + tokens = []; + break; + + case 'endcidrange': + case 'endbfrange': + for (var j = 0; j < tokens.length; j += 3) { + var startRange = tokens[j]; + var endRange = tokens[j + 1]; + var code = tokens[j + 2]; + while (startRange < endRange) { + var mapping = map[startRange] || {}; + mapping.unicode = code++; + map[startRange] = mapping; + ++startRange; + } + } + break; + + case 'endcidchar': + case 'endbfchar': + for (var j = 0; j < tokens.length; j += 2) { + var index = tokens[j]; + var code = tokens[j + 1]; + var mapping = map[index] || {}; + mapping.unicode = code; + map[index] = mapping; + } + break; + + case '': + break; + + default: + if (token[0] >= '0' && token[0] <= '9') + token = parseInt(token, 10); // a number + tokens.push(token); + token = ''; + } + switch (byte) { + case 0x5B: + // begin list parsing + tokens.push(beginArrayToken); + break; + case 0x5D: + // collect array items + var items = [], item; + while (tokens.length && + (item = tokens.pop()) != beginArrayToken) + items.unshift(item); + tokens.push(items); + break; + } + } else if (byte == 0x3E) { + if (token.length) { + // parsing hex number + tokens.push(parseInt(token, 16)); + token = ''; + } + } else { + token += String.fromCharCode(byte); + } + } + } + } + return glyphs; + }, + + getBaseFontMetricsAndMap: function getBaseFontMetricsAndMap(name) { + var map = {}; + if (/^Symbol(-?(Bold|Italic))*$/.test(name)) { + // special case for symbols + var encoding = Encodings.symbolsEncoding.slice(); + for (var i = 0, n = encoding.length, j; i < n; i++) { + if (!(j = encoding[i])) + continue; + map[i] = GlyphsUnicode[j] || 0; + } + } + + var defaultWidth = 0; + var widths = Metrics[stdFontMap[name] || name]; + if (isNum(widths)) { + defaultWidth = widths; + widths = null; + } + + return { + defaultWidth: defaultWidth, + widths: widths || [], + map: map + }; + }, + + translateFont: function partialEvaluatorTranslateFont(dict, xref, resources, + queue, handler, uniquePrefix, dependency) { + var baseDict = dict; + var type = dict.get('Subtype'); + assertWellFormed(isName(type), 'invalid font Subtype'); + + var composite = false; + if (type.name == 'Type0') { + // If font is a composite + // - get the descendant font + // - set the type according to the descendant font + // - get the FontDescriptor from the descendant font + var df = dict.get('DescendantFonts'); + if (!df) + return null; + + if (isRef(df)) + df = xref.fetch(df); + + dict = xref.fetchIfRef(isRef(df) ? df : df[0]); + + type = dict.get('Subtype'); + assertWellFormed(isName(type), 'invalid font Subtype'); + composite = true; + } + + var descriptor = xref.fetchIfRef(dict.get('FontDescriptor')); + if (!descriptor) { + if (type.name == 'Type3') { + // FontDescriptor is only required for Type3 fonts when the document + // is a tagged pdf. Create a barbebones one to get by. + descriptor = new Dict(); + descriptor.set('FontName', new Name(type.name)); + } else { + // Before PDF 1.5 if the font was one of the base 14 fonts, having a + // FontDescriptor was not required. + // This case is here for compatibility. + var baseFontName = dict.get('BaseFont'); + if (!isName(baseFontName)) + return null; + + // Using base font name as a font name. + baseFontName = baseFontName.name.replace(/[,_]/g, '-'); + var metricsAndMap = this.getBaseFontMetricsAndMap(baseFontName); + + var properties = { + type: type.name, + encoding: metricsAndMap.map, + differences: [], + widths: metricsAndMap.widths, + defaultWidth: metricsAndMap.defaultWidth, + firstChar: 0, + lastChar: 256 + }; + this.extractEncoding(dict, xref, properties); + + return { + name: baseFontName, + dict: baseDict, + properties: properties + }; + } + + } + + // According to the spec if 'FontDescriptor' is declared, 'FirstChar', + // 'LastChar' and 'Widths' should exists too, but some PDF encoders seems + // to ignore this rule when a variant of a standart font is used. + // TODO Fill the width array depending on which of the base font this is + // a variant. + var firstChar = xref.fetchIfRef(dict.get('FirstChar')) || 0; + var lastChar = xref.fetchIfRef(dict.get('LastChar')) || 256; + var defaultWidth = 0; + var glyphWidths = {}; + var encoding = {}; + var widths = xref.fetchIfRef(dict.get('Widths')); + if (widths) { + for (var i = 0, j = firstChar; i < widths.length; i++, j++) + glyphWidths[j] = widths[i]; + defaultWidth = parseFloat(descriptor.get('MissingWidth')) || 0; + } else { + // Trying get the BaseFont metrics (see comment above). + var baseFontName = dict.get('BaseFont'); + if (isName(baseFontName)) { + var metricsAndMap = this.getBaseFontMetricsAndMap(baseFontName.name); + + glyphWidths = metricsAndMap.widths; + defaultWidth = metricsAndMap.defaultWidth; + encoding = metricsAndMap.map; + } + } + + var fontName = xref.fetchIfRef(descriptor.get('FontName')); + assertWellFormed(isName(fontName), 'invalid font name'); + + var fontFile = descriptor.get('FontFile', 'FontFile2', 'FontFile3'); + if (fontFile) { + fontFile = xref.fetchIfRef(fontFile); + if (fontFile.dict) { + var subtype = fontFile.dict.get('Subtype'); + if (subtype) + subtype = subtype.name; + + var length1 = fontFile.dict.get('Length1'); + if (!isInt(length1)) + length1 = xref.fetchIfRef(length1); + + var length2 = fontFile.dict.get('Length2'); + if (!isInt(length2)) + length2 = xref.fetchIfRef(length2); + } + } + + var properties = { + type: type.name, + subtype: subtype, + file: fontFile, + length1: length1, + length2: length2, + composite: composite, + fixedPitch: false, + fontMatrix: dict.get('FontMatrix') || IDENTITY_MATRIX, + firstChar: firstChar || 0, + lastChar: lastChar || 256, + bbox: descriptor.get('FontBBox'), + ascent: descriptor.get('Ascent'), + descent: descriptor.get('Descent'), + xHeight: descriptor.get('XHeight'), + capHeight: descriptor.get('CapHeight'), + defaultWidth: defaultWidth, + flags: descriptor.get('Flags'), + italicAngle: descriptor.get('ItalicAngle'), + differences: [], + widths: glyphWidths, + encoding: encoding, + coded: false + }; + properties.glyphs = this.extractEncoding(dict, xref, properties); + + if (type.name === 'Type3') { + properties.coded = true; + var charProcs = xref.fetchIfRef(dict.get('CharProcs')); + var fontResources = xref.fetchIfRef(dict.get('Resources')) || resources; + properties.resources = fontResources; + for (var key in charProcs.map) { + var glyphStream = xref.fetchIfRef(charProcs.map[key]); - var queue = {}; ++ var queueObj = {}; + properties.glyphs[key].IRQueue = this.getIRQueue(glyphStream, - fontResources, queue, dependency); ++ fontResources, ++ queueObj, ++ dependency); + } + } + + return { + name: fontName.name, + dict: baseDict, + file: fontFile, + properties: properties + }; + } + }; + + return constructor; +})(); + +var EvalState = (function evalState() { + function constructor() { + // Are soft masks and alpha values shapes or opacities? + this.alphaIsShape = false; + this.fontSize = 0; + this.textMatrix = IDENTITY_MATRIX; + this.leading = 0; + // Start of text line (in text coordinates) + this.lineX = 0; + this.lineY = 0; + // Character and word spacing + this.charSpacing = 0; + this.wordSpacing = 0; + this.textHScale = 1; + // Color spaces + this.fillColorSpace = null; + this.strokeColorSpace = null; + } + constructor.prototype = { + }; + return constructor; +})(); diff --cc src/fonts.js index 1663fe7,0000000..f123b5f mode 100644,000000..100644 --- a/src/fonts.js +++ b/src/fonts.js @@@ -1,3273 -1,0 +1,3274 @@@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ + +'use strict'; + +var isWorker = (typeof window == 'undefined'); + +/** + * Maximum time to wait for a font to be loaded by font-face rules. + */ +var kMaxWaitForFontFace = 1000; + +// Unicode Private Use Area +var kCmapGlyphOffset = 0xE000; +var kSizeOfGlyphArea = 0x1900; + +// PDF Glyph Space Units are one Thousandth of a TextSpace Unit +// except for Type 3 fonts +var kPDFGlyphSpaceUnits = 1000; + +// Until hinting is fully supported this constant can be used +var kHintingEnabled = false; + +var Encodings = { + get ExpertEncoding() { + return shadow(this, 'ExpertEncoding', ['', '', '', '', '', '', '', '', '', + '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', + '', '', '', '', '', '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' + ]); + }, + get MacExpertEncoding() { + return shadow(this, 'MacExpertEncoding', ['', '', '', '', '', '', '', '', + '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', + '', '', '', '', '', '', 'space', 'exclamsmall', 'Hungarumlautsmall', + 'centoldstyle', 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', + 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', + 'twodotenleader', 'onedotenleader', 'comma', 'hyphen', 'period', + 'fraction', 'zerooldstyle', 'oneoldstyle', 'twooldstyle', + 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', + 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', + '', 'threequartersemdash', '', 'questionsmall', '', '', '', '', + 'Ethsmall', '', '', 'onequarter', 'onehalf', 'threequarters', + 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', + 'twothirds', '', '', '', '', '', '', 'ff', 'fi', 'fl', 'ffi', 'ffl', + 'parenleftinferior', '', 'parenrightinferior', 'Circumflexsmall', + 'hypheninferior', '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', '', '', + 'asuperior', 'centsuperior', '', '', '', '', 'Aacutesmall', + 'Agravesmall', 'Acircumflexsmall', 'Adieresissmall', 'Atildesmall', + 'Aringsmall', 'Ccedillasmall', 'Eacutesmall', 'Egravesmall', + 'Ecircumflexsmall', 'Edieresissmall', 'Iacutesmall', 'Igravesmall', + 'Icircumflexsmall', 'Idieresissmall', 'Ntildesmall', 'Oacutesmall', + 'Ogravesmall', 'Ocircumflexsmall', 'Odieresissmall', 'Otildesmall', + 'Uacutesmall', 'Ugravesmall', 'Ucircumflexsmall', 'Udieresissmall', '', + 'eightsuperior', 'fourinferior', 'threeinferior', 'sixinferior', + 'eightinferior', 'seveninferior', 'Scaronsmall', '', 'centinferior', + 'twoinferior', '', 'Dieresissmall', '', 'Caronsmall', 'osuperior', + 'fiveinferior', '', 'commainferior', 'periodinferior', 'Yacutesmall', '', + 'dollarinferior', '', 'Thornsmall', '', 'nineinferior', 'zeroinferior', + 'Zcaronsmall', 'AEsmall', 'Oslashsmall', 'questiondownsmall', + 'oneinferior', 'Lslashsmall', '', '', '', '', '', '', 'Cedillasmall', '', + '', '', '', '', 'OEsmall', 'figuredash', 'hyphensuperior', '', '', '', + '', 'exclamdownsmall', '', 'Ydieresissmall', '', 'onesuperior', + 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior', + 'sixsuperior', 'sevensuperior', 'ninesuperior', 'zerosuperior', '', + 'esuperior', 'rsuperior', 'tsuperior', '', '', 'isuperior', 'ssuperior', + 'dsuperior', '', '', '', '', '', 'lsuperior', 'Ogoneksmall', + 'Brevesmall', 'Macronsmall', 'bsuperior', 'nsuperior', 'msuperior', + 'commasuperior', 'periodsuperior', 'Dotaccentsmall', 'Ringsmall' + ]); + }, + get MacRomanEncoding() { + return shadow(this, 'MacRomanEncoding', ['', '', '', '', '', '', '', '', + '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', + '', '', '', '', '', '', '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', 'space', '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' + ]); + }, + get StandardEncoding() { + return shadow(this, 'StandardEncoding', ['', '', '', '', '', '', '', '', + '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', + '', '', '', '', '', '', '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' + ]); + }, + get WinAnsiEncoding() { + return shadow(this, 'WinAnsiEncoding', ['', '', '', '', '', '', '', '', '', + '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', + '', '', '', '', '', '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', 'bullet', 'Euro', + 'bullet', 'quotesinglbase', 'florin', 'quotedblbase', 'ellipsis', + 'dagger', 'daggerdbl', 'circumflex', 'perthousand', 'Scaron', + 'guilsinglleft', 'OE', 'bullet', 'Zcaron', 'bullet', 'bullet', + 'quoteleft', 'quoteright', 'quotedblleft', 'quotedblright', 'bullet', + 'endash', 'emdash', 'tilde', 'trademark', 'scaron', 'guilsinglright', + 'oe', 'bullet', 'zcaron', 'Ydieresis', 'space', 'exclamdown', 'cent', + 'sterling', 'currency', 'yen', 'brokenbar', 'section', 'dieresis', + 'copyright', 'ordfeminine', 'guillemotleft', 'logicalnot', 'hyphen', + 'registered', 'macron', 'degree', 'plusminus', 'twosuperior', + 'threesuperior', 'acute', 'mu', 'paragraph', 'periodcentered', + 'cedilla', 'onesuperior', 'ordmasculine', 'guillemotright', 'onequarter', + 'onehalf', 'threequarters', 'questiondown', 'Agrave', 'Aacute', + 'Acircumflex', 'Atilde', 'Adieresis', 'Aring', 'AE', 'Ccedilla', + 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', 'Igrave', 'Iacute', + 'Icircumflex', 'Idieresis', 'Eth', 'Ntilde', 'Ograve', 'Oacute', + 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', 'Oslash', 'Ugrave', + 'Uacute', 'Ucircumflex', 'Udieresis', 'Yacute', 'Thorn', 'germandbls', + 'agrave', 'aacute', 'acircumflex', 'atilde', 'adieresis', 'aring', 'ae', + 'ccedilla', 'egrave', 'eacute', 'ecircumflex', 'edieresis', 'igrave', + 'iacute', 'icircumflex', 'idieresis', 'eth', 'ntilde', 'ograve', + 'oacute', 'ocircumflex', 'otilde', 'odieresis', 'divide', 'oslash', + 'ugrave', 'uacute', 'ucircumflex', 'udieresis', 'yacute', 'thorn', + 'ydieresis' + ]); + }, + get symbolsEncoding() { + return shadow(this, 'symbolsEncoding', ['', '', '', '', '', '', '', '', '', + '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', + '', '', '', '', '', 'space', 'exclam', 'universal', 'numbersign', + 'existential', 'percent', 'ampersand', 'suchthat', 'parenleft', + 'parenright', 'asteriskmath', 'plus', 'comma', 'minus', 'period', + 'slash', 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', + 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', + 'question', 'congruent', 'Alpha', 'Beta', 'Chi', 'Delta', 'Epsilon', + 'Phi', 'Gamma', 'Eta', 'Iota', 'theta1', 'Kappa', 'Lambda', 'Mu', 'Nu', + 'Omicron', 'Pi', 'Theta', 'Rho', 'Sigma', 'Tau', 'Upsilon', 'sigma1', + 'Omega', 'Xi', 'Psi', 'Zeta', 'bracketleft', 'therefore', 'bracketright', + 'perpendicular', 'underscore', 'radicalex', 'alpha', 'beta', 'chi', + 'delta', 'epsilon', 'phi', 'gamma', 'eta', 'iota', 'phi1', 'kappa', + 'lambda', 'mu', 'nu', 'omicron', 'pi', 'theta', 'rho', 'sigma', 'tau', + 'upsilon', 'omega1', 'omega', 'xi', 'psi', 'zeta', 'braceleft', 'bar', + 'braceright', 'similar', '', '', '', '', '', '', '', '', '', '', '', '', + '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', + '', '', '', 'Euro', 'Upsilon1', 'minute', 'lessequal', 'fraction', + 'infinity', 'florin', 'club', 'diamond', 'heart', 'spade', 'arrowboth', + 'arrowleft', 'arrowup', 'arrowright', 'arrowdown', 'degree', 'plusminus', + 'second', 'greaterequal', 'multiply', 'proportional', 'partialdiff', + 'bullet', 'divide', 'notequal', 'equivalence', 'approxequal', 'ellipsis', + 'arrowvertex', 'arrowhorizex', 'carriagereturn', 'aleph', 'Ifraktur', + 'Rfraktur', 'weierstrass', 'circlemultiply', 'circleplus', 'emptyset', + 'intersection', 'union', 'propersuperset', 'reflexsuperset', 'notsubset', + 'propersubset', 'reflexsubset', 'element', 'notelement', 'angle', + 'gradient', 'registerserif', 'copyrightserif', 'trademarkserif', + 'product', 'radical', 'dotmath', 'logicalnot', 'logicaland', 'logicalor', + 'arrowdblboth', 'arrowdblleft', 'arrowdblup', 'arrowdblright', + 'arrowdbldown', 'lozenge', 'angleleft', 'registersans', 'copyrightsans', + 'trademarksans', 'summation', 'parenlefttp', 'parenleftex', + 'parenleftbt', 'bracketlefttp', 'bracketleftex', 'bracketleftbt', + 'bracelefttp', 'braceleftmid', 'braceleftbt', 'braceex', '', + 'angleright', 'integral', 'integraltp', 'integralex', 'integralbt', + 'parenrighttp', 'parenrightex', 'parenrightbt', 'bracketrighttp', + 'bracketrightex', 'bracketrightbt', 'bracerighttp', 'bracerightmid', + 'bracerightbt' + ]); + }, + get zapfDingbatsEncoding() { + return shadow(this, 'zapfDingbatsEncoding', ['', '', '', '', '', '', '', + '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', + '', '', '', '', '', '', '', 'space', 'a1', 'a2', 'a202', 'a3', 'a4', + 'a5', 'a119', 'a118', 'a117', 'a11', 'a12', 'a13', 'a14', 'a15', 'a16', + 'a105', 'a17', 'a18', 'a19', 'a20', 'a21', 'a22', 'a23', 'a24', 'a25', + 'a26', 'a27', 'a28', 'a6', 'a7', 'a8', 'a9', 'a10', 'a29', 'a30', 'a31', + 'a32', 'a33', 'a34', 'a35', 'a36', 'a37', 'a38', 'a39', 'a40', 'a41', + 'a42', 'a43', 'a44', 'a45', 'a46', 'a47', 'a48', 'a49', 'a50', 'a51', + 'a52', 'a53', 'a54', 'a55', 'a56', 'a57', 'a58', 'a59', 'a60', 'a61', + 'a62', 'a63', 'a64', 'a65', 'a66', 'a67', 'a68', 'a69', 'a70', 'a71', + 'a72', 'a73', 'a74', 'a203', 'a75', 'a204', 'a76', 'a77', 'a78', 'a79', + 'a81', 'a82', 'a83', 'a84', 'a97', 'a98', 'a99', 'a100', '', '', '', '', + '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', + '', '', '', '', '', '', '', '', '', '', '', '', 'a101', 'a102', 'a103', + 'a104', 'a106', 'a107', 'a108', 'a112', 'a111', 'a110', 'a109', 'a120', + 'a121', 'a122', 'a123', 'a124', 'a125', 'a126', 'a127', 'a128', 'a129', + 'a130', 'a131', 'a132', 'a133', 'a134', 'a135', 'a136', 'a137', 'a138', + 'a139', 'a140', 'a141', 'a142', 'a143', 'a144', 'a145', 'a146', 'a147', + 'a148', 'a149', 'a150', 'a151', 'a152', 'a153', 'a154', 'a155', 'a156', + 'a157', 'a158', 'a159', 'a160', 'a161', 'a163', 'a164', 'a196', 'a165', + 'a192', 'a166', 'a167', 'a168', 'a169', 'a170', 'a171', 'a172', 'a173', + 'a162', 'a174', 'a175', 'a176', 'a177', 'a178', 'a179', 'a193', 'a180', + 'a199', 'a181', 'a200', 'a182', '', 'a201', 'a183', 'a184', 'a197', + 'a185', 'a194', 'a198', 'a186', 'a195', 'a187', 'a188', 'a189', 'a190', + 'a191' + ]); + } +}; + +/** + * Hold a map of decoded fonts and of the standard fourteen Type1 + * fonts and their acronyms. + */ +var stdFontMap = { + 'ArialNarrow': 'Helvetica', + 'ArialNarrow-Bold': 'Helvetica-Bold', + 'ArialNarrow-BoldItalic': 'Helvetica-BoldOblique', + 'ArialNarrow-Italic': 'Helvetica-Oblique', + 'ArialBlack': 'Helvetica', + 'ArialBlack-Bold': 'Helvetica-Bold', + 'ArialBlack-BoldItalic': 'Helvetica-BoldOblique', + 'ArialBlack-Italic': 'Helvetica-Oblique', + 'Arial': 'Helvetica', + 'Arial-Bold': 'Helvetica-Bold', + 'Arial-BoldItalic': 'Helvetica-BoldOblique', + 'Arial-Italic': 'Helvetica-Oblique', + 'Arial-BoldItalicMT': 'Helvetica-BoldOblique', + 'Arial-BoldMT': 'Helvetica-Bold', + 'Arial-ItalicMT': 'Helvetica-Oblique', + 'ArialMT': 'Helvetica', + 'Courier-Bold': 'Courier-Bold', + 'Courier-BoldItalic': 'Courier-BoldOblique', + 'Courier-Italic': 'Courier-Oblique', + 'CourierNew': 'Courier', + 'CourierNew-Bold': 'Courier-Bold', + 'CourierNew-BoldItalic': 'Courier-BoldOblique', + 'CourierNew-Italic': 'Courier-Oblique', + 'CourierNewPS-BoldItalicMT': 'Courier-BoldOblique', + 'CourierNewPS-BoldMT': 'Courier-Bold', + 'CourierNewPS-ItalicMT': 'Courier-Oblique', + 'CourierNewPSMT': 'Courier', + 'Helvetica-Bold': 'Helvetica-Bold', + 'Helvetica-BoldItalic': 'Helvetica-BoldOblique', + 'Helvetica-Italic': 'Helvetica-Oblique', + 'Symbol-Bold': 'Symbol', + 'Symbol-BoldItalic': 'Symbol', + 'Symbol-Italic': 'Symbol', + 'TimesNewRoman': 'Times-Roman', + 'TimesNewRoman-Bold': 'Times-Bold', + 'TimesNewRoman-BoldItalic': 'Times-BoldItalic', + 'TimesNewRoman-Italic': 'Times-Italic', + 'TimesNewRomanPS': 'Times-Roman', + 'TimesNewRomanPS-Bold': 'Times-Bold', + 'TimesNewRomanPS-BoldItalic': 'Times-BoldItalic', + 'TimesNewRomanPS-BoldItalicMT': 'Times-BoldItalic', + 'TimesNewRomanPS-BoldMT': 'Times-Bold', + 'TimesNewRomanPS-Italic': 'Times-Italic', + 'TimesNewRomanPS-ItalicMT': 'Times-Italic', + 'TimesNewRomanPSMT': 'Times-Roman', + 'TimesNewRomanPSMT-Bold': 'Times-Bold', + 'TimesNewRomanPSMT-BoldItalic': 'Times-BoldItalic', + 'TimesNewRomanPSMT-Italic': 'Times-Italic' +}; + +var serifFonts = { + 'Adobe Jenson': true, 'Adobe Text': true, 'Albertus': true, + 'Aldus': true, 'Alexandria': true, 'Algerian': true, + 'American Typewriter': true, 'Antiqua': true, 'Apex': true, + 'Arno': true, 'Aster': true, 'Aurora': true, + 'Baskerville': true, 'Bell': true, 'Bembo': true, + 'Bembo Schoolbook': true, 'Benguiat': true, 'Berkeley Old Style': true, + 'Bernhard Modern': true, 'Berthold City': true, 'Bodoni': true, + 'Bauer Bodoni': true, 'Book Antiqua': true, 'Bookman': true, + 'Bordeaux Roman': true, 'Californian FB': true, 'Calisto': true, + 'Calvert': true, 'Capitals': true, 'Cambria': true, + 'Cartier': true, 'Caslon': true, 'Catull': true, + 'Centaur': true, 'Century Old Style': true, 'Century Schoolbook': true, + 'Chaparral': true, 'Charis SIL': true, 'Cheltenham': true, + 'Cholla Slab': true, 'Clarendon': true, 'Clearface': true, + 'Cochin': true, 'Colonna': true, 'Computer Modern': true, + 'Concrete Roman': true, 'Constantia': true, 'Cooper Black': true, + 'Corona': true, 'Ecotype': true, 'Egyptienne': true, + 'Elephant': true, 'Excelsior': true, 'Fairfield': true, + 'FF Scala': true, 'Folkard': true, 'Footlight': true, + 'FreeSerif': true, 'Friz Quadrata': true, 'Garamond': true, + 'Gentium': true, 'Georgia': true, 'Gloucester': true, + 'Goudy Old Style': true, 'Goudy Schoolbook': true, 'Goudy Pro Font': true, + 'Granjon': true, 'Guardian Egyptian': true, 'Heather': true, + 'Hercules': true, 'High Tower Text': true, 'Hiroshige': true, + 'Hoefler Text': true, 'Humana Serif': true, 'Imprint': true, + 'Ionic No. 5': true, 'Janson': true, 'Joanna': true, + 'Korinna': true, 'Lexicon': true, 'Liberation Serif': true, + 'Linux Libertine': true, 'Literaturnaya': true, 'Lucida': true, + 'Lucida Bright': true, 'Melior': true, 'Memphis': true, + 'Miller': true, 'Minion': true, 'Modern': true, + 'Mona Lisa': true, 'Mrs Eaves': true, 'MS Serif': true, + 'Museo Slab': true, 'New York': true, 'Nimbus Roman': true, + 'NPS Rawlinson Roadway': true, 'Palatino': true, 'Perpetua': true, + 'Plantin': true, 'Plantin Schoolbook': true, 'Playbill': true, + 'Poor Richard': true, 'Rawlinson Roadway': true, 'Renault': true, + 'Requiem': true, 'Rockwell': true, 'Roman': true, + 'Rotis Serif': true, 'Sabon': true, 'Scala': true, + 'Seagull': true, 'Sistina': true, 'Souvenir': true, + 'STIX': true, 'Stone Informal': true, 'Stone Serif': true, + 'Sylfaen': true, 'Times': true, 'Trajan': true, + 'Trinité': true, 'Trump Mediaeval': true, 'Utopia': true, + 'Vale Type': true, 'Bitstream Vera': true, 'Vera Serif': true, + 'Versailles': true, 'Wanted': true, 'Weiss': true, + 'Wide Latin': true, 'Windsor': true, 'XITS': true +}; + +var FontLoader = { + listeningForFontLoad: false, + + bind: function fontLoaderBind(fonts, callback) { + function checkFontsLoaded() { + for (var i = 0; i < objs.length; i++) { + var fontObj = objs[i]; + if (fontObj.loading) { + return false; + } + } + + document.documentElement.removeEventListener( + 'pdfjsFontLoad', checkFontsLoaded, false); + + callback(); + return true; + } + + var rules = [], names = [], objs = []; + + for (var i = 0; i < fonts.length; i++) { + var font = fonts[i]; + + // If there is already a fontObj on the font, then it was loaded/attached + // to the page already and we don't have to do anything for this font + // here future. + if (font.fontObj) { + continue; + } + + var obj = new Font(font.name, font.file, font.properties); + + // Store the fontObj on the font such that `setFont` in CanvasGraphics + // can reuse it later again. + font.fontObj = obj; + + objs.push(obj); + + var str = ''; + var data = obj.data; + if (data) { + var length = data.length; + for (var j = 0; j < length; j++) + str += String.fromCharCode(data[j]); + + var rule = isWorker ? obj.bindWorker(str) : obj.bindDOM(str); + if (rule) { + rules.push(rule); + names.push(obj.loadedName); + } + } + } + + this.listeningForFontLoad = false; + if (!isWorker && rules.length) { + FontLoader.prepareFontLoadEvent(rules, names, objs); + } + + if (!checkFontsLoaded()) { + document.documentElement.addEventListener( + 'pdfjsFontLoad', checkFontsLoaded, false); + } + + return objs; + }, + // Set things up so that at least one pdfjsFontLoad event is + // dispatched when all the @font-face |rules| for |names| have been + // 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 fontLoaderPrepareFontLoadEvent(rules, names, + objs) { + /** 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 + // ready. This code will be obsoleted by Mozilla bug 471915. + // + // The only reliable way to know if a font is loaded in Gecko + // (at the moment) is document.onload in a document with + // a @font-face rule defined in a "static" stylesheet. We use a + // subdocument in an