diff --git a/LICENSE b/LICENSE index d96b927a3..f8a848205 100644 --- a/LICENSE +++ b/LICENSE @@ -8,6 +8,7 @@ Justin D'Arcangelo Yury Delendik Kalervo Kujala + Adil Allawi <@ironymark> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/Makefile b/Makefile index 0ca269642..fb4ffe9cb 100644 --- a/Makefile +++ b/Makefile @@ -55,30 +55,30 @@ browser-test: --browserManifestFile=$(PDF_BROWSERS) \ --manifestFile=$(PDF_TESTS) -# make shell-test -# -# This target runs all of the tests that can be run in a JS shell. -# The shell used is taken from the JS_SHELL environment variable. If -# that variable is not defined, the script will attempt to use the copy -# of Rhino that comes with the Closure compiler used for producing the -# website. -SHELL_TARGET = $(NULL) -ifeq ($(JS_SHELL),) -JS_SHELL := "java -cp $(BUILD_DIR)/compiler.jar" -JS_SHELL += "com.google.javascript.jscomp.mozilla.rhino.tools.shell.Main" -SHELL_TARGET = compiler -endif - -shell-test: shell-msg $(SHELL_TARGET) font-test -shell-msg: -ifeq ($(SHELL_TARGET), compiler) - @echo "No JS_SHELL env variable present." - @echo "The default is to find a copy of Rhino and try that." -endif - @echo "JS shell command is: $(JS_SHELL)" - -font-test: - @echo "font test stub." +# # make shell-test +# # +# # This target runs all of the tests that can be run in a JS shell. +# # The shell used is taken from the JS_SHELL environment variable. If +# # that variable is not defined, the script will attempt to use the copy +# # of Rhino that comes with the Closure compiler used for producing the +# # website. +# SHELL_TARGET = $(NULL) +# ifeq ($(JS_SHELL),) +# JS_SHELL := "java -cp $(BUILD_DIR)/compiler.jar" +# JS_SHELL += "com.google.javascript.jscomp.mozilla.rhino.tools.shell.Main" +# SHELL_TARGET = compiler +# endif +# +# shell-test: shell-msg $(SHELL_TARGET) font-test +# shell-msg: +# ifeq ($(SHELL_TARGET), compiler) +# @echo "No JS_SHELL env variable present." +# @echo "The default is to find a copy of Rhino and try that." +# endif +# @echo "JS shell command is: $(JS_SHELL)" +# +# font-test: +# @echo "font test stub." # make lint # @@ -133,18 +133,18 @@ $(GH_PAGES)/web/%: web/% $(GH_PAGES)/web/images/%: web/images/% @cp $< $@ -# make compiler -# -# This target downloads the Closure compiler, and places it in the -# build directory. This target is also useful when the user doesn't -# have a JS shell available--we can have them use the Rhino shell that -# comes with Closure. -COMPILER_URL = http://closure-compiler.googlecode.com/files/compiler-latest.zip - -compiler: $(BUILD_DIR)/compiler.zip -$(BUILD_DIR)/compiler.zip: | $(BUILD_DIR) - curl $(COMPILER_URL) > $(BUILD_DIR)/compiler.zip; - cd $(BUILD_DIR); unzip compiler.zip compiler.jar; +# # make compiler +# # +# # This target downloads the Closure compiler, and places it in the +# # build directory. This target is also useful when the user doesn't +# # have a JS shell available--we can have them use the Rhino shell that +# # comes with Closure. +# COMPILER_URL = http://closure-compiler.googlecode.com/files/compiler-latest.zip +# +# compiler: $(BUILD_DIR)/compiler.zip +# $(BUILD_DIR)/compiler.zip: | $(BUILD_DIR) +# curl $(COMPILER_URL) > $(BUILD_DIR)/compiler.zip; +# cd $(BUILD_DIR); unzip compiler.zip compiler.jar; # make firefox-extension # diff --git a/README.md b/README.md index 0d439b139..c6cf92ede 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,84 @@ # pdf.js -pdf.js is a technology demonstrator prototype to explore whether the HTML5 -platform is complete enough to faithfully and efficiently render the ISO -32000-1:2008 Portable Document Format (PDF) without native code assistance. -pdf.js is not currently part of the Mozilla project, and there is no plan -yet to integrate it into Firefox. We will explore that possibility once -pdf.js is production ready. Until then we aim to publish a Firefox -PDF reader extension powered by pdf.js. + +## Overview + +pdf.js is an HTML5 technology experiment that explores building a faithful +and efficient Portable Document Format (PDF) renderer without native code +assistance. + +pdf.js is community-driven and supported by Mozilla Labs. Our goal is to +create a general-purpose, web standards-based platform for parsing and +rendering PDFs, and eventually release a PDF reader extension powered by +pdf.js. Integration with Firefox is a possibility if the experiment proves +successful. + + + +## Getting started + +**Online demo** + +For an online demo, visit: + + http://andreasgal.github.com/pdf.js/web/viewer.html + +This demo provides an interactive interface for displaying and browsing PDFs +using the pdf.js API. + +**Hello world** + +For a "hello world" example, take a look at: + + examples/helloworld/ + +This example illustrates the bare minimum ingredients for integrating pdf.js +in a custom project. + + + +## Running the Tests + +pdf.js comes with browser-level regression tests that allow one to probe +whether it's able to successfully parse PDFs, as well as compare its output +against reference images, pixel-by-pixel. + +To run the tests, first configure the browser manifest file at: + + test/resources/browser_manifests/browser_manifest.json + +Sample manifests for different platforms are provided in that directory. + +To run all the bundled tests, type: + + $ make test + +and cross your fingers. Different types of tests are available, see the test +manifest file at: + + test/test_manifest.json + +The test type `eq` tests whether the output images are identical to reference +images. The test type `load` simply tests whether the file loads without +raising any errors. + + +## Contributing + +pdf.js is a community-driver project, so contributors are always welcome. +Simply fork our repo and contribute away. A great place to start is our +open issues. + +For better consistency and long-term stability, please do look around the +code and try to follow our conventions. + + +## Additional resources Our demo site is here: - http://andreasgal.github.com/pdf.js/ + http://andreasgal.github.com/pdf.js/web/viewer.html You can read more about pdf.js here: @@ -19,14 +86,19 @@ You can read more about pdf.js here: http://blog.mozilla.com/cjones/2011/06/15/overview-of-pdf-js-guts/ -follow us on twitter: @pdfjs +Follow us on twitter: @pdfjs http://twitter.com/#!/pdfjs -join our mailing list: +Join our mailing list: dev-pdf-js@lists.mozilla.org + +Subscribe either using lists.mozilla.org or Google Groups: + + https://lists.mozilla.org/listinfo/dev-pdf-js + https://groups.google.com/group/mozilla.dev.pdf-js/topics -and talk to us on IRC: +Talk to us on IRC: #pdfjs on irc.mozilla.org diff --git a/crypto.js b/crypto.js index bfffa1f44..a91f9e41d 100644 --- a/crypto.js +++ b/crypto.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'; diff --git a/examples/helloworld/README.md b/examples/helloworld/README.md new file mode 100644 index 000000000..8395733f3 --- /dev/null +++ b/examples/helloworld/README.md @@ -0,0 +1,16 @@ +## "Hello World" overview + +This example is a minimalistic application of the pdf.js project. The file +`helloworld.pdf` is from the GNUpdf project (see [Introduction to PDF at GNUpdf](http://gnupdf.org/Introduction_to_PDF), and contains a simple and +human-readable PDF. + + +## Getting started + +Point your browser to `index.html`. Voila. Take a peek at `hello.js` to see +how to make basic calls to `pdf.js`. + + +## Additional resources + ++ [GNUpdf - Introduction to PDF](http://gnupdf.org/Introduction_to_PDF) diff --git a/examples/helloworld/hello.js b/examples/helloworld/hello.js new file mode 100644 index 000000000..21799c33a --- /dev/null +++ b/examples/helloworld/hello.js @@ -0,0 +1,49 @@ +// +// See README for overview +// + + +// +// Ajax GET request, for binary files +// (like jQuery's $.get(), but supports the binary type ArrayBuffer) +// +var ajaxGet = function(url, callback){ + var xhr = new XMLHttpRequest(); + xhr.open('GET', url); + xhr.mozResponseType = xhr.responseType = 'arraybuffer'; + xhr.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200; + xhr.onreadystatechange = function() { + if (xhr.readyState === 4 && xhr.status === xhr.expected) { + var data = (xhr.mozResponseArrayBuffer || xhr.mozResponse || + xhr.responseArrayBuffer || xhr.response); + + callback(data); + } + }; + xhr.send(null); +} + +// +// This is where the fun happens +// +ajaxGet('helloworld.pdf', function(data){ + // + // Instantiate PDFDoc with PDF data + // + var pdf = new PDFDoc(new Stream(data)); + var page = pdf.getPage(1); + var scale = 1.5; + + // + // Prepare canvas using PDF page dimensions + // + var canvas = document.getElementById('the-canvas'); + var context = canvas.getContext('2d'); + canvas.height = page.height * scale; + canvas.width = page.width * scale; + + // + // Render PDF page into canvas context + // + page.startRendering(context); +}); diff --git a/examples/helloworld/helloworld.pdf b/examples/helloworld/helloworld.pdf new file mode 100644 index 000000000..d98b4e1db --- /dev/null +++ b/examples/helloworld/helloworld.pdf @@ -0,0 +1,68 @@ +%PDF-1.7 + +1 0 obj % entry point +<< + /Type /Catalog + /Pages 2 0 R +>> +endobj + +2 0 obj +<< + /Type /Pages + /MediaBox [ 0 0 200 200 ] + /Count 1 + /Kids [ 3 0 R ] +>> +endobj + +3 0 obj +<< + /Type /Page + /Parent 2 0 R + /Resources << + /Font << + /F1 4 0 R + >> + >> + /Contents 5 0 R +>> +endobj + +4 0 obj +<< + /Type /Font + /Subtype /Type1 + /BaseFont /Times-Roman +>> +endobj + +5 0 obj % page content +<< + /Length 44 +>> +stream +BT +70 50 TD +/F1 12 Tf +(Hello, world!) Tj +ET +endstream +endobj + +xref +0 6 +0000000000 65535 f +0000000010 00000 n +0000000079 00000 n +0000000173 00000 n +0000000301 00000 n +0000000380 00000 n +trailer +<< + /Size 6 + /Root 1 0 R +>> +startxref +492 +%%EOF \ No newline at end of file diff --git a/examples/helloworld/index.html b/examples/helloworld/index.html new file mode 100644 index 000000000..c353b6a89 --- /dev/null +++ b/examples/helloworld/index.html @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/fonts.js b/fonts.js old mode 100755 new mode 100644 index cca1d816c..eeefa02f8 --- a/fonts.js +++ b/fonts.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'; @@ -12,6 +12,13 @@ var kMaxWaitForFontFace = 1000; // Unicode Private Use Area var kCmapGlyphOffset = 0xE000; +// 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; + /** * Hold a map of decoded fonts and of the standard fourteen Type1 * fonts and their acronyms. @@ -114,54 +121,6 @@ var serifFonts = { 'Wide Latin': true, 'Windsor': true, 'XITS': true }; -var FontMeasure = (function FontMeasure() { - var kScalePrecision = 30; - var ctx = document.createElement('canvas').getContext('2d'); - ctx.scale(1 / kScalePrecision, 1); - - var current; - var measureCache; - - return { - setActive: function fonts_setActive(font, size) { - if (current == font) { - var sizes = current.sizes; - if (!(measureCache = sizes[size])) - measureCache = sizes[size] = Object.create(null); - } else { - measureCache = null; - } - - var name = font.loadedName; - var bold = font.bold ? 'bold' : 'normal'; - var italic = font.italic ? 'italic' : 'normal'; - size *= kScalePrecision; - var rule = italic + ' ' + bold + ' ' + size + 'px "' + name + '"'; - ctx.font = rule; - current = font; - }, - measureText: function fonts_measureText(text, encoding, size) { - var width; - if (measureCache && (width = measureCache[text])) - return width; - - try { - width = 0.0; - for (var i = 0; i < text.length; i++) { - var charWidth = encoding[text.charCodeAt(i)].width; - width += parseFloat(charWidth); - } - width = width * size / 1000; - } catch(e) { - width = ctx.measureText(text).width / kScalePrecision; - } - if (measureCache) - measureCache[text] = width; - return width; - } - }; -})(); - var FontLoader = { listeningForFontLoad: false, @@ -456,10 +415,10 @@ var Font = (function Font() { this.encoding = properties.encoding; this.sizes = []; - var names = name.split("+"); + var names = name.split('+'); names = names.length > 1 ? names[1] : names[0]; names = names.split(/[-,_]/g)[0]; - this.serif = serifFonts[names] || (name.indexOf("Serif") != -1); + this.serif = serifFonts[names] || (name.search(/serif/gi) != -1); // If the font is to be ignored, register it like an already loaded font // to avoid the cost of waiting for it be be loaded by the platform. @@ -473,14 +432,15 @@ var Font = (function Font() { // The file data is not specified. Trying to fix the font name // to be used with the canvas.font. var fontName = stdFontMap[name] || name.replace('_', '-'); - this.bold = (fontName.indexOf('Bold') != -1); - this.italic = (fontName.indexOf('Oblique') != -1) || - (fontName.indexOf('Italic') != -1); + this.bold = (fontName.search(/bold/gi) != -1); + this.italic = (fontName.search(/oblique/gi) != -1) || + (fontName.search(/italic/gi) != -1); // Use 'name' instead of 'fontName' here because the original // name ArialBlack for example will be replaced by Helvetica. - this.black = (name.indexOf("Black") != -1) + this.black = (name.search(/Black/g) != -1); + this.defaultWidth = properties.defaultWidth; this.loadedName = fontName.split('-')[0]; this.loading = false; return; @@ -493,8 +453,8 @@ var Font = (function Font() { this.mimetype = 'font/opentype'; var subtype = properties.subtype; - var cff = (subtype === 'Type1C') ? new Type2CFF(file, properties) - : new CFF(name, file, properties); + var cff = (subtype === 'Type1C') ? + new Type2CFF(file, properties) : new CFF(name, file, properties); // Wrap the CFF data inside an OTF font file data = this.convert(name, cff, properties); @@ -517,6 +477,7 @@ var Font = (function Font() { this.data = data; this.type = properties.type; this.textMatrix = properties.textMatrix; + this.defaultWidth = properties.defaultWidth; this.loadedName = getUniqueName(); this.composite = properties.composite; this.loading = true; @@ -579,6 +540,10 @@ var Font = (function Font() { }; function createOpenTypeHeader(sfnt, file, numTables) { + // Windows hates the Mac TrueType sfnt version number + if (sfnt == 'true') + sfnt = string32(0x00010000); + // sfnt version (4 bytes) var header = sfnt; @@ -632,19 +597,24 @@ var Font = (function Font() { var codes = []; var length = glyphs.length; for (var n = 0; n < length; ++n) - codes.push(String.fromCharCode(glyphs[n].unicode)); - codes.sort(); + codes.push({ unicode: glyphs[n].unicode, code: n }); + codes.sort(function(a, b) { + return a.unicode - b.unicode; + }); // Split the sorted codes into ranges. var ranges = []; for (var n = 0; n < length; ) { - var start = codes[n++].charCodeAt(0); + var start = codes[n].unicode; + var startCode = codes[n].code; + ++n; var end = start; - while (n < length && end + 1 == codes[n].charCodeAt(0)) { + while (n < length && end + 1 == codes[n].unicode) { ++end; ++n; } - ranges.push([start, end]); + var endCode = codes[n - 1].code; + ranges.push([start, end, startCode, endCode]); } return ranges; @@ -673,22 +643,39 @@ var Font = (function Font() { var idRangeOffsets = ''; var glyphsIds = ''; var bias = 0; - for (var i = 0; i < segCount - 1; i++) { - var range = ranges[i]; - var start = range[0]; - var end = range[1]; - var offset = (segCount - i) * 2 + bias * 2; - bias += (end - start + 1); - startCount += string16(start); - endCount += string16(end); - idDeltas += string16(0); - idRangeOffsets += string16(offset); + if (deltas) { + for (var i = 0; i < segCount - 1; i++) { + var range = ranges[i]; + var start = range[0]; + var end = range[1]; + var offset = (segCount - i) * 2 + bias * 2; + bias += (end - start + 1); + + startCount += string16(start); + endCount += string16(end); + idDeltas += string16(0); + idRangeOffsets += string16(offset); + + var startCode = range[2]; + var endCode = range[3]; + for (var j = startCode; j <= endCode; ++j) + glyphsIds += string16(deltas[j]); + } + } else { + for (var i = 0; i < segCount - 1; i++) { + var range = ranges[i]; + var start = range[0]; + var end = range[1]; + var startCode = range[2]; + + startCount += string16(start); + endCount += string16(end); + idDeltas += string16((startCode - start + 1) & 0xFFFF); + idRangeOffsets += string16(0); + } } - for (var i = 0; i < glyphs.length; i++) - glyphsIds += string16(deltas ? deltas[i] : i + 1); - endCount += '\xFF\xFF'; startCount += '\xFF\xFF'; idDeltas += '\x00\x01'; @@ -708,7 +695,9 @@ var Font = (function Font() { format314); }; - function createOS2Table(properties) { + function createOS2Table(properties, override) { + var override = override || {}; + var ulUnicodeRange1 = 0; var ulUnicodeRange2 = 0; var ulUnicodeRange3 = 0; @@ -739,6 +728,24 @@ var Font = (function Font() { } } + var unitsPerEm = override.unitsPerEm || kPDFGlyphSpaceUnits; + var typoAscent = override.ascent || properties.ascent; + var typoDescent = override.descent || properties.descent; + var winAscent = override.yMax || typoAscent; + var winDescent = -override.yMin || -typoDescent; + + // if there is a units per em value but no other override + // then scale the calculated ascent + if (unitsPerEm != kPDFGlyphSpaceUnits && + 'undefined' == typeof(override.ascent)) { + // if the font units differ to the PDF glyph space units + // then scale up the values + typoAscent = Math.round(typoAscent * unitsPerEm / kPDFGlyphSpaceUnits); + typoDescent = Math.round(typoDescent * unitsPerEm / kPDFGlyphSpaceUnits); + winAscent = typoAscent; + winDescent = -typoDescent; + } + return '\x00\x03' + // version '\x02\x24' + // xAvgCharWidth '\x01\xF4' + // usWeightClass @@ -767,11 +774,11 @@ var Font = (function Font() { string16(firstCharIndex || properties.firstChar) + // usFirstCharIndex string16(lastCharIndex || properties.lastChar) + // usLastCharIndex - string16(properties.ascent) + // sTypoAscender - string16(properties.descent) + // sTypoDescender + string16(typoAscent) + // sTypoAscender + string16(typoDescent) + // sTypoDescender '\x00\x64' + // sTypoLineGap (7%-10% of the unitsPerEM value) - string16(properties.ascent) + // usWinAscent - string16(-properties.descent) + // usWinDescent + string16(winAscent) + // usWinAscent + string16(winDescent) + // usWinDescent '\x00\x00\x00\x00' + // ulCodePageRange1 (Bits 0-31) '\x00\x00\x00\x00' + // ulCodePageRange2 (Bits 32-63) string16(properties.xHeight) + // sxHeight @@ -878,9 +885,11 @@ var Font = (function Font() { var data = file.getBytes(length); file.pos = previousPosition; - if (tag == 'head') + if (tag == 'head') { // clearing checksum adjustment data[8] = data[9] = data[10] = data[11] = 0; + data[17] |= 0x20; //Set font optimized for cleartype flag + } return { tag: tag, @@ -920,7 +929,7 @@ var Font = (function Font() { // Check that table are sorted by platformID then encodingID, records.sort(function(a, b) { return ((a.platformID << 16) + a.encodingID) - - ((b.platformID << 16) + b.encodingID) + ((b.platformID << 16) + b.encodingID); }); var tables = [records[0]]; @@ -952,7 +961,7 @@ var Font = (function Font() { } for (var i = 0; i < data.length; i++) - cmap.data[i] = data.charCodeAt(i); + cmap.data[i] = data.charCodeAt(i); } var encoding = properties.encoding; @@ -979,11 +988,13 @@ var Font = (function Font() { deltas.push(index); var unicode = j + kCmapGlyphOffset; - encoding[j].unicode = unicode; + var mapping = encoding[j] || {}; + mapping.unicode = unicode; + encoding[j] = mapping; glyphs.push({ unicode: unicode }); } } - + return cmap.data = createCMapTable(glyphs, deltas); } else if (format == 6) { // Format 6 is a 2-bytes dense mapping, which means the font data @@ -995,48 +1006,98 @@ var Font = (function Font() { var entryCount = int16(font.getBytes(2)); var glyphs = []; - var min = 0xffff, max = 0; - for (var j = 0; j < entryCount; j++) { - var charcode = int16(font.getBytes(2)); - if (!charcode) - continue; - glyphs.push(charcode); + var ids = []; + for (var j = 0; j < firstCode + entryCount; j++) { + var code = (j >= firstCode) ? int16(font.getBytes(2)) : j; + glyphs.push({ unicode: j + kCmapGlyphOffset }); + ids.push(code); - if (charcode < min) - min = charcode; - if (charcode > max) - max = charcode; + var mapping = encoding[j] || {}; + mapping.unicode = glyphs[j].unicode; + encoding[j] = mapping; } - - // Since Format 6 is a dense array, check for gaps - for (var j = min; j < max; j++) { - if (glyphs.indexOf(j) == -1) - glyphs.push(j); - } - - 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 denseRange = ranges[0]; - var start = denseRange[0]; - var end = denseRange[1]; - var index = firstCode; - for (var j = start; j <= end; j++) { - var code = j - firstCode - 1; - var mapping = encoding[index + 1] || {}; - mapping.unicode = glyphs[code].unicode; - encoding[index++] = mapping; - } - return cmap.data = createCMapTable(glyphs); + return cmap.data = createCMapTable(glyphs, ids); } } return cmap.data; }; + function sanitizeMetrics(font, header, metrics, numGlyphs) { + if (!header && !metrics) + return; + + // The vhea/vmtx tables are not required, so it happens that + // some fonts embed a vmtx table without a vhea table. In this + // situation the sanitizer assume numOfLongVerMetrics = 1. As + // a result it tries to read numGlyphs - 1 SHORT from the vmtx + // table, and if it is not possible, the font is rejected. + // So remove the vmtx table if there is no vhea table. + if (!header && metrics) { + metrics.data = null; + return; + } + + font.pos = (font.start ? font.start : 0) + header.offset; + font.pos += header.length - 2; + var numOfMetrics = int16(font.getBytes(2)); + + var numOfSidebearings = numGlyphs - numOfMetrics; + var numMissing = numOfSidebearings - + ((hmtx.length - numOfMetrics * 4) >> 1); + if (numMissing > 0) { + font.pos = (font.start ? font.start : 0) + metrics.offset; + var entries = ''; + for (var i = 0; i < hmtx.length; i++) + entries += String.fromCharCode(font.getByte()); + for (var i = 0; i < numMissing; i++) + entries += '\x00\x00'; + metrics.data = stringToArray(entries); + } + }; + + function sanitizeGlyphLocations(loca, glyf, numGlyphs, + isGlyphLocationsLong) { + var itemSize, itemDecode, itemEncode; + if (isGlyphLocationsLong) { + itemSize = 4; + itemDecode = function(data, offset) { + return (data[offset] << 24) | (data[offset + 1] << 16) | + (data[offset + 2] << 8) | data[offset + 3]; + }; + itemEncode = function(data, offset, value) { + data[offset] = (value >>> 24) & 0xFF; + data[offset + 1] = (value >> 16) & 0xFF; + data[offset + 2] = (value >> 8) & 0xFF; + data[offset + 3] = value & 0xFF; + }; + } else { + itemSize = 2; + itemDecode = function(data, offset) { + return (data[offset] << 9) | (data[offset + 1] << 1); + }; + itemEncode = function(data, offset, value) { + data[offset] = (value >> 9) & 0xFF; + data[offset + 1] = (value >> 1) & 0xFF; + }; + } + var locaData = loca.data; + var startOffset = itemDecode(locaData, 0); + var firstOffset = itemDecode(locaData, itemSize); + if (firstOffset - startOffset < 12 || startOffset > 0) { + // removing first glyph + glyf.data = glyf.data.subarray(firstOffset); + glyf.length -= firstOffset; + + itemEncode(locaData, 0, 0); + var i, pos = itemSize; + for (i = 1; i <= numGlyphs; ++i) { + itemEncode(locaData, pos, + itemDecode(locaData, pos) - firstOffset); + pos += itemSize; + } + } + } + // Check that required tables are present var requiredTables = ['OS/2', 'cmap', 'head', 'hhea', 'hmtx', 'maxp', 'name', 'post']; @@ -1044,7 +1105,7 @@ var Font = (function Font() { var header = readOpenTypeHeader(font); var numTables = header.numTables; - var cmap, maxp, hhea, hmtx; + var cmap, maxp, hhea, hmtx, vhea, vmtx, head, loca, glyf; var tables = []; for (var i = 0; i < numTables; i++) { var table = readTableEntry(font); @@ -1058,8 +1119,19 @@ var Font = (function Font() { hhea = table; else if (table.tag == 'hmtx') hmtx = table; + else if (table.tag == 'head') + head = table; requiredTables.splice(index, 1); + } else { + if (table.tag == 'vmtx') + vmtx = table; + else if (table.tag == 'vhea') + vhea = table; + else if (table.tag == 'loca') + loca = table; + else if (table.tag == 'glyf') + glyf = table; } tables.push(table); } @@ -1079,33 +1151,34 @@ var Font = (function Font() { createOpenTypeHeader(header.version, ttf, numTables); if (requiredTables.indexOf('OS/2') != -1) { + // extract some more font properties from the OpenType head and + // hhea tables; yMin and descent value are always negative + var override = { + unitsPerEm: int16([head.data[18], head.data[19]]), + yMax: int16([head.data[42], head.data[43]]), + yMin: int16([head.data[38], head.data[39]]) - 0x10000, + ascent: int16([hhea.data[4], hhea.data[5]]), + descent: int16([hhea.data[6], hhea.data[7]]) - 0x10000 + }; + tables.push({ tag: 'OS/2', - data: stringToArray(createOS2Table(properties)) + data: stringToArray(createOS2Table(properties, override)) }); } - // 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; + // Ensure the [h/v]mtx tables contains the advance width and + // sidebearings information for numGlyphs in the maxp table + font.pos = (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)); + sanitizeMetrics(font, hhea, hmtx, numGlyphs); + sanitizeMetrics(font, vhea, vmtx, numGlyphs); - var numOfSidebearings = numGlyphs - numOfHMetrics; - var numMissing = numOfSidebearings - - ((hmtx.length - numOfHMetrics * 4) >> 1); - 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); + if (head && loca && glyf) { + var isGlyphLocationsLong = int16([head.data[50], head.data[51]]); + sanitizeGlyphLocations(loca, glyf, numGlyphs, isGlyphLocationsLong); } // Sanitizer reduces the glyph advanceWidth to the maxAdvanceWidth @@ -1132,20 +1205,36 @@ var Font = (function Font() { tables.push(cmap); } - var encoding = properties.encoding; + var encoding = properties.encoding, i; if (!encoding[0]) { // the font is directly characters to glyphs with no encoding // so create an identity encoding - for (i = 0; i < numGlyphs; i++) - encoding[i] = { unicode: i + kCmapGlyphOffset }; + var widths = properties.widths; + for (i = 0; i < numGlyphs; i++) { + var width = widths[i]; + encoding[i] = { + unicode: i <= 0x1f || (i >= 127 && i <= 255) ? + i + kCmapGlyphOffset : i, + width: IsNum(width) ? width : properties.defaultWidth + }; + } } else { - for (var code in encoding) - encoding[code].unicode += kCmapGlyphOffset; + for (i in encoding) { + if (encoding.hasOwnProperty(i)) { + var unicode = encoding[i].unicode; + if (unicode <= 0x1f || (unicode >= 127 && unicode <= 255)) + encoding[i].unicode = unicode += kCmapGlyphOffset; + } + } } var glyphs = []; - for (var i = 1; i < numGlyphs; i++) - glyphs.push({ unicode: i + kCmapGlyphOffset }); + for (i = 1; i < numGlyphs; i++) { + glyphs.push({ + unicode: i <= 0x1f || (i >= 127 && i <= 255) ? + i + kCmapGlyphOffset : i + }); + } cmap.data = createCMapTable(glyphs); } else { replaceCMapTable(cmap, font, properties); @@ -1204,7 +1293,7 @@ var Font = (function Font() { return false; } return true; - }; + } // The offsets object holds at the same time a representation of where // to write the table entry information about a table and another offset @@ -1330,20 +1419,25 @@ var Font = (function Font() { window.btoa(data) + ');'); var rule = "@font-face { font-family:'" + fontName + "';src:" + url + '}'; var styleSheet = document.styleSheets[0]; + if (!styleSheet) { + document.documentElement.firstChild.appendChild( + document.createElement('style')); + styleSheet = document.styleSheets[0]; + } styleSheet.insertRule(rule, styleSheet.cssRules.length); return rule; }, - charsToUnicode: function fonts_chars2Unicode(chars) { + charsToGlyphs: function fonts_chars2Glyphs(chars) { var charsCache = this.charsCache; - var str; + var glyphs; // if we translated this string before, just grab it from the cache if (charsCache) { - str = charsCache[chars]; - if (str) - return str; + glyphs = charsCache[chars]; + if (glyphs) + return glyphs; } // lazily create the translation cache @@ -1354,7 +1448,8 @@ var Font = (function Font() { var encoding = this.encoding; if (!encoding) return chars; - str = ''; + + glyphs = []; if (this.composite) { // composite fonts have multi-byte strings convert the string from @@ -1365,30 +1460,39 @@ var Font = (function Font() { // loop should never end on the last byte for (var i = 0; i < length; i++) { var charcode = int16([chars.charCodeAt(i++), chars.charCodeAt(i)]); - var unicode = encoding[charcode].unicode; - str += String.fromCharCode(unicode); + var glyph = encoding[charcode]; + if ('undefined' == typeof(glyph)) { + warn('Unencoded charcode ' + charcode); + glyph = { + unicode: charcode, + width: this.defaultWidth + }; + } + glyphs.push(glyph); + // placing null after each word break charcode (ASCII SPACE) + if (charcode == 0x20) + glyphs.push(null); } } else { for (var i = 0; i < chars.length; ++i) { var charcode = chars.charCodeAt(i); - var unicode = encoding[charcode].unicode; - if ('undefined' == typeof(unicode)) { + var glyph = encoding[charcode]; + if ('undefined' == typeof(glyph)) { warn('Unencoded charcode ' + charcode); - unicode = charcode; + glyph = { + unicode: charcode, + width: this.defaultWidth + }; } - - // Handle surrogate pairs - if (unicode > 0xFFFF) { - str += String.fromCharCode(unicode & 0xFFFF); - unicode >>= 16; - } - str += String.fromCharCode(unicode); + glyphs.push(glyph); + if (charcode == 0x20) + glyphs.push(null); } } // Enter the translated string into the cache - return charsCache[chars] = str; + return (charsCache[chars] = glyphs); } }; @@ -1421,7 +1525,7 @@ var Type1Parser = function() { r = ((value + r) * c1 + c2) & ((1 << 16) - 1); } return decryptedString.slice(discardNumber); - }; + } /* * CharStrings are encoded following the the CharString Encoding sequence @@ -1562,6 +1666,9 @@ var Type1Parser = function() { i++; continue; } + } else if (!kHintingEnabled && (value == 1 || value == 2)) { + charstring.push('drop', 'drop', 'drop', 'drop', 'drop', 'drop'); + continue; } command = charStringDictionary['12'][escape]; @@ -1586,6 +1693,9 @@ var Type1Parser = function() { charstring.push(lsb, 'hmoveto'); continue; + } else if (!kHintingEnabled && (value == 1 || value == 3)) { + charstring.push('drop', 'drop'); + continue; } command = charStringDictionary[value]; } @@ -1618,7 +1728,7 @@ var Type1Parser = function() { } return { charstring: charstring, width: width, lsb: lsb }; - }; + } /* * Returns an object containing a Subrs array and a CharStrings @@ -1638,7 +1748,7 @@ var Type1Parser = function() { for (var i = 0; i < array.length; i++) array[i] = parseFloat(array[i] || 0); return array; - }; + } function readNumber(str, index) { while (str[index] == ' ') @@ -1651,11 +1761,11 @@ var Type1Parser = function() { count++; return parseFloat(str.substr(start, count) || 0); - }; + } function isSeparator(c) { return c == ' ' || c == '\n' || c == '\x0d'; - }; + } this.extractFontProgram = function t1_extractFontProgram(stream) { var eexec = decrypt(stream, kEexecEncryptionKey, 4); @@ -1693,7 +1803,7 @@ var Type1Parser = function() { }; var c = eexecStr[i]; - if ((glyphsSection || subrsSection) && + if ((glyphsSection || subrsSection) && (token == 'RD' || token == '-|')) { i++; var data = eexec.slice(i, i + length); @@ -1729,7 +1839,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 == '|-' || t == 'noaccess') + if (t == 'ND' || t == '|-' || t == 'noaccess') break; var index = parseInt(getToken(), 10); if (index > j) @@ -1780,7 +1890,7 @@ var Type1Parser = function() { } return program; - }, + }; this.extractFontHeader = function t1_extractFontHeader(stream, properties) { var headerString = ''; @@ -1828,10 +1938,12 @@ var Type1Parser = function() { if (token == 'dup') { var index = parseInt(getToken(), 10); var glyph = getToken(); - + if ('undefined' == typeof(properties.differences[index])) { - var mapping = { unicode: GlyphsUnicode[glyph] || j }; - properties.glyphs[glyph] = properties.encoding[index] = mapping; + var mapping = properties.encoding[index] || {}; + mapping.unicode = GlyphsUnicode[glyph] || index; + properties.glyphs[glyph] = properties.encoding[index] = + mapping; } getToken(); // read the in 'put' } @@ -1847,7 +1959,7 @@ var Type1Parser = function() { }; /** - * The CFF class takes a Type1 file and wrap it into a + * The CFF class takes a Type1 file and wrap it into a * 'Compact Font Format' which itself embed Type2 charstrings. */ var CFFStrings = [ @@ -2177,7 +2289,7 @@ CFF.prototype = { 'globalSubrs': this.createCFFIndexHeader([]), 'charset': (function charset(self) { - var charset = '\x00'; // Encoding + var charsetString = '\x00'; // Encoding var count = glyphs.length; for (var i = 0; i < count; i++) { @@ -2189,9 +2301,9 @@ CFF.prototype = { if (index == -1) index = 0; - charset += String.fromCharCode(index >> 8, index & 0xff); + charsetString += String.fromCharCode(index >> 8, index & 0xff); } - return charset; + return charsetString; })(this), 'charstrings': this.createCFFIndexHeader([[0x8B, 0x0E]].concat(glyphs), @@ -2258,7 +2370,7 @@ var Type2CFF = (function() { this.properties = properties; this.data = this.parse(); - }; + } constructor.prototype = { parse: function cff_parse() { @@ -2289,7 +2401,7 @@ var Type2CFF = (function() { var charStrings = this.parseIndex(topDict.CharStrings); var charset = this.parseCharsets(topDict.charset, charStrings.length, strings); - var hasSupplement = this.parseEncoding(topDict.Encoding, properties, + var hasSupplement = this.parseEncoding(topDict.Encoding, properties, strings, charset); // The font sanitizer does not support CFF encoding with a @@ -2321,8 +2433,6 @@ var Type2CFF = (function() { getCharStrings: function cff_charstrings(charsets, charStrings, privDict, properties) { - var widths = properties.widths; - var defaultWidth = privDict['defaultWidthX']; var nominalWidth = privDict['nominalWidthX']; @@ -2344,13 +2454,13 @@ var Type2CFF = (function() { if (code == -1) index = code = mapping.unicode || index; - var width = mapping.width || defaultWidth; if (code <= 0x1f || (code >= 127 && code <= 255)) code += kCmapGlyphOffset; + var width = mapping.width; properties.glyphs[glyph] = properties.encoding[index] = { unicode: code, - width: width + width: IsNum(width) ? width : defaultWidth }; charstrings.push({ @@ -2366,7 +2476,8 @@ var Type2CFF = (function() { return charstrings; }, - parseEncoding: function cff_parseencoding(pos, properties, strings, charset) { + parseEncoding: function cff_parseencoding(pos, properties, strings, + charset) { var encoding = {}; var bytes = this.bytes; @@ -2381,8 +2492,8 @@ var Type2CFF = (function() { if (pos == 0 || pos == 1) { var gid = 1; - var baseEncoding = pos ? Encodings.ExpertEncoding - : Encodings.StandardEncoding; + var baseEncoding = + pos ? Encodings.ExpertEncoding : Encodings.StandardEncoding; for (var i = 0; i < charset.length; i++) { var index = baseEncoding.indexOf(charset[i]); if (index != -1) @@ -2393,7 +2504,7 @@ var Type2CFF = (function() { switch (format & 0x7f) { case 0: var glyphsCount = bytes[pos++]; - for (var i = 1; i <= glyphsCount; i++) + for (var i = 1; i <= glyphsCount; i++) encoding[bytes[pos++]] = i; if (format & 0x80) { @@ -2419,7 +2530,7 @@ var Type2CFF = (function() { break; default: - error('Unknow encoding format: ' + format + " in CFF"); + error('Unknow encoding format: ' + format + ' in CFF'); break; } } @@ -2482,7 +2593,7 @@ var Type2CFF = (function() { case 21: dict['nominalWidthX'] = value[0]; default: - TODO('interpret top dict key'); + TODO('interpret top dict key: ' + key); } } return dict; @@ -2594,7 +2705,7 @@ var Type2CFF = (function() { error('Incorrect byte'); } return -1; - }; + } function parseFloatOperand() { var str = ''; @@ -2616,7 +2727,7 @@ var Type2CFF = (function() { str += lookup[b2]; } return parseFloat(str); - }; + } var operands = []; var entries = []; @@ -2642,15 +2753,14 @@ var Type2CFF = (function() { parseIndex: function cff_parseIndex(pos) { var bytes = this.bytes; var count = bytes[pos++] << 8 | bytes[pos++]; - if (count == 0) { - var offsets = []; - var end = pos; - } else { + var offsets = []; + var end = pos; + + if (count != 0) { var offsetSize = bytes[pos++]; // add 1 for offset to determine size of last object var startPos = pos + ((count + 1) * offsetSize) - 1; - var offsets = []; for (var i = 0, ii = count + 1; i < ii; ++i) { var offset = 0; for (var j = 0; j < offsetSize; ++j) { @@ -2659,7 +2769,7 @@ var Type2CFF = (function() { } offsets.push(startPos + offset); } - var end = offsets[count]; + end = offsets[count]; } return { diff --git a/glyphlist.js b/glyphlist.js index 9be0e8d5a..5691f8546 100644 --- a/glyphlist.js +++ b/glyphlist.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'; diff --git a/metrics.js b/metrics.js new file mode 100644 index 000000000..9cb8eb0e6 --- /dev/null +++ b/metrics.js @@ -0,0 +1,2941 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ + +var Metrics = { + 'Courier': 600, + 'Courier-Bold': 600, + 'Courier-BoldOblique': 600, + 'Courier-Oblique': 600, + 'Helvetica' : { + 'space': 278, + 'exclam': 278, + 'quotedbl': 355, + 'numbersign': 556, + 'dollar': 556, + 'percent': 889, + 'ampersand': 667, + 'quoteright': 222, + 'parenleft': 333, + 'parenright': 333, + 'asterisk': 389, + 'plus': 584, + 'comma': 278, + 'hyphen': 333, + 'period': 278, + 'slash': 278, + 'zero': 556, + 'one': 556, + 'two': 556, + 'three': 556, + 'four': 556, + 'five': 556, + 'six': 556, + 'seven': 556, + 'eight': 556, + 'nine': 556, + 'colon': 278, + 'semicolon': 278, + 'less': 584, + 'equal': 584, + 'greater': 584, + 'question': 556, + 'at': 1015, + 'A': 667, + 'B': 667, + 'C': 722, + 'D': 722, + 'E': 667, + 'F': 611, + 'G': 778, + 'H': 722, + 'I': 278, + 'J': 500, + 'K': 667, + 'L': 556, + 'M': 833, + 'N': 722, + 'O': 778, + 'P': 667, + 'Q': 778, + 'R': 722, + 'S': 667, + 'T': 611, + 'U': 722, + 'V': 667, + 'W': 944, + 'X': 667, + 'Y': 667, + 'Z': 611, + 'bracketleft': 278, + 'backslash': 278, + 'bracketright': 278, + 'asciicircum': 469, + 'underscore': 556, + 'quoteleft': 222, + 'a': 556, + 'b': 556, + 'c': 500, + 'd': 556, + 'e': 556, + 'f': 278, + 'g': 556, + 'h': 556, + 'i': 222, + 'j': 222, + 'k': 500, + 'l': 222, + 'm': 833, + 'n': 556, + 'o': 556, + 'p': 556, + 'q': 556, + 'r': 333, + 's': 500, + 't': 278, + 'u': 556, + 'v': 500, + 'w': 722, + 'x': 500, + 'y': 500, + 'z': 500, + 'braceleft': 334, + 'bar': 260, + 'braceright': 334, + 'asciitilde': 584, + 'exclamdown': 333, + 'cent': 556, + 'sterling': 556, + 'fraction': 167, + 'yen': 556, + 'florin': 556, + 'section': 556, + 'currency': 556, + 'quotesingle': 191, + 'quotedblleft': 333, + 'guillemotleft': 556, + 'guilsinglleft': 333, + 'guilsinglright': 333, + 'fi': 500, + 'fl': 500, + 'endash': 556, + 'dagger': 556, + 'daggerdbl': 556, + 'periodcentered': 278, + 'paragraph': 537, + 'bullet': 350, + 'quotesinglbase': 222, + 'quotedblbase': 333, + 'quotedblright': 333, + 'guillemotright': 556, + 'ellipsis': 1000, + 'perthousand': 1000, + 'questiondown': 611, + 'grave': 333, + 'acute': 333, + 'circumflex': 333, + 'tilde': 333, + 'macron': 333, + 'breve': 333, + 'dotaccent': 333, + 'dieresis': 333, + 'ring': 333, + 'cedilla': 333, + 'hungarumlaut': 333, + 'ogonek': 333, + 'caron': 333, + 'emdash': 1000, + 'AE': 1000, + 'ordfeminine': 370, + 'Lslash': 556, + 'Oslash': 778, + 'OE': 1000, + 'ordmasculine': 365, + 'ae': 889, + 'dotlessi': 278, + 'lslash': 222, + 'oslash': 611, + 'oe': 944, + 'germandbls': 611, + 'Idieresis': 278, + 'eacute': 556, + 'abreve': 556, + 'uhungarumlaut': 556, + 'ecaron': 556, + 'Ydieresis': 667, + 'divide': 584, + 'Yacute': 667, + 'Acircumflex': 667, + 'aacute': 556, + 'Ucircumflex': 722, + 'yacute': 500, + 'scommaaccent': 500, + 'ecircumflex': 556, + 'Uring': 722, + 'Udieresis': 722, + 'aogonek': 556, + 'Uacute': 722, + 'uogonek': 556, + 'Edieresis': 667, + 'Dcroat': 722, + 'commaaccent': 250, + 'copyright': 737, + 'Emacron': 667, + 'ccaron': 500, + 'aring': 556, + 'Ncommaaccent': 722, + 'lacute': 222, + 'agrave': 556, + 'Tcommaaccent': 611, + 'Cacute': 722, + 'atilde': 556, + 'Edotaccent': 667, + 'scaron': 500, + 'scedilla': 500, + 'iacute': 278, + 'lozenge': 471, + 'Rcaron': 722, + 'Gcommaaccent': 778, + 'ucircumflex': 556, + 'acircumflex': 556, + 'Amacron': 667, + 'rcaron': 333, + 'ccedilla': 500, + 'Zdotaccent': 611, + 'Thorn': 667, + 'Omacron': 778, + 'Racute': 722, + 'Sacute': 667, + 'dcaron': 643, + 'Umacron': 722, + 'uring': 556, + 'threesuperior': 333, + 'Ograve': 778, + 'Agrave': 667, + 'Abreve': 667, + 'multiply': 584, + 'uacute': 556, + 'Tcaron': 611, + 'partialdiff': 476, + 'ydieresis': 500, + 'Nacute': 722, + 'icircumflex': 278, + 'Ecircumflex': 667, + 'adieresis': 556, + 'edieresis': 556, + 'cacute': 500, + 'nacute': 556, + 'umacron': 556, + 'Ncaron': 722, + 'Iacute': 278, + 'plusminus': 584, + 'brokenbar': 260, + 'registered': 737, + 'Gbreve': 778, + 'Idotaccent': 278, + 'summation': 600, + 'Egrave': 667, + 'racute': 333, + 'omacron': 556, + 'Zacute': 611, + 'Zcaron': 611, + 'greaterequal': 549, + 'Eth': 722, + 'Ccedilla': 722, + 'lcommaaccent': 222, + 'tcaron': 317, + 'eogonek': 556, + 'Uogonek': 722, + 'Aacute': 667, + 'Adieresis': 667, + 'egrave': 556, + 'zacute': 500, + 'iogonek': 222, + 'Oacute': 778, + 'oacute': 556, + 'amacron': 556, + 'sacute': 500, + 'idieresis': 278, + 'Ocircumflex': 778, + 'Ugrave': 722, + 'Delta': 612, + 'thorn': 556, + 'twosuperior': 333, + 'Odieresis': 778, + 'mu': 556, + 'igrave': 278, + 'ohungarumlaut': 556, + 'Eogonek': 667, + 'dcroat': 556, + 'threequarters': 834, + 'Scedilla': 667, + 'lcaron': 299, + 'Kcommaaccent': 667, + 'Lacute': 556, + 'trademark': 1000, + 'edotaccent': 556, + 'Igrave': 278, + 'Imacron': 278, + 'Lcaron': 556, + 'onehalf': 834, + 'lessequal': 549, + 'ocircumflex': 556, + 'ntilde': 556, + 'Uhungarumlaut': 722, + 'Eacute': 667, + 'emacron': 556, + 'gbreve': 556, + 'onequarter': 834, + 'Scaron': 667, + 'Scommaaccent': 667, + 'Ohungarumlaut': 778, + 'degree': 400, + 'ograve': 556, + 'Ccaron': 722, + 'ugrave': 556, + 'radical': 453, + 'Dcaron': 722, + 'rcommaaccent': 333, + 'Ntilde': 722, + 'otilde': 556, + 'Rcommaaccent': 722, + 'Lcommaaccent': 556, + 'Atilde': 667, + 'Aogonek': 667, + 'Aring': 667, + 'Otilde': 778, + 'zdotaccent': 500, + 'Ecaron': 667, + 'Iogonek': 278, + 'kcommaaccent': 500, + 'minus': 584, + 'Icircumflex': 278, + 'ncaron': 556, + 'tcommaaccent': 278, + 'logicalnot': 584, + 'odieresis': 556, + 'udieresis': 556, + 'notequal': 549, + 'gcommaaccent': 556, + 'eth': 556, + 'zcaron': 500, + 'ncommaaccent': 556, + 'onesuperior': 333, + 'imacron': 278, + 'Euro': 556 + }, + 'Helvetica-Bold': { + 'space': 278, + 'exclam': 333, + 'quotedbl': 474, + 'numbersign': 556, + 'dollar': 556, + 'percent': 889, + 'ampersand': 722, + 'quoteright': 278, + 'parenleft': 333, + 'parenright': 333, + 'asterisk': 389, + 'plus': 584, + 'comma': 278, + 'hyphen': 333, + 'period': 278, + 'slash': 278, + 'zero': 556, + 'one': 556, + 'two': 556, + 'three': 556, + 'four': 556, + 'five': 556, + 'six': 556, + 'seven': 556, + 'eight': 556, + 'nine': 556, + 'colon': 333, + 'semicolon': 333, + 'less': 584, + 'equal': 584, + 'greater': 584, + 'question': 611, + 'at': 975, + 'A': 722, + 'B': 722, + 'C': 722, + 'D': 722, + 'E': 667, + 'F': 611, + 'G': 778, + 'H': 722, + 'I': 278, + 'J': 556, + 'K': 722, + 'L': 611, + 'M': 833, + 'N': 722, + 'O': 778, + 'P': 667, + 'Q': 778, + 'R': 722, + 'S': 667, + 'T': 611, + 'U': 722, + 'V': 667, + 'W': 944, + 'X': 667, + 'Y': 667, + 'Z': 611, + 'bracketleft': 333, + 'backslash': 278, + 'bracketright': 333, + 'asciicircum': 584, + 'underscore': 556, + 'quoteleft': 278, + 'a': 556, + 'b': 611, + 'c': 556, + 'd': 611, + 'e': 556, + 'f': 333, + 'g': 611, + 'h': 611, + 'i': 278, + 'j': 278, + 'k': 556, + 'l': 278, + 'm': 889, + 'n': 611, + 'o': 611, + 'p': 611, + 'q': 611, + 'r': 389, + 's': 556, + 't': 333, + 'u': 611, + 'v': 556, + 'w': 778, + 'x': 556, + 'y': 556, + 'z': 500, + 'braceleft': 389, + 'bar': 280, + 'braceright': 389, + 'asciitilde': 584, + 'exclamdown': 333, + 'cent': 556, + 'sterling': 556, + 'fraction': 167, + 'yen': 556, + 'florin': 556, + 'section': 556, + 'currency': 556, + 'quotesingle': 238, + 'quotedblleft': 500, + 'guillemotleft': 556, + 'guilsinglleft': 333, + 'guilsinglright': 333, + 'fi': 611, + 'fl': 611, + 'endash': 556, + 'dagger': 556, + 'daggerdbl': 556, + 'periodcentered': 278, + 'paragraph': 556, + 'bullet': 350, + 'quotesinglbase': 278, + 'quotedblbase': 500, + 'quotedblright': 500, + 'guillemotright': 556, + 'ellipsis': 1000, + 'perthousand': 1000, + 'questiondown': 611, + 'grave': 333, + 'acute': 333, + 'circumflex': 333, + 'tilde': 333, + 'macron': 333, + 'breve': 333, + 'dotaccent': 333, + 'dieresis': 333, + 'ring': 333, + 'cedilla': 333, + 'hungarumlaut': 333, + 'ogonek': 333, + 'caron': 333, + 'emdash': 1000, + 'AE': 1000, + 'ordfeminine': 370, + 'Lslash': 611, + 'Oslash': 778, + 'OE': 1000, + 'ordmasculine': 365, + 'ae': 889, + 'dotlessi': 278, + 'lslash': 278, + 'oslash': 611, + 'oe': 944, + 'germandbls': 611, + 'Idieresis': 278, + 'eacute': 556, + 'abreve': 556, + 'uhungarumlaut': 611, + 'ecaron': 556, + 'Ydieresis': 667, + 'divide': 584, + 'Yacute': 667, + 'Acircumflex': 722, + 'aacute': 556, + 'Ucircumflex': 722, + 'yacute': 556, + 'scommaaccent': 556, + 'ecircumflex': 556, + 'Uring': 722, + 'Udieresis': 722, + 'aogonek': 556, + 'Uacute': 722, + 'uogonek': 611, + 'Edieresis': 667, + 'Dcroat': 722, + 'commaaccent': 250, + 'copyright': 737, + 'Emacron': 667, + 'ccaron': 556, + 'aring': 556, + 'Ncommaaccent': 722, + 'lacute': 278, + 'agrave': 556, + 'Tcommaaccent': 611, + 'Cacute': 722, + 'atilde': 556, + 'Edotaccent': 667, + 'scaron': 556, + 'scedilla': 556, + 'iacute': 278, + 'lozenge': 494, + 'Rcaron': 722, + 'Gcommaaccent': 778, + 'ucircumflex': 611, + 'acircumflex': 556, + 'Amacron': 722, + 'rcaron': 389, + 'ccedilla': 556, + 'Zdotaccent': 611, + 'Thorn': 667, + 'Omacron': 778, + 'Racute': 722, + 'Sacute': 667, + 'dcaron': 743, + 'Umacron': 722, + 'uring': 611, + 'threesuperior': 333, + 'Ograve': 778, + 'Agrave': 722, + 'Abreve': 722, + 'multiply': 584, + 'uacute': 611, + 'Tcaron': 611, + 'partialdiff': 494, + 'ydieresis': 556, + 'Nacute': 722, + 'icircumflex': 278, + 'Ecircumflex': 667, + 'adieresis': 556, + 'edieresis': 556, + 'cacute': 556, + 'nacute': 611, + 'umacron': 611, + 'Ncaron': 722, + 'Iacute': 278, + 'plusminus': 584, + 'brokenbar': 280, + 'registered': 737, + 'Gbreve': 778, + 'Idotaccent': 278, + 'summation': 600, + 'Egrave': 667, + 'racute': 389, + 'omacron': 611, + 'Zacute': 611, + 'Zcaron': 611, + 'greaterequal': 549, + 'Eth': 722, + 'Ccedilla': 722, + 'lcommaaccent': 278, + 'tcaron': 389, + 'eogonek': 556, + 'Uogonek': 722, + 'Aacute': 722, + 'Adieresis': 722, + 'egrave': 556, + 'zacute': 500, + 'iogonek': 278, + 'Oacute': 778, + 'oacute': 611, + 'amacron': 556, + 'sacute': 556, + 'idieresis': 278, + 'Ocircumflex': 778, + 'Ugrave': 722, + 'Delta': 612, + 'thorn': 611, + 'twosuperior': 333, + 'Odieresis': 778, + 'mu': 611, + 'igrave': 278, + 'ohungarumlaut': 611, + 'Eogonek': 667, + 'dcroat': 611, + 'threequarters': 834, + 'Scedilla': 667, + 'lcaron': 400, + 'Kcommaaccent': 722, + 'Lacute': 611, + 'trademark': 1000, + 'edotaccent': 556, + 'Igrave': 278, + 'Imacron': 278, + 'Lcaron': 611, + 'onehalf': 834, + 'lessequal': 549, + 'ocircumflex': 611, + 'ntilde': 611, + 'Uhungarumlaut': 722, + 'Eacute': 667, + 'emacron': 556, + 'gbreve': 611, + 'onequarter': 834, + 'Scaron': 667, + 'Scommaaccent': 667, + 'Ohungarumlaut': 778, + 'degree': 400, + 'ograve': 611, + 'Ccaron': 722, + 'ugrave': 611, + 'radical': 549, + 'Dcaron': 722, + 'rcommaaccent': 389, + 'Ntilde': 722, + 'otilde': 611, + 'Rcommaaccent': 722, + 'Lcommaaccent': 611, + 'Atilde': 722, + 'Aogonek': 722, + 'Aring': 722, + 'Otilde': 778, + 'zdotaccent': 500, + 'Ecaron': 667, + 'Iogonek': 278, + 'kcommaaccent': 556, + 'minus': 584, + 'Icircumflex': 278, + 'ncaron': 611, + 'tcommaaccent': 333, + 'logicalnot': 584, + 'odieresis': 611, + 'udieresis': 611, + 'notequal': 549, + 'gcommaaccent': 611, + 'eth': 611, + 'zcaron': 500, + 'ncommaaccent': 611, + 'onesuperior': 333, + 'imacron': 278, + 'Euro': 556 + }, + 'Helvetica-BoldOblique': { + 'space': 278, + 'exclam': 333, + 'quotedbl': 474, + 'numbersign': 556, + 'dollar': 556, + 'percent': 889, + 'ampersand': 722, + 'quoteright': 278, + 'parenleft': 333, + 'parenright': 333, + 'asterisk': 389, + 'plus': 584, + 'comma': 278, + 'hyphen': 333, + 'period': 278, + 'slash': 278, + 'zero': 556, + 'one': 556, + 'two': 556, + 'three': 556, + 'four': 556, + 'five': 556, + 'six': 556, + 'seven': 556, + 'eight': 556, + 'nine': 556, + 'colon': 333, + 'semicolon': 333, + 'less': 584, + 'equal': 584, + 'greater': 584, + 'question': 611, + 'at': 975, + 'A': 722, + 'B': 722, + 'C': 722, + 'D': 722, + 'E': 667, + 'F': 611, + 'G': 778, + 'H': 722, + 'I': 278, + 'J': 556, + 'K': 722, + 'L': 611, + 'M': 833, + 'N': 722, + 'O': 778, + 'P': 667, + 'Q': 778, + 'R': 722, + 'S': 667, + 'T': 611, + 'U': 722, + 'V': 667, + 'W': 944, + 'X': 667, + 'Y': 667, + 'Z': 611, + 'bracketleft': 333, + 'backslash': 278, + 'bracketright': 333, + 'asciicircum': 584, + 'underscore': 556, + 'quoteleft': 278, + 'a': 556, + 'b': 611, + 'c': 556, + 'd': 611, + 'e': 556, + 'f': 333, + 'g': 611, + 'h': 611, + 'i': 278, + 'j': 278, + 'k': 556, + 'l': 278, + 'm': 889, + 'n': 611, + 'o': 611, + 'p': 611, + 'q': 611, + 'r': 389, + 's': 556, + 't': 333, + 'u': 611, + 'v': 556, + 'w': 778, + 'x': 556, + 'y': 556, + 'z': 500, + 'braceleft': 389, + 'bar': 280, + 'braceright': 389, + 'asciitilde': 584, + 'exclamdown': 333, + 'cent': 556, + 'sterling': 556, + 'fraction': 167, + 'yen': 556, + 'florin': 556, + 'section': 556, + 'currency': 556, + 'quotesingle': 238, + 'quotedblleft': 500, + 'guillemotleft': 556, + 'guilsinglleft': 333, + 'guilsinglright': 333, + 'fi': 611, + 'fl': 611, + 'endash': 556, + 'dagger': 556, + 'daggerdbl': 556, + 'periodcentered': 278, + 'paragraph': 556, + 'bullet': 350, + 'quotesinglbase': 278, + 'quotedblbase': 500, + 'quotedblright': 500, + 'guillemotright': 556, + 'ellipsis': 1000, + 'perthousand': 1000, + 'questiondown': 611, + 'grave': 333, + 'acute': 333, + 'circumflex': 333, + 'tilde': 333, + 'macron': 333, + 'breve': 333, + 'dotaccent': 333, + 'dieresis': 333, + 'ring': 333, + 'cedilla': 333, + 'hungarumlaut': 333, + 'ogonek': 333, + 'caron': 333, + 'emdash': 1000, + 'AE': 1000, + 'ordfeminine': 370, + 'Lslash': 611, + 'Oslash': 778, + 'OE': 1000, + 'ordmasculine': 365, + 'ae': 889, + 'dotlessi': 278, + 'lslash': 278, + 'oslash': 611, + 'oe': 944, + 'germandbls': 611, + 'Idieresis': 278, + 'eacute': 556, + 'abreve': 556, + 'uhungarumlaut': 611, + 'ecaron': 556, + 'Ydieresis': 667, + 'divide': 584, + 'Yacute': 667, + 'Acircumflex': 722, + 'aacute': 556, + 'Ucircumflex': 722, + 'yacute': 556, + 'scommaaccent': 556, + 'ecircumflex': 556, + 'Uring': 722, + 'Udieresis': 722, + 'aogonek': 556, + 'Uacute': 722, + 'uogonek': 611, + 'Edieresis': 667, + 'Dcroat': 722, + 'commaaccent': 250, + 'copyright': 737, + 'Emacron': 667, + 'ccaron': 556, + 'aring': 556, + 'Ncommaaccent': 722, + 'lacute': 278, + 'agrave': 556, + 'Tcommaaccent': 611, + 'Cacute': 722, + 'atilde': 556, + 'Edotaccent': 667, + 'scaron': 556, + 'scedilla': 556, + 'iacute': 278, + 'lozenge': 494, + 'Rcaron': 722, + 'Gcommaaccent': 778, + 'ucircumflex': 611, + 'acircumflex': 556, + 'Amacron': 722, + 'rcaron': 389, + 'ccedilla': 556, + 'Zdotaccent': 611, + 'Thorn': 667, + 'Omacron': 778, + 'Racute': 722, + 'Sacute': 667, + 'dcaron': 743, + 'Umacron': 722, + 'uring': 611, + 'threesuperior': 333, + 'Ograve': 778, + 'Agrave': 722, + 'Abreve': 722, + 'multiply': 584, + 'uacute': 611, + 'Tcaron': 611, + 'partialdiff': 494, + 'ydieresis': 556, + 'Nacute': 722, + 'icircumflex': 278, + 'Ecircumflex': 667, + 'adieresis': 556, + 'edieresis': 556, + 'cacute': 556, + 'nacute': 611, + 'umacron': 611, + 'Ncaron': 722, + 'Iacute': 278, + 'plusminus': 584, + 'brokenbar': 280, + 'registered': 737, + 'Gbreve': 778, + 'Idotaccent': 278, + 'summation': 600, + 'Egrave': 667, + 'racute': 389, + 'omacron': 611, + 'Zacute': 611, + 'Zcaron': 611, + 'greaterequal': 549, + 'Eth': 722, + 'Ccedilla': 722, + 'lcommaaccent': 278, + 'tcaron': 389, + 'eogonek': 556, + 'Uogonek': 722, + 'Aacute': 722, + 'Adieresis': 722, + 'egrave': 556, + 'zacute': 500, + 'iogonek': 278, + 'Oacute': 778, + 'oacute': 611, + 'amacron': 556, + 'sacute': 556, + 'idieresis': 278, + 'Ocircumflex': 778, + 'Ugrave': 722, + 'Delta': 612, + 'thorn': 611, + 'twosuperior': 333, + 'Odieresis': 778, + 'mu': 611, + 'igrave': 278, + 'ohungarumlaut': 611, + 'Eogonek': 667, + 'dcroat': 611, + 'threequarters': 834, + 'Scedilla': 667, + 'lcaron': 400, + 'Kcommaaccent': 722, + 'Lacute': 611, + 'trademark': 1000, + 'edotaccent': 556, + 'Igrave': 278, + 'Imacron': 278, + 'Lcaron': 611, + 'onehalf': 834, + 'lessequal': 549, + 'ocircumflex': 611, + 'ntilde': 611, + 'Uhungarumlaut': 722, + 'Eacute': 667, + 'emacron': 556, + 'gbreve': 611, + 'onequarter': 834, + 'Scaron': 667, + 'Scommaaccent': 667, + 'Ohungarumlaut': 778, + 'degree': 400, + 'ograve': 611, + 'Ccaron': 722, + 'ugrave': 611, + 'radical': 549, + 'Dcaron': 722, + 'rcommaaccent': 389, + 'Ntilde': 722, + 'otilde': 611, + 'Rcommaaccent': 722, + 'Lcommaaccent': 611, + 'Atilde': 722, + 'Aogonek': 722, + 'Aring': 722, + 'Otilde': 778, + 'zdotaccent': 500, + 'Ecaron': 667, + 'Iogonek': 278, + 'kcommaaccent': 556, + 'minus': 584, + 'Icircumflex': 278, + 'ncaron': 611, + 'tcommaaccent': 333, + 'logicalnot': 584, + 'odieresis': 611, + 'udieresis': 611, + 'notequal': 549, + 'gcommaaccent': 611, + 'eth': 611, + 'zcaron': 500, + 'ncommaaccent': 611, + 'onesuperior': 333, + 'imacron': 278, + 'Euro': 556 + }, + 'Helvetica-Oblique' : { + 'space': 278, + 'exclam': 278, + 'quotedbl': 355, + 'numbersign': 556, + 'dollar': 556, + 'percent': 889, + 'ampersand': 667, + 'quoteright': 222, + 'parenleft': 333, + 'parenright': 333, + 'asterisk': 389, + 'plus': 584, + 'comma': 278, + 'hyphen': 333, + 'period': 278, + 'slash': 278, + 'zero': 556, + 'one': 556, + 'two': 556, + 'three': 556, + 'four': 556, + 'five': 556, + 'six': 556, + 'seven': 556, + 'eight': 556, + 'nine': 556, + 'colon': 278, + 'semicolon': 278, + 'less': 584, + 'equal': 584, + 'greater': 584, + 'question': 556, + 'at': 1015, + 'A': 667, + 'B': 667, + 'C': 722, + 'D': 722, + 'E': 667, + 'F': 611, + 'G': 778, + 'H': 722, + 'I': 278, + 'J': 500, + 'K': 667, + 'L': 556, + 'M': 833, + 'N': 722, + 'O': 778, + 'P': 667, + 'Q': 778, + 'R': 722, + 'S': 667, + 'T': 611, + 'U': 722, + 'V': 667, + 'W': 944, + 'X': 667, + 'Y': 667, + 'Z': 611, + 'bracketleft': 278, + 'backslash': 278, + 'bracketright': 278, + 'asciicircum': 469, + 'underscore': 556, + 'quoteleft': 222, + 'a': 556, + 'b': 556, + 'c': 500, + 'd': 556, + 'e': 556, + 'f': 278, + 'g': 556, + 'h': 556, + 'i': 222, + 'j': 222, + 'k': 500, + 'l': 222, + 'm': 833, + 'n': 556, + 'o': 556, + 'p': 556, + 'q': 556, + 'r': 333, + 's': 500, + 't': 278, + 'u': 556, + 'v': 500, + 'w': 722, + 'x': 500, + 'y': 500, + 'z': 500, + 'braceleft': 334, + 'bar': 260, + 'braceright': 334, + 'asciitilde': 584, + 'exclamdown': 333, + 'cent': 556, + 'sterling': 556, + 'fraction': 167, + 'yen': 556, + 'florin': 556, + 'section': 556, + 'currency': 556, + 'quotesingle': 191, + 'quotedblleft': 333, + 'guillemotleft': 556, + 'guilsinglleft': 333, + 'guilsinglright': 333, + 'fi': 500, + 'fl': 500, + 'endash': 556, + 'dagger': 556, + 'daggerdbl': 556, + 'periodcentered': 278, + 'paragraph': 537, + 'bullet': 350, + 'quotesinglbase': 222, + 'quotedblbase': 333, + 'quotedblright': 333, + 'guillemotright': 556, + 'ellipsis': 1000, + 'perthousand': 1000, + 'questiondown': 611, + 'grave': 333, + 'acute': 333, + 'circumflex': 333, + 'tilde': 333, + 'macron': 333, + 'breve': 333, + 'dotaccent': 333, + 'dieresis': 333, + 'ring': 333, + 'cedilla': 333, + 'hungarumlaut': 333, + 'ogonek': 333, + 'caron': 333, + 'emdash': 1000, + 'AE': 1000, + 'ordfeminine': 370, + 'Lslash': 556, + 'Oslash': 778, + 'OE': 1000, + 'ordmasculine': 365, + 'ae': 889, + 'dotlessi': 278, + 'lslash': 222, + 'oslash': 611, + 'oe': 944, + 'germandbls': 611, + 'Idieresis': 278, + 'eacute': 556, + 'abreve': 556, + 'uhungarumlaut': 556, + 'ecaron': 556, + 'Ydieresis': 667, + 'divide': 584, + 'Yacute': 667, + 'Acircumflex': 667, + 'aacute': 556, + 'Ucircumflex': 722, + 'yacute': 500, + 'scommaaccent': 500, + 'ecircumflex': 556, + 'Uring': 722, + 'Udieresis': 722, + 'aogonek': 556, + 'Uacute': 722, + 'uogonek': 556, + 'Edieresis': 667, + 'Dcroat': 722, + 'commaaccent': 250, + 'copyright': 737, + 'Emacron': 667, + 'ccaron': 500, + 'aring': 556, + 'Ncommaaccent': 722, + 'lacute': 222, + 'agrave': 556, + 'Tcommaaccent': 611, + 'Cacute': 722, + 'atilde': 556, + 'Edotaccent': 667, + 'scaron': 500, + 'scedilla': 500, + 'iacute': 278, + 'lozenge': 471, + 'Rcaron': 722, + 'Gcommaaccent': 778, + 'ucircumflex': 556, + 'acircumflex': 556, + 'Amacron': 667, + 'rcaron': 333, + 'ccedilla': 500, + 'Zdotaccent': 611, + 'Thorn': 667, + 'Omacron': 778, + 'Racute': 722, + 'Sacute': 667, + 'dcaron': 643, + 'Umacron': 722, + 'uring': 556, + 'threesuperior': 333, + 'Ograve': 778, + 'Agrave': 667, + 'Abreve': 667, + 'multiply': 584, + 'uacute': 556, + 'Tcaron': 611, + 'partialdiff': 476, + 'ydieresis': 500, + 'Nacute': 722, + 'icircumflex': 278, + 'Ecircumflex': 667, + 'adieresis': 556, + 'edieresis': 556, + 'cacute': 500, + 'nacute': 556, + 'umacron': 556, + 'Ncaron': 722, + 'Iacute': 278, + 'plusminus': 584, + 'brokenbar': 260, + 'registered': 737, + 'Gbreve': 778, + 'Idotaccent': 278, + 'summation': 600, + 'Egrave': 667, + 'racute': 333, + 'omacron': 556, + 'Zacute': 611, + 'Zcaron': 611, + 'greaterequal': 549, + 'Eth': 722, + 'Ccedilla': 722, + 'lcommaaccent': 222, + 'tcaron': 317, + 'eogonek': 556, + 'Uogonek': 722, + 'Aacute': 667, + 'Adieresis': 667, + 'egrave': 556, + 'zacute': 500, + 'iogonek': 222, + 'Oacute': 778, + 'oacute': 556, + 'amacron': 556, + 'sacute': 500, + 'idieresis': 278, + 'Ocircumflex': 778, + 'Ugrave': 722, + 'Delta': 612, + 'thorn': 556, + 'twosuperior': 333, + 'Odieresis': 778, + 'mu': 556, + 'igrave': 278, + 'ohungarumlaut': 556, + 'Eogonek': 667, + 'dcroat': 556, + 'threequarters': 834, + 'Scedilla': 667, + 'lcaron': 299, + 'Kcommaaccent': 667, + 'Lacute': 556, + 'trademark': 1000, + 'edotaccent': 556, + 'Igrave': 278, + 'Imacron': 278, + 'Lcaron': 556, + 'onehalf': 834, + 'lessequal': 549, + 'ocircumflex': 556, + 'ntilde': 556, + 'Uhungarumlaut': 722, + 'Eacute': 667, + 'emacron': 556, + 'gbreve': 556, + 'onequarter': 834, + 'Scaron': 667, + 'Scommaaccent': 667, + 'Ohungarumlaut': 778, + 'degree': 400, + 'ograve': 556, + 'Ccaron': 722, + 'ugrave': 556, + 'radical': 453, + 'Dcaron': 722, + 'rcommaaccent': 333, + 'Ntilde': 722, + 'otilde': 556, + 'Rcommaaccent': 722, + 'Lcommaaccent': 556, + 'Atilde': 667, + 'Aogonek': 667, + 'Aring': 667, + 'Otilde': 778, + 'zdotaccent': 500, + 'Ecaron': 667, + 'Iogonek': 278, + 'kcommaaccent': 500, + 'minus': 584, + 'Icircumflex': 278, + 'ncaron': 556, + 'tcommaaccent': 278, + 'logicalnot': 584, + 'odieresis': 556, + 'udieresis': 556, + 'notequal': 549, + 'gcommaaccent': 556, + 'eth': 556, + 'zcaron': 500, + 'ncommaaccent': 556, + 'onesuperior': 333, + 'imacron': 278, + 'Euro': 556 + }, + 'Symbol': { + 'space': 250, + 'exclam': 333, + 'universal': 713, + 'numbersign': 500, + 'existential': 549, + 'percent': 833, + 'ampersand': 778, + 'suchthat': 439, + 'parenleft': 333, + 'parenright': 333, + 'asteriskmath': 500, + 'plus': 549, + 'comma': 250, + 'minus': 549, + 'period': 250, + 'slash': 278, + 'zero': 500, + 'one': 500, + 'two': 500, + 'three': 500, + 'four': 500, + 'five': 500, + 'six': 500, + 'seven': 500, + 'eight': 500, + 'nine': 500, + 'colon': 278, + 'semicolon': 278, + 'less': 549, + 'equal': 549, + 'greater': 549, + 'question': 444, + 'congruent': 549, + 'Alpha': 722, + 'Beta': 667, + 'Chi': 722, + 'Delta': 612, + 'Epsilon': 611, + 'Phi': 763, + 'Gamma': 603, + 'Eta': 722, + 'Iota': 333, + 'theta1': 631, + 'Kappa': 722, + 'Lambda': 686, + 'Mu': 889, + 'Nu': 722, + 'Omicron': 722, + 'Pi': 768, + 'Theta': 741, + 'Rho': 556, + 'Sigma': 592, + 'Tau': 611, + 'Upsilon': 690, + 'sigma1': 439, + 'Omega': 768, + 'Xi': 645, + 'Psi': 795, + 'Zeta': 611, + 'bracketleft': 333, + 'therefore': 863, + 'bracketright': 333, + 'perpendicular': 658, + 'underscore': 500, + 'radicalex': 500, + 'alpha': 631, + 'beta': 549, + 'chi': 549, + 'delta': 494, + 'epsilon': 439, + 'phi': 521, + 'gamma': 411, + 'eta': 603, + 'iota': 329, + 'phi1': 603, + 'kappa': 549, + 'lambda': 549, + 'mu': 576, + 'nu': 521, + 'omicron': 549, + 'pi': 549, + 'theta': 521, + 'rho': 549, + 'sigma': 603, + 'tau': 439, + 'upsilon': 576, + 'omega1': 713, + 'omega': 686, + 'xi': 493, + 'psi': 686, + 'zeta': 494, + 'braceleft': 480, + 'bar': 200, + 'braceright': 480, + 'similar': 549, + 'Euro': 750, + 'Upsilon1': 620, + 'minute': 247, + 'lessequal': 549, + 'fraction': 167, + 'infinity': 713, + 'florin': 500, + 'club': 753, + 'diamond': 753, + 'heart': 753, + 'spade': 753, + 'arrowboth': 1042, + 'arrowleft': 987, + 'arrowup': 603, + 'arrowright': 987, + 'arrowdown': 603, + 'degree': 400, + 'plusminus': 549, + 'second': 411, + 'greaterequal': 549, + 'multiply': 549, + 'proportional': 713, + 'partialdiff': 494, + 'bullet': 460, + 'divide': 549, + 'notequal': 549, + 'equivalence': 549, + 'approxequal': 549, + 'ellipsis': 1000, + 'arrowvertex': 603, + 'arrowhorizex': 1000, + 'carriagereturn': 658, + 'aleph': 823, + 'Ifraktur': 686, + 'Rfraktur': 795, + 'weierstrass': 987, + 'circlemultiply': 768, + 'circleplus': 768, + 'emptyset': 823, + 'intersection': 768, + 'union': 768, + 'propersuperset': 713, + 'reflexsuperset': 713, + 'notsubset': 713, + 'propersubset': 713, + 'reflexsubset': 713, + 'element': 713, + 'notelement': 713, + 'angle': 768, + 'gradient': 713, + 'registerserif': 790, + 'copyrightserif': 790, + 'trademarkserif': 890, + 'product': 823, + 'radical': 549, + 'dotmath': 250, + 'logicalnot': 713, + 'logicaland': 603, + 'logicalor': 603, + 'arrowdblboth': 1042, + 'arrowdblleft': 987, + 'arrowdblup': 603, + 'arrowdblright': 987, + 'arrowdbldown': 603, + 'lozenge': 494, + 'angleleft': 329, + 'registersans': 790, + 'copyrightsans': 790, + 'trademarksans': 786, + 'summation': 713, + 'parenlefttp': 384, + 'parenleftex': 384, + 'parenleftbt': 384, + 'bracketlefttp': 384, + 'bracketleftex': 384, + 'bracketleftbt': 384, + 'bracelefttp': 494, + 'braceleftmid': 494, + 'braceleftbt': 494, + 'braceex': 494, + 'angleright': 329, + 'integral': 274, + 'integraltp': 686, + 'integralex': 686, + 'integralbt': 686, + 'parenrighttp': 384, + 'parenrightex': 384, + 'parenrightbt': 384, + 'bracketrighttp': 384, + 'bracketrightex': 384, + 'bracketrightbt': 384, + 'bracerighttp': 494, + 'bracerightmid': 494, + 'bracerightbt': 494, + 'apple': 790 + }, + 'Times-Roman': { + 'space': 250, + 'exclam': 333, + 'quotedbl': 408, + 'numbersign': 500, + 'dollar': 500, + 'percent': 833, + 'ampersand': 778, + 'quoteright': 333, + 'parenleft': 333, + 'parenright': 333, + 'asterisk': 500, + 'plus': 564, + 'comma': 250, + 'hyphen': 333, + 'period': 250, + 'slash': 278, + 'zero': 500, + 'one': 500, + 'two': 500, + 'three': 500, + 'four': 500, + 'five': 500, + 'six': 500, + 'seven': 500, + 'eight': 500, + 'nine': 500, + 'colon': 278, + 'semicolon': 278, + 'less': 564, + 'equal': 564, + 'greater': 564, + 'question': 444, + 'at': 921, + 'A': 722, + 'B': 667, + 'C': 667, + 'D': 722, + 'E': 611, + 'F': 556, + 'G': 722, + 'H': 722, + 'I': 333, + 'J': 389, + 'K': 722, + 'L': 611, + 'M': 889, + 'N': 722, + 'O': 722, + 'P': 556, + 'Q': 722, + 'R': 667, + 'S': 556, + 'T': 611, + 'U': 722, + 'V': 722, + 'W': 944, + 'X': 722, + 'Y': 722, + 'Z': 611, + 'bracketleft': 333, + 'backslash': 278, + 'bracketright': 333, + 'asciicircum': 469, + 'underscore': 500, + 'quoteleft': 333, + 'a': 444, + 'b': 500, + 'c': 444, + 'd': 500, + 'e': 444, + 'f': 333, + 'g': 500, + 'h': 500, + 'i': 278, + 'j': 278, + 'k': 500, + 'l': 278, + 'm': 778, + 'n': 500, + 'o': 500, + 'p': 500, + 'q': 500, + 'r': 333, + 's': 389, + 't': 278, + 'u': 500, + 'v': 500, + 'w': 722, + 'x': 500, + 'y': 500, + 'z': 444, + 'braceleft': 480, + 'bar': 200, + 'braceright': 480, + 'asciitilde': 541, + 'exclamdown': 333, + 'cent': 500, + 'sterling': 500, + 'fraction': 167, + 'yen': 500, + 'florin': 500, + 'section': 500, + 'currency': 500, + 'quotesingle': 180, + 'quotedblleft': 444, + 'guillemotleft': 500, + 'guilsinglleft': 333, + 'guilsinglright': 333, + 'fi': 556, + 'fl': 556, + 'endash': 500, + 'dagger': 500, + 'daggerdbl': 500, + 'periodcentered': 250, + 'paragraph': 453, + 'bullet': 350, + 'quotesinglbase': 333, + 'quotedblbase': 444, + 'quotedblright': 444, + 'guillemotright': 500, + 'ellipsis': 1000, + 'perthousand': 1000, + 'questiondown': 444, + 'grave': 333, + 'acute': 333, + 'circumflex': 333, + 'tilde': 333, + 'macron': 333, + 'breve': 333, + 'dotaccent': 333, + 'dieresis': 333, + 'ring': 333, + 'cedilla': 333, + 'hungarumlaut': 333, + 'ogonek': 333, + 'caron': 333, + 'emdash': 1000, + 'AE': 889, + 'ordfeminine': 276, + 'Lslash': 611, + 'Oslash': 722, + 'OE': 889, + 'ordmasculine': 310, + 'ae': 667, + 'dotlessi': 278, + 'lslash': 278, + 'oslash': 500, + 'oe': 722, + 'germandbls': 500, + 'Idieresis': 333, + 'eacute': 444, + 'abreve': 444, + 'uhungarumlaut': 500, + 'ecaron': 444, + 'Ydieresis': 722, + 'divide': 564, + 'Yacute': 722, + 'Acircumflex': 722, + 'aacute': 444, + 'Ucircumflex': 722, + 'yacute': 500, + 'scommaaccent': 389, + 'ecircumflex': 444, + 'Uring': 722, + 'Udieresis': 722, + 'aogonek': 444, + 'Uacute': 722, + 'uogonek': 500, + 'Edieresis': 611, + 'Dcroat': 722, + 'commaaccent': 250, + 'copyright': 760, + 'Emacron': 611, + 'ccaron': 444, + 'aring': 444, + 'Ncommaaccent': 722, + 'lacute': 278, + 'agrave': 444, + 'Tcommaaccent': 611, + 'Cacute': 667, + 'atilde': 444, + 'Edotaccent': 611, + 'scaron': 389, + 'scedilla': 389, + 'iacute': 278, + 'lozenge': 471, + 'Rcaron': 667, + 'Gcommaaccent': 722, + 'ucircumflex': 500, + 'acircumflex': 444, + 'Amacron': 722, + 'rcaron': 333, + 'ccedilla': 444, + 'Zdotaccent': 611, + 'Thorn': 556, + 'Omacron': 722, + 'Racute': 667, + 'Sacute': 556, + 'dcaron': 588, + 'Umacron': 722, + 'uring': 500, + 'threesuperior': 300, + 'Ograve': 722, + 'Agrave': 722, + 'Abreve': 722, + 'multiply': 564, + 'uacute': 500, + 'Tcaron': 611, + 'partialdiff': 476, + 'ydieresis': 500, + 'Nacute': 722, + 'icircumflex': 278, + 'Ecircumflex': 611, + 'adieresis': 444, + 'edieresis': 444, + 'cacute': 444, + 'nacute': 500, + 'umacron': 500, + 'Ncaron': 722, + 'Iacute': 333, + 'plusminus': 564, + 'brokenbar': 200, + 'registered': 760, + 'Gbreve': 722, + 'Idotaccent': 333, + 'summation': 600, + 'Egrave': 611, + 'racute': 333, + 'omacron': 500, + 'Zacute': 611, + 'Zcaron': 611, + 'greaterequal': 549, + 'Eth': 722, + 'Ccedilla': 667, + 'lcommaaccent': 278, + 'tcaron': 326, + 'eogonek': 444, + 'Uogonek': 722, + 'Aacute': 722, + 'Adieresis': 722, + 'egrave': 444, + 'zacute': 444, + 'iogonek': 278, + 'Oacute': 722, + 'oacute': 500, + 'amacron': 444, + 'sacute': 389, + 'idieresis': 278, + 'Ocircumflex': 722, + 'Ugrave': 722, + 'Delta': 612, + 'thorn': 500, + 'twosuperior': 300, + 'Odieresis': 722, + 'mu': 500, + 'igrave': 278, + 'ohungarumlaut': 500, + 'Eogonek': 611, + 'dcroat': 500, + 'threequarters': 750, + 'Scedilla': 556, + 'lcaron': 344, + 'Kcommaaccent': 722, + 'Lacute': 611, + 'trademark': 980, + 'edotaccent': 444, + 'Igrave': 333, + 'Imacron': 333, + 'Lcaron': 611, + 'onehalf': 750, + 'lessequal': 549, + 'ocircumflex': 500, + 'ntilde': 500, + 'Uhungarumlaut': 722, + 'Eacute': 611, + 'emacron': 444, + 'gbreve': 500, + 'onequarter': 750, + 'Scaron': 556, + 'Scommaaccent': 556, + 'Ohungarumlaut': 722, + 'degree': 400, + 'ograve': 500, + 'Ccaron': 667, + 'ugrave': 500, + 'radical': 453, + 'Dcaron': 722, + 'rcommaaccent': 333, + 'Ntilde': 722, + 'otilde': 500, + 'Rcommaaccent': 667, + 'Lcommaaccent': 611, + 'Atilde': 722, + 'Aogonek': 722, + 'Aring': 722, + 'Otilde': 722, + 'zdotaccent': 444, + 'Ecaron': 611, + 'Iogonek': 333, + 'kcommaaccent': 500, + 'minus': 564, + 'Icircumflex': 333, + 'ncaron': 500, + 'tcommaaccent': 278, + 'logicalnot': 564, + 'odieresis': 500, + 'udieresis': 500, + 'notequal': 549, + 'gcommaaccent': 500, + 'eth': 500, + 'zcaron': 444, + 'ncommaaccent': 500, + 'onesuperior': 300, + 'imacron': 278, + 'Euro': 500 + }, + 'Times-Bold': { + 'space': 250, + 'exclam': 333, + 'quotedbl': 555, + 'numbersign': 500, + 'dollar': 500, + 'percent': 1000, + 'ampersand': 833, + 'quoteright': 333, + 'parenleft': 333, + 'parenright': 333, + 'asterisk': 500, + 'plus': 570, + 'comma': 250, + 'hyphen': 333, + 'period': 250, + 'slash': 278, + 'zero': 500, + 'one': 500, + 'two': 500, + 'three': 500, + 'four': 500, + 'five': 500, + 'six': 500, + 'seven': 500, + 'eight': 500, + 'nine': 500, + 'colon': 333, + 'semicolon': 333, + 'less': 570, + 'equal': 570, + 'greater': 570, + 'question': 500, + 'at': 930, + 'A': 722, + 'B': 667, + 'C': 722, + 'D': 722, + 'E': 667, + 'F': 611, + 'G': 778, + 'H': 778, + 'I': 389, + 'J': 500, + 'K': 778, + 'L': 667, + 'M': 944, + 'N': 722, + 'O': 778, + 'P': 611, + 'Q': 778, + 'R': 722, + 'S': 556, + 'T': 667, + 'U': 722, + 'V': 722, + 'W': 1000, + 'X': 722, + 'Y': 722, + 'Z': 667, + 'bracketleft': 333, + 'backslash': 278, + 'bracketright': 333, + 'asciicircum': 581, + 'underscore': 500, + 'quoteleft': 333, + 'a': 500, + 'b': 556, + 'c': 444, + 'd': 556, + 'e': 444, + 'f': 333, + 'g': 500, + 'h': 556, + 'i': 278, + 'j': 333, + 'k': 556, + 'l': 278, + 'm': 833, + 'n': 556, + 'o': 500, + 'p': 556, + 'q': 556, + 'r': 444, + 's': 389, + 't': 333, + 'u': 556, + 'v': 500, + 'w': 722, + 'x': 500, + 'y': 500, + 'z': 444, + 'braceleft': 394, + 'bar': 220, + 'braceright': 394, + 'asciitilde': 520, + 'exclamdown': 333, + 'cent': 500, + 'sterling': 500, + 'fraction': 167, + 'yen': 500, + 'florin': 500, + 'section': 500, + 'currency': 500, + 'quotesingle': 278, + 'quotedblleft': 500, + 'guillemotleft': 500, + 'guilsinglleft': 333, + 'guilsinglright': 333, + 'fi': 556, + 'fl': 556, + 'endash': 500, + 'dagger': 500, + 'daggerdbl': 500, + 'periodcentered': 250, + 'paragraph': 540, + 'bullet': 350, + 'quotesinglbase': 333, + 'quotedblbase': 500, + 'quotedblright': 500, + 'guillemotright': 500, + 'ellipsis': 1000, + 'perthousand': 1000, + 'questiondown': 500, + 'grave': 333, + 'acute': 333, + 'circumflex': 333, + 'tilde': 333, + 'macron': 333, + 'breve': 333, + 'dotaccent': 333, + 'dieresis': 333, + 'ring': 333, + 'cedilla': 333, + 'hungarumlaut': 333, + 'ogonek': 333, + 'caron': 333, + 'emdash': 1000, + 'AE': 1000, + 'ordfeminine': 300, + 'Lslash': 667, + 'Oslash': 778, + 'OE': 1000, + 'ordmasculine': 330, + 'ae': 722, + 'dotlessi': 278, + 'lslash': 278, + 'oslash': 500, + 'oe': 722, + 'germandbls': 556, + 'Idieresis': 389, + 'eacute': 444, + 'abreve': 500, + 'uhungarumlaut': 556, + 'ecaron': 444, + 'Ydieresis': 722, + 'divide': 570, + 'Yacute': 722, + 'Acircumflex': 722, + 'aacute': 500, + 'Ucircumflex': 722, + 'yacute': 500, + 'scommaaccent': 389, + 'ecircumflex': 444, + 'Uring': 722, + 'Udieresis': 722, + 'aogonek': 500, + 'Uacute': 722, + 'uogonek': 556, + 'Edieresis': 667, + 'Dcroat': 722, + 'commaaccent': 250, + 'copyright': 747, + 'Emacron': 667, + 'ccaron': 444, + 'aring': 500, + 'Ncommaaccent': 722, + 'lacute': 278, + 'agrave': 500, + 'Tcommaaccent': 667, + 'Cacute': 722, + 'atilde': 500, + 'Edotaccent': 667, + 'scaron': 389, + 'scedilla': 389, + 'iacute': 278, + 'lozenge': 494, + 'Rcaron': 722, + 'Gcommaaccent': 778, + 'ucircumflex': 556, + 'acircumflex': 500, + 'Amacron': 722, + 'rcaron': 444, + 'ccedilla': 444, + 'Zdotaccent': 667, + 'Thorn': 611, + 'Omacron': 778, + 'Racute': 722, + 'Sacute': 556, + 'dcaron': 672, + 'Umacron': 722, + 'uring': 556, + 'threesuperior': 300, + 'Ograve': 778, + 'Agrave': 722, + 'Abreve': 722, + 'multiply': 570, + 'uacute': 556, + 'Tcaron': 667, + 'partialdiff': 494, + 'ydieresis': 500, + 'Nacute': 722, + 'icircumflex': 278, + 'Ecircumflex': 667, + 'adieresis': 500, + 'edieresis': 444, + 'cacute': 444, + 'nacute': 556, + 'umacron': 556, + 'Ncaron': 722, + 'Iacute': 389, + 'plusminus': 570, + 'brokenbar': 220, + 'registered': 747, + 'Gbreve': 778, + 'Idotaccent': 389, + 'summation': 600, + 'Egrave': 667, + 'racute': 444, + 'omacron': 500, + 'Zacute': 667, + 'Zcaron': 667, + 'greaterequal': 549, + 'Eth': 722, + 'Ccedilla': 722, + 'lcommaaccent': 278, + 'tcaron': 416, + 'eogonek': 444, + 'Uogonek': 722, + 'Aacute': 722, + 'Adieresis': 722, + 'egrave': 444, + 'zacute': 444, + 'iogonek': 278, + 'Oacute': 778, + 'oacute': 500, + 'amacron': 500, + 'sacute': 389, + 'idieresis': 278, + 'Ocircumflex': 778, + 'Ugrave': 722, + 'Delta': 612, + 'thorn': 556, + 'twosuperior': 300, + 'Odieresis': 778, + 'mu': 556, + 'igrave': 278, + 'ohungarumlaut': 500, + 'Eogonek': 667, + 'dcroat': 556, + 'threequarters': 750, + 'Scedilla': 556, + 'lcaron': 394, + 'Kcommaaccent': 778, + 'Lacute': 667, + 'trademark': 1000, + 'edotaccent': 444, + 'Igrave': 389, + 'Imacron': 389, + 'Lcaron': 667, + 'onehalf': 750, + 'lessequal': 549, + 'ocircumflex': 500, + 'ntilde': 556, + 'Uhungarumlaut': 722, + 'Eacute': 667, + 'emacron': 444, + 'gbreve': 500, + 'onequarter': 750, + 'Scaron': 556, + 'Scommaaccent': 556, + 'Ohungarumlaut': 778, + 'degree': 400, + 'ograve': 500, + 'Ccaron': 722, + 'ugrave': 556, + 'radical': 549, + 'Dcaron': 722, + 'rcommaaccent': 444, + 'Ntilde': 722, + 'otilde': 500, + 'Rcommaaccent': 722, + 'Lcommaaccent': 667, + 'Atilde': 722, + 'Aogonek': 722, + 'Aring': 722, + 'Otilde': 778, + 'zdotaccent': 444, + 'Ecaron': 667, + 'Iogonek': 389, + 'kcommaaccent': 556, + 'minus': 570, + 'Icircumflex': 389, + 'ncaron': 556, + 'tcommaaccent': 333, + 'logicalnot': 570, + 'odieresis': 500, + 'udieresis': 556, + 'notequal': 549, + 'gcommaaccent': 500, + 'eth': 500, + 'zcaron': 444, + 'ncommaaccent': 556, + 'onesuperior': 300, + 'imacron': 278, + 'Euro': 500 + }, + 'Times-BoldItalic': { + 'space': 250, + 'exclam': 389, + 'quotedbl': 555, + 'numbersign': 500, + 'dollar': 500, + 'percent': 833, + 'ampersand': 778, + 'quoteright': 333, + 'parenleft': 333, + 'parenright': 333, + 'asterisk': 500, + 'plus': 570, + 'comma': 250, + 'hyphen': 333, + 'period': 250, + 'slash': 278, + 'zero': 500, + 'one': 500, + 'two': 500, + 'three': 500, + 'four': 500, + 'five': 500, + 'six': 500, + 'seven': 500, + 'eight': 500, + 'nine': 500, + 'colon': 333, + 'semicolon': 333, + 'less': 570, + 'equal': 570, + 'greater': 570, + 'question': 500, + 'at': 832, + 'A': 667, + 'B': 667, + 'C': 667, + 'D': 722, + 'E': 667, + 'F': 667, + 'G': 722, + 'H': 778, + 'I': 389, + 'J': 500, + 'K': 667, + 'L': 611, + 'M': 889, + 'N': 722, + 'O': 722, + 'P': 611, + 'Q': 722, + 'R': 667, + 'S': 556, + 'T': 611, + 'U': 722, + 'V': 667, + 'W': 889, + 'X': 667, + 'Y': 611, + 'Z': 611, + 'bracketleft': 333, + 'backslash': 278, + 'bracketright': 333, + 'asciicircum': 570, + 'underscore': 500, + 'quoteleft': 333, + 'a': 500, + 'b': 500, + 'c': 444, + 'd': 500, + 'e': 444, + 'f': 333, + 'g': 500, + 'h': 556, + 'i': 278, + 'j': 278, + 'k': 500, + 'l': 278, + 'm': 778, + 'n': 556, + 'o': 500, + 'p': 500, + 'q': 500, + 'r': 389, + 's': 389, + 't': 278, + 'u': 556, + 'v': 444, + 'w': 667, + 'x': 500, + 'y': 444, + 'z': 389, + 'braceleft': 348, + 'bar': 220, + 'braceright': 348, + 'asciitilde': 570, + 'exclamdown': 389, + 'cent': 500, + 'sterling': 500, + 'fraction': 167, + 'yen': 500, + 'florin': 500, + 'section': 500, + 'currency': 500, + 'quotesingle': 278, + 'quotedblleft': 500, + 'guillemotleft': 500, + 'guilsinglleft': 333, + 'guilsinglright': 333, + 'fi': 556, + 'fl': 556, + 'endash': 500, + 'dagger': 500, + 'daggerdbl': 500, + 'periodcentered': 250, + 'paragraph': 500, + 'bullet': 350, + 'quotesinglbase': 333, + 'quotedblbase': 500, + 'quotedblright': 500, + 'guillemotright': 500, + 'ellipsis': 1000, + 'perthousand': 1000, + 'questiondown': 500, + 'grave': 333, + 'acute': 333, + 'circumflex': 333, + 'tilde': 333, + 'macron': 333, + 'breve': 333, + 'dotaccent': 333, + 'dieresis': 333, + 'ring': 333, + 'cedilla': 333, + 'hungarumlaut': 333, + 'ogonek': 333, + 'caron': 333, + 'emdash': 1000, + 'AE': 944, + 'ordfeminine': 266, + 'Lslash': 611, + 'Oslash': 722, + 'OE': 944, + 'ordmasculine': 300, + 'ae': 722, + 'dotlessi': 278, + 'lslash': 278, + 'oslash': 500, + 'oe': 722, + 'germandbls': 500, + 'Idieresis': 389, + 'eacute': 444, + 'abreve': 500, + 'uhungarumlaut': 556, + 'ecaron': 444, + 'Ydieresis': 611, + 'divide': 570, + 'Yacute': 611, + 'Acircumflex': 667, + 'aacute': 500, + 'Ucircumflex': 722, + 'yacute': 444, + 'scommaaccent': 389, + 'ecircumflex': 444, + 'Uring': 722, + 'Udieresis': 722, + 'aogonek': 500, + 'Uacute': 722, + 'uogonek': 556, + 'Edieresis': 667, + 'Dcroat': 722, + 'commaaccent': 250, + 'copyright': 747, + 'Emacron': 667, + 'ccaron': 444, + 'aring': 500, + 'Ncommaaccent': 722, + 'lacute': 278, + 'agrave': 500, + 'Tcommaaccent': 611, + 'Cacute': 667, + 'atilde': 500, + 'Edotaccent': 667, + 'scaron': 389, + 'scedilla': 389, + 'iacute': 278, + 'lozenge': 494, + 'Rcaron': 667, + 'Gcommaaccent': 722, + 'ucircumflex': 556, + 'acircumflex': 500, + 'Amacron': 667, + 'rcaron': 389, + 'ccedilla': 444, + 'Zdotaccent': 611, + 'Thorn': 611, + 'Omacron': 722, + 'Racute': 667, + 'Sacute': 556, + 'dcaron': 608, + 'Umacron': 722, + 'uring': 556, + 'threesuperior': 300, + 'Ograve': 722, + 'Agrave': 667, + 'Abreve': 667, + 'multiply': 570, + 'uacute': 556, + 'Tcaron': 611, + 'partialdiff': 494, + 'ydieresis': 444, + 'Nacute': 722, + 'icircumflex': 278, + 'Ecircumflex': 667, + 'adieresis': 500, + 'edieresis': 444, + 'cacute': 444, + 'nacute': 556, + 'umacron': 556, + 'Ncaron': 722, + 'Iacute': 389, + 'plusminus': 570, + 'brokenbar': 220, + 'registered': 747, + 'Gbreve': 722, + 'Idotaccent': 389, + 'summation': 600, + 'Egrave': 667, + 'racute': 389, + 'omacron': 500, + 'Zacute': 611, + 'Zcaron': 611, + 'greaterequal': 549, + 'Eth': 722, + 'Ccedilla': 667, + 'lcommaaccent': 278, + 'tcaron': 366, + 'eogonek': 444, + 'Uogonek': 722, + 'Aacute': 667, + 'Adieresis': 667, + 'egrave': 444, + 'zacute': 389, + 'iogonek': 278, + 'Oacute': 722, + 'oacute': 500, + 'amacron': 500, + 'sacute': 389, + 'idieresis': 278, + 'Ocircumflex': 722, + 'Ugrave': 722, + 'Delta': 612, + 'thorn': 500, + 'twosuperior': 300, + 'Odieresis': 722, + 'mu': 576, + 'igrave': 278, + 'ohungarumlaut': 500, + 'Eogonek': 667, + 'dcroat': 500, + 'threequarters': 750, + 'Scedilla': 556, + 'lcaron': 382, + 'Kcommaaccent': 667, + 'Lacute': 611, + 'trademark': 1000, + 'edotaccent': 444, + 'Igrave': 389, + 'Imacron': 389, + 'Lcaron': 611, + 'onehalf': 750, + 'lessequal': 549, + 'ocircumflex': 500, + 'ntilde': 556, + 'Uhungarumlaut': 722, + 'Eacute': 667, + 'emacron': 444, + 'gbreve': 500, + 'onequarter': 750, + 'Scaron': 556, + 'Scommaaccent': 556, + 'Ohungarumlaut': 722, + 'degree': 400, + 'ograve': 500, + 'Ccaron': 667, + 'ugrave': 556, + 'radical': 549, + 'Dcaron': 722, + 'rcommaaccent': 389, + 'Ntilde': 722, + 'otilde': 500, + 'Rcommaaccent': 667, + 'Lcommaaccent': 611, + 'Atilde': 667, + 'Aogonek': 667, + 'Aring': 667, + 'Otilde': 722, + 'zdotaccent': 389, + 'Ecaron': 667, + 'Iogonek': 389, + 'kcommaaccent': 500, + 'minus': 606, + 'Icircumflex': 389, + 'ncaron': 556, + 'tcommaaccent': 278, + 'logicalnot': 606, + 'odieresis': 500, + 'udieresis': 556, + 'notequal': 549, + 'gcommaaccent': 500, + 'eth': 500, + 'zcaron': 389, + 'ncommaaccent': 556, + 'onesuperior': 300, + 'imacron': 278, + 'Euro': 500 + }, + 'Times-Italic': { + 'space': 250, + 'exclam': 333, + 'quotedbl': 420, + 'numbersign': 500, + 'dollar': 500, + 'percent': 833, + 'ampersand': 778, + 'quoteright': 333, + 'parenleft': 333, + 'parenright': 333, + 'asterisk': 500, + 'plus': 675, + 'comma': 250, + 'hyphen': 333, + 'period': 250, + 'slash': 278, + 'zero': 500, + 'one': 500, + 'two': 500, + 'three': 500, + 'four': 500, + 'five': 500, + 'six': 500, + 'seven': 500, + 'eight': 500, + 'nine': 500, + 'colon': 333, + 'semicolon': 333, + 'less': 675, + 'equal': 675, + 'greater': 675, + 'question': 500, + 'at': 920, + 'A': 611, + 'B': 611, + 'C': 667, + 'D': 722, + 'E': 611, + 'F': 611, + 'G': 722, + 'H': 722, + 'I': 333, + 'J': 444, + 'K': 667, + 'L': 556, + 'M': 833, + 'N': 667, + 'O': 722, + 'P': 611, + 'Q': 722, + 'R': 611, + 'S': 500, + 'T': 556, + 'U': 722, + 'V': 611, + 'W': 833, + 'X': 611, + 'Y': 556, + 'Z': 556, + 'bracketleft': 389, + 'backslash': 278, + 'bracketright': 389, + 'asciicircum': 422, + 'underscore': 500, + 'quoteleft': 333, + 'a': 500, + 'b': 500, + 'c': 444, + 'd': 500, + 'e': 444, + 'f': 278, + 'g': 500, + 'h': 500, + 'i': 278, + 'j': 278, + 'k': 444, + 'l': 278, + 'm': 722, + 'n': 500, + 'o': 500, + 'p': 500, + 'q': 500, + 'r': 389, + 's': 389, + 't': 278, + 'u': 500, + 'v': 444, + 'w': 667, + 'x': 444, + 'y': 444, + 'z': 389, + 'braceleft': 400, + 'bar': 275, + 'braceright': 400, + 'asciitilde': 541, + 'exclamdown': 389, + 'cent': 500, + 'sterling': 500, + 'fraction': 167, + 'yen': 500, + 'florin': 500, + 'section': 500, + 'currency': 500, + 'quotesingle': 214, + 'quotedblleft': 556, + 'guillemotleft': 500, + 'guilsinglleft': 333, + 'guilsinglright': 333, + 'fi': 500, + 'fl': 500, + 'endash': 500, + 'dagger': 500, + 'daggerdbl': 500, + 'periodcentered': 250, + 'paragraph': 523, + 'bullet': 350, + 'quotesinglbase': 333, + 'quotedblbase': 556, + 'quotedblright': 556, + 'guillemotright': 500, + 'ellipsis': 889, + 'perthousand': 1000, + 'questiondown': 500, + 'grave': 333, + 'acute': 333, + 'circumflex': 333, + 'tilde': 333, + 'macron': 333, + 'breve': 333, + 'dotaccent': 333, + 'dieresis': 333, + 'ring': 333, + 'cedilla': 333, + 'hungarumlaut': 333, + 'ogonek': 333, + 'caron': 333, + 'emdash': 889, + 'AE': 889, + 'ordfeminine': 276, + 'Lslash': 556, + 'Oslash': 722, + 'OE': 944, + 'ordmasculine': 310, + 'ae': 667, + 'dotlessi': 278, + 'lslash': 278, + 'oslash': 500, + 'oe': 667, + 'germandbls': 500, + 'Idieresis': 333, + 'eacute': 444, + 'abreve': 500, + 'uhungarumlaut': 500, + 'ecaron': 444, + 'Ydieresis': 556, + 'divide': 675, + 'Yacute': 556, + 'Acircumflex': 611, + 'aacute': 500, + 'Ucircumflex': 722, + 'yacute': 444, + 'scommaaccent': 389, + 'ecircumflex': 444, + 'Uring': 722, + 'Udieresis': 722, + 'aogonek': 500, + 'Uacute': 722, + 'uogonek': 500, + 'Edieresis': 611, + 'Dcroat': 722, + 'commaaccent': 250, + 'copyright': 760, + 'Emacron': 611, + 'ccaron': 444, + 'aring': 500, + 'Ncommaaccent': 667, + 'lacute': 278, + 'agrave': 500, + 'Tcommaaccent': 556, + 'Cacute': 667, + 'atilde': 500, + 'Edotaccent': 611, + 'scaron': 389, + 'scedilla': 389, + 'iacute': 278, + 'lozenge': 471, + 'Rcaron': 611, + 'Gcommaaccent': 722, + 'ucircumflex': 500, + 'acircumflex': 500, + 'Amacron': 611, + 'rcaron': 389, + 'ccedilla': 444, + 'Zdotaccent': 556, + 'Thorn': 611, + 'Omacron': 722, + 'Racute': 611, + 'Sacute': 500, + 'dcaron': 544, + 'Umacron': 722, + 'uring': 500, + 'threesuperior': 300, + 'Ograve': 722, + 'Agrave': 611, + 'Abreve': 611, + 'multiply': 675, + 'uacute': 500, + 'Tcaron': 556, + 'partialdiff': 476, + 'ydieresis': 444, + 'Nacute': 667, + 'icircumflex': 278, + 'Ecircumflex': 611, + 'adieresis': 500, + 'edieresis': 444, + 'cacute': 444, + 'nacute': 500, + 'umacron': 500, + 'Ncaron': 667, + 'Iacute': 333, + 'plusminus': 675, + 'brokenbar': 275, + 'registered': 760, + 'Gbreve': 722, + 'Idotaccent': 333, + 'summation': 600, + 'Egrave': 611, + 'racute': 389, + 'omacron': 500, + 'Zacute': 556, + 'Zcaron': 556, + 'greaterequal': 549, + 'Eth': 722, + 'Ccedilla': 667, + 'lcommaaccent': 278, + 'tcaron': 300, + 'eogonek': 444, + 'Uogonek': 722, + 'Aacute': 611, + 'Adieresis': 611, + 'egrave': 444, + 'zacute': 389, + 'iogonek': 278, + 'Oacute': 722, + 'oacute': 500, + 'amacron': 500, + 'sacute': 389, + 'idieresis': 278, + 'Ocircumflex': 722, + 'Ugrave': 722, + 'Delta': 612, + 'thorn': 500, + 'twosuperior': 300, + 'Odieresis': 722, + 'mu': 500, + 'igrave': 278, + 'ohungarumlaut': 500, + 'Eogonek': 611, + 'dcroat': 500, + 'threequarters': 750, + 'Scedilla': 500, + 'lcaron': 300, + 'Kcommaaccent': 667, + 'Lacute': 556, + 'trademark': 980, + 'edotaccent': 444, + 'Igrave': 333, + 'Imacron': 333, + 'Lcaron': 611, + 'onehalf': 750, + 'lessequal': 549, + 'ocircumflex': 500, + 'ntilde': 500, + 'Uhungarumlaut': 722, + 'Eacute': 611, + 'emacron': 444, + 'gbreve': 500, + 'onequarter': 750, + 'Scaron': 500, + 'Scommaaccent': 500, + 'Ohungarumlaut': 722, + 'degree': 400, + 'ograve': 500, + 'Ccaron': 667, + 'ugrave': 500, + 'radical': 453, + 'Dcaron': 722, + 'rcommaaccent': 389, + 'Ntilde': 667, + 'otilde': 500, + 'Rcommaaccent': 611, + 'Lcommaaccent': 556, + 'Atilde': 611, + 'Aogonek': 611, + 'Aring': 611, + 'Otilde': 722, + 'zdotaccent': 389, + 'Ecaron': 611, + 'Iogonek': 333, + 'kcommaaccent': 444, + 'minus': 675, + 'Icircumflex': 333, + 'ncaron': 500, + 'tcommaaccent': 278, + 'logicalnot': 675, + 'odieresis': 500, + 'udieresis': 500, + 'notequal': 549, + 'gcommaaccent': 500, + 'eth': 500, + 'zcaron': 389, + 'ncommaaccent': 500, + 'onesuperior': 300, + 'imacron': 278, + 'Euro': 500 + }, + 'ZapfDingbats': { + 'space': 278, + 'a1': 974, + 'a2': 961, + 'a202': 974, + 'a3': 980, + 'a4': 719, + 'a5': 789, + 'a119': 790, + 'a118': 791, + 'a117': 690, + 'a11': 960, + 'a12': 939, + 'a13': 549, + 'a14': 855, + 'a15': 911, + 'a16': 933, + 'a105': 911, + 'a17': 945, + 'a18': 974, + 'a19': 755, + 'a20': 846, + 'a21': 762, + 'a22': 761, + 'a23': 571, + 'a24': 677, + 'a25': 763, + 'a26': 760, + 'a27': 759, + 'a28': 754, + 'a6': 494, + 'a7': 552, + 'a8': 537, + 'a9': 577, + 'a10': 692, + 'a29': 786, + 'a30': 788, + 'a31': 788, + 'a32': 790, + 'a33': 793, + 'a34': 794, + 'a35': 816, + 'a36': 823, + 'a37': 789, + 'a38': 841, + 'a39': 823, + 'a40': 833, + 'a41': 816, + 'a42': 831, + 'a43': 923, + 'a44': 744, + 'a45': 723, + 'a46': 749, + 'a47': 790, + 'a48': 792, + 'a49': 695, + 'a50': 776, + 'a51': 768, + 'a52': 792, + 'a53': 759, + 'a54': 707, + 'a55': 708, + 'a56': 682, + 'a57': 701, + 'a58': 826, + 'a59': 815, + 'a60': 789, + 'a61': 789, + 'a62': 707, + 'a63': 687, + 'a64': 696, + 'a65': 689, + 'a66': 786, + 'a67': 787, + 'a68': 713, + 'a69': 791, + 'a70': 785, + 'a71': 791, + 'a72': 873, + 'a73': 761, + 'a74': 762, + 'a203': 762, + 'a75': 759, + 'a204': 759, + 'a76': 892, + 'a77': 892, + 'a78': 788, + 'a79': 784, + 'a81': 438, + 'a82': 138, + 'a83': 277, + 'a84': 415, + 'a97': 392, + 'a98': 392, + 'a99': 668, + 'a100': 668, + 'a89': 390, + 'a90': 390, + 'a93': 317, + 'a94': 317, + 'a91': 276, + 'a92': 276, + 'a205': 509, + 'a85': 509, + 'a206': 410, + 'a86': 410, + 'a87': 234, + 'a88': 234, + 'a95': 334, + 'a96': 334, + 'a101': 732, + 'a102': 544, + 'a103': 544, + 'a104': 910, + 'a106': 667, + 'a107': 760, + 'a108': 760, + 'a112': 776, + 'a111': 595, + 'a110': 694, + 'a109': 626, + 'a120': 788, + 'a121': 788, + 'a122': 788, + 'a123': 788, + 'a124': 788, + 'a125': 788, + 'a126': 788, + 'a127': 788, + 'a128': 788, + 'a129': 788, + 'a130': 788, + 'a131': 788, + 'a132': 788, + 'a133': 788, + 'a134': 788, + 'a135': 788, + 'a136': 788, + 'a137': 788, + 'a138': 788, + 'a139': 788, + 'a140': 788, + 'a141': 788, + 'a142': 788, + 'a143': 788, + 'a144': 788, + 'a145': 788, + 'a146': 788, + 'a147': 788, + 'a148': 788, + 'a149': 788, + 'a150': 788, + 'a151': 788, + 'a152': 788, + 'a153': 788, + 'a154': 788, + 'a155': 788, + 'a156': 788, + 'a157': 788, + 'a158': 788, + 'a159': 788, + 'a160': 894, + 'a161': 838, + 'a163': 1016, + 'a164': 458, + 'a196': 748, + 'a165': 924, + 'a192': 748, + 'a166': 918, + 'a167': 927, + 'a168': 928, + 'a169': 928, + 'a170': 834, + 'a171': 873, + 'a172': 828, + 'a173': 924, + 'a162': 924, + 'a174': 917, + 'a175': 930, + 'a176': 931, + 'a177': 463, + 'a178': 883, + 'a179': 836, + 'a193': 836, + 'a180': 867, + 'a199': 867, + 'a181': 696, + 'a200': 696, + 'a182': 874, + 'a201': 874, + 'a183': 760, + 'a184': 946, + 'a197': 771, + 'a185': 865, + 'a194': 771, + 'a198': 888, + 'a186': 967, + 'a195': 888, + 'a187': 831, + 'a188': 873, + 'a189': 927, + 'a190': 970, + 'a191': 918 + } +}; diff --git a/pdf.js b/pdf.js index 824138464..0b810a3ee 100644 --- a/pdf.js +++ b/pdf.js @@ -85,12 +85,15 @@ function stringToBytes(str) { } var PDFStringTranslateTable = [ - ,,,,,,,,,,,,,,,,,,,,,,,, 0x2D8, 0x2C7, 0x2C6, 0x2D9, 0x2DD, 0x2DB, 0x2DA, - 0x2DC,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, - ,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0x2D8, 0x2C7, 0x2C6, 0x2D9, 0x2DD, 0x2DB, 0x2DA, 0x2DC, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x192, 0x2044, 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C, - 0x201D, 0x2018, 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x141, 0x152, - 0x160, 0x178, 0x17D, 0x131, 0x142, 0x153, 0x161, 0x17E,, 0x20AC + 0x201D, 0x2018, 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x141, 0x152, 0x160, + 0x178, 0x17D, 0x131, 0x142, 0x153, 0x161, 0x17E, 0, 0x20AC ]; function stringToPDFString(str) { @@ -556,12 +559,6 @@ var FlateStream = (function() { }; constructor.prototype.readBlock = function() { - function repeat(stream, array, len, offset, what) { - var repeatLength = stream.getBits(len) + offset; - while (repeatLength-- > 0) - array[i++] = what; - } - // read block header var hdr = this.getBits(3); if (hdr & 1) @@ -631,14 +628,19 @@ var FlateStream = (function() { while (i < codes) { var code = this.getCode(codeLenCodeTab); if (code == 16) { - repeat(this, codeLengths, 2, 3, len); + var bitsLength = 2, bitsOffset = 3, what = len; } else if (code == 17) { - repeat(this, codeLengths, 3, 3, len = 0); + var bitsLength = 3, bitsOffset = 3, what = (len = 0); } else if (code == 18) { - repeat(this, codeLengths, 7, 11, len = 0); + var bitsLength = 7, bitsOffset = 11, what = (len = 0); } else { codeLengths[i++] = len = code; + continue; } + + var repeatLength = this.getBits(bitsLength) + bitsOffset; + while (repeatLength-- > 0) + codeLengths[i++] = what; } litCodeTable = @@ -711,9 +713,9 @@ var PredictorStream = (function() { var bits = this.bits = params.get('BitsPerComponent') || 8; var columns = this.columns = params.get('Columns') || 1; - var pixBytes = this.pixBytes = (colors * bits + 7) >> 3; + this.pixBytes = (colors * bits + 7) >> 3; // add an extra pixByte to represent the pixel left of column 0 - var rowBytes = this.rowBytes = (columns * colors * bits + 7) >> 3; + this.rowBytes = (columns * colors * bits + 7) >> 3; DecodeStream.call(this); return this; @@ -723,7 +725,6 @@ var PredictorStream = (function() { constructor.prototype.readBlockTiff = function() { var rowBytes = this.rowBytes; - var pixBytes = this.pixBytes; var bufferLength = this.bufferLength; var buffer = this.ensureBuffer(bufferLength + rowBytes); @@ -734,16 +735,18 @@ var PredictorStream = (function() { var rawBytes = this.stream.getBytes(rowBytes); + var inbuf = 0, outbuf = 0; + var inbits = 0, outbits = 0; + if (bits === 1) { - var inbuf = 0; for (var i = 0; i < rowBytes; ++i) { var c = rawBytes[i]; - inBuf = (inBuf << 8) | c; + inbuf = (inbuf << 8) | c; // bitwise addition is exclusive or - // first shift inBuf and then add - currentRow[i] = (c ^ (inBuf >> colors)) & 0xFF; - // truncate inBuf (assumes colors < 16) - inBuf &= 0xFFFF; + // first shift inbuf and then add + currentRow[i] = (c ^ (inbuf >> colors)) & 0xFF; + // truncate inbuf (assumes colors < 16) + inbuf &= 0xFFFF; } } else if (bits === 8) { for (var i = 0; i < colors; ++i) @@ -753,8 +756,6 @@ var PredictorStream = (function() { } else { var compArray = new Uint8Array(colors + 1); var bitMask = (1 << bits) - 1; - var inbuf = 0, outbut = 0; - var inbits = 0, outbits = 0; var j = 0, k = 0; var columns = this.columns; for (var i = 0; i < columns; ++i) { @@ -798,59 +799,58 @@ var PredictorStream = (function() { prevRow = currentRow; switch (predictor) { - case 0: - break; - case 1: - for (var i = 0; i < pixBytes; ++i) - currentRow[i] = rawBytes[i]; - for (; i < rowBytes; ++i) - currentRow[i] = (currentRow[i - pixBytes] + rawBytes[i]) & 0xFF; - break; - case 2: - for (var i = 0; i < rowBytes; ++i) - currentRow[i] = (prevRow[i] + rawBytes[i]) & 0xFF; - break; - case 3: - for (var i = 0; i < pixBytes; ++i) - currentRow[i] = (prevRow[i] >> 1) + rawBytes[i]; - for (; i < rowBytes; ++i) { - currentRow[i] = (((prevRow[i] + currentRow[i - pixBytes]) >> 1) + - rawBytes[i]) & 0xFF; - } - break; - case 4: - // we need to save the up left pixels values. the simplest way - // is to create a new buffer - for (var i = 0; i < pixBytes; ++i) - currentRow[i] = rawBytes[i]; - for (; i < rowBytes; ++i) { - var up = prevRow[i]; - var upLeft = lastRow[i - pixBytes]; - var left = currentRow[i - pixBytes]; - var p = left + up - upLeft; + case 0: + break; + case 1: + for (var i = 0; i < pixBytes; ++i) + currentRow[i] = rawBytes[i]; + for (; i < rowBytes; ++i) + currentRow[i] = (currentRow[i - pixBytes] + rawBytes[i]) & 0xFF; + break; + case 2: + for (var i = 0; i < rowBytes; ++i) + currentRow[i] = (prevRow[i] + rawBytes[i]) & 0xFF; + break; + case 3: + for (var i = 0; i < pixBytes; ++i) + currentRow[i] = (prevRow[i] >> 1) + rawBytes[i]; + for (; i < rowBytes; ++i) { + currentRow[i] = (((prevRow[i] + currentRow[i - pixBytes]) >> 1) + + rawBytes[i]) & 0xFF; + } + break; + case 4: + // we need to save the up left pixels values. the simplest way + // is to create a new buffer + for (var i = 0; i < pixBytes; ++i) + currentRow[i] = rawBytes[i]; + for (; i < rowBytes; ++i) { + var up = prevRow[i]; + var upLeft = prevRow[i - pixBytes]; + var left = currentRow[i - pixBytes]; + var p = left + up - upLeft; - var pa = p - left; - if (pa < 0) - pa = -pa; - var pb = p - up; - if (pb < 0) - pb = -pb; - var pc = p - upLeft; - if (pc < 0) - pc = -pc; + var pa = p - left; + if (pa < 0) + pa = -pa; + var pb = p - up; + if (pb < 0) + pb = -pb; + var pc = p - upLeft; + if (pc < 0) + pc = -pc; - var c = rawBytes[i]; - if (pa <= pb && pa <= pc) - currentRow[i] = left + c; - else if (pb <= pc) - currentRow[i] = up + c; - else - currentRow[i] = upLeft + c; - } - break; - default: - error('Unsupported predictor: ' + predictor); - break; + var c = rawBytes[i]; + if (pa <= pb && pa <= pc) + currentRow[i] = left + c; + else if (pb <= pc) + currentRow[i] = up + c; + else + currentRow[i] = upLeft + c; + } + break; + default: + error('Unsupported predictor: ' + predictor); } this.bufferLength += rowBytes; }; @@ -861,11 +861,44 @@ var PredictorStream = (function() { // A JpegStream can't be read directly. We use the platform to render // the underlying JPEG data for us. var JpegStream = (function() { + function isYcckImage(bytes) { + var maxBytesScanned = Math.max(bytes.length - 16, 1024); + // Looking for APP14, 'Adobe' and transform = 2 + for (var i = 0; i < maxBytesScanned; ++i) { + if (bytes[i] == 0xFF && bytes[i + 1] == 0xEE && + bytes[i + 2] == 0x00 && bytes[i + 3] == 0x0E && + bytes[i + 4] == 0x41 && bytes[i + 5] == 0x64 && + bytes[i + 6] == 0x6F && bytes[i + 7] == 0x62 && + bytes[i + 8] == 0x65 && bytes[i + 9] == 0x00) + return bytes[i + 15] == 0x02; + // scanning until frame tag + if (bytes[i] == 0xFF && bytes[i + 1] == 0xC0) + break; + } + return false; + } + + function fixYcckImage(bytes) { + // Inserting 'EMBED' marker after JPEG signature + var embedMarker = new Uint8Array([0xFF, 0xEC, 0, 8, 0x45, 0x4D, 0x42, 0x45, + 0x44, 0]); + var newBytes = new Uint8Array(bytes.length + embedMarker.length); + newBytes.set(bytes, embedMarker.length); + // copy JPEG header + newBytes[0] = bytes[0]; + newBytes[1] = bytes[1]; + newBytes.set(embedMarker, 2); + return newBytes; + } + function constructor(bytes, dict) { // TODO: per poppler, some images may have "junk" before that // need to be removed this.dict = dict; + if (isYcckImage(bytes)) + bytes = fixYcckImage(bytes); + // create DOM image var img = new Image(); img.onload = (function() { @@ -985,11 +1018,11 @@ var Ascii85Stream = (function() { return; } - var bufferLength = this.bufferLength; + var bufferLength = this.bufferLength, buffer; // special code for z if (c == zCode) { - var buffer = this.ensureBuffer(bufferLength + 4); + buffer = this.ensureBuffer(bufferLength + 4); for (var i = 0; i < 4; ++i) buffer[bufferLength + i] = 0; this.bufferLength += 4; @@ -1006,7 +1039,7 @@ var Ascii85Stream = (function() { if (!c || c == tildaCode) break; } - var buffer = this.ensureBuffer(bufferLength + i - 1); + buffer = this.ensureBuffer(bufferLength + i - 1); this.bufferLength += i - 1; // partial ending; @@ -1553,7 +1586,7 @@ var CCITTFaxStream = (function() { this.row = 0; this.nextLine2D = this.encoding < 0; this.inputBits = 0; - this.inputBuf; + this.inputBuf = 0; this.outputBits = 0; this.buf = EOF; @@ -1661,129 +1694,128 @@ var CCITTFaxStream = (function() { while (codingLine[this.codingPos] < columns) { code1 = this.getTwoDimCode(); switch (code1) { - case twoDimPass: - this.addPixels(refLine[refPos + 1], blackPixels); - if (refLine[refPos + 1] < columns) - refPos += 2; - break; - case twoDimHoriz: - code1 = code2 = 0; - if (blackPixels) { - do { - code1 += (code3 = this.getBlackCode()); - } while (code3 >= 64); - do { - code2 += (code3 = this.getWhiteCode()); - } while (code3 >= 64); - } else { - do { - code1 += (code3 = this.getWhiteCode()); - } while (code3 >= 64); - do { - code2 += (code3 = this.getBlackCode()); - } while (code3 >= 64); - } - this.addPixels(codingLine[this.codingPos] + - code1, blackPixels); - if (codingLine[this.codingPos] < columns) { - this.addPixels(codingLine[this.codingPos] + code2, - blackPixels ^ 1); - } - while (refLine[refPos] <= codingLine[this.codingPos] && - refLine[refPos] < columns) { - refPos += 2; - } - break; - case twoDimVertR3: - this.addPixels(refLine[refPos] + 3, blackPixels); - blackPixels ^= 1; - if (codingLine[this.codingPos] < columns) { - ++refPos; - while (refLine[refPos] <= codingLine[this.codingPos] && - refLine[refPos] < columns) + case twoDimPass: + this.addPixels(refLine[refPos + 1], blackPixels); + if (refLine[refPos + 1] < columns) refPos += 2; - } - break; - case twoDimVertR2: - this.addPixels(refLine[refPos] + 2, blackPixels); - blackPixels ^= 1; - if (codingLine[this.codingPos] < columns) { - ++refPos; + break; + case twoDimHoriz: + code1 = code2 = 0; + if (blackPixels) { + do { + code1 += (code3 = this.getBlackCode()); + } while (code3 >= 64); + do { + code2 += (code3 = this.getWhiteCode()); + } while (code3 >= 64); + } else { + do { + code1 += (code3 = this.getWhiteCode()); + } while (code3 >= 64); + do { + code2 += (code3 = this.getBlackCode()); + } while (code3 >= 64); + } + this.addPixels(codingLine[this.codingPos] + + code1, blackPixels); + if (codingLine[this.codingPos] < columns) { + this.addPixels(codingLine[this.codingPos] + code2, + blackPixels ^ 1); + } while (refLine[refPos] <= codingLine[this.codingPos] && refLine[refPos] < columns) { refPos += 2; } - } - break; - case twoDimVertR1: - this.addPixels(refLine[refPos] + 1, blackPixels); - blackPixels ^= 1; - if (codingLine[this.codingPos] < columns) { - ++refPos; - while (refLine[refPos] <= codingLine[this.codingPos] && - refLine[refPos] < columns) - refPos += 2; - } - break; - case twoDimVert0: - this.addPixels(refLine[refPos], blackPixels); - blackPixels ^= 1; - if (codingLine[this.codingPos] < columns) { - ++refPos; - while (refLine[refPos] <= codingLine[this.codingPos] && - refLine[refPos] < columns) - refPos += 2; - } - break; - case twoDimVertL3: - this.addPixelsNeg(refLine[refPos] - 3, blackPixels); - blackPixels ^= 1; - if (codingLine[this.codingPos] < columns) { - if (refPos > 0) - --refPos; - else + break; + case twoDimVertR3: + this.addPixels(refLine[refPos] + 3, blackPixels); + blackPixels ^= 1; + if (codingLine[this.codingPos] < columns) { ++refPos; - while (refLine[refPos] <= codingLine[this.codingPos] && - refLine[refPos] < columns) - refPos += 2; - } - break; - case twoDimVertL2: - this.addPixelsNeg(refLine[refPos] - 2, blackPixels); - blackPixels ^= 1; - if (codingLine[this.codingPos] < columns) { - if (refPos > 0) - --refPos; - else + while (refLine[refPos] <= codingLine[this.codingPos] && + refLine[refPos] < columns) + refPos += 2; + } + break; + case twoDimVertR2: + this.addPixels(refLine[refPos] + 2, blackPixels); + blackPixels ^= 1; + if (codingLine[this.codingPos] < columns) { ++refPos; - while (refLine[refPos] <= codingLine[this.codingPos] && - refLine[refPos] < columns) - refPos += 2; - } - break; - case twoDimVertL1: - this.addPixelsNeg(refLine[refPos] - 1, blackPixels); - blackPixels ^= 1; - if (codingLine[this.codingPos] < columns) { - if (refPos > 0) - --refPos; - else + while (refLine[refPos] <= codingLine[this.codingPos] && + refLine[refPos] < columns) { + refPos += 2; + } + } + break; + case twoDimVertR1: + this.addPixels(refLine[refPos] + 1, blackPixels); + blackPixels ^= 1; + if (codingLine[this.codingPos] < columns) { ++refPos; + while (refLine[refPos] <= codingLine[this.codingPos] && + refLine[refPos] < columns) + refPos += 2; + } + break; + case twoDimVert0: + this.addPixels(refLine[refPos], blackPixels); + blackPixels ^= 1; + if (codingLine[this.codingPos] < columns) { + ++refPos; + while (refLine[refPos] <= codingLine[this.codingPos] && + refLine[refPos] < columns) + refPos += 2; + } + break; + case twoDimVertL3: + this.addPixelsNeg(refLine[refPos] - 3, blackPixels); + blackPixels ^= 1; + if (codingLine[this.codingPos] < columns) { + if (refPos > 0) + --refPos; + else + ++refPos; + while (refLine[refPos] <= codingLine[this.codingPos] && + refLine[refPos] < columns) + refPos += 2; + } + break; + case twoDimVertL2: + this.addPixelsNeg(refLine[refPos] - 2, blackPixels); + blackPixels ^= 1; + if (codingLine[this.codingPos] < columns) { + if (refPos > 0) + --refPos; + else + ++refPos; + while (refLine[refPos] <= codingLine[this.codingPos] && + refLine[refPos] < columns) + refPos += 2; + } + break; + case twoDimVertL1: + this.addPixelsNeg(refLine[refPos] - 1, blackPixels); + blackPixels ^= 1; + if (codingLine[this.codingPos] < columns) { + if (refPos > 0) + --refPos; + else + ++refPos; - while (refLine[refPos] <= codingLine[this.codingPos] && - refLine[refPos] < columns) - refPos += 2; - } - break; - case EOF: - this.addPixels(columns, 0); - this.eof = true; - break; - default: - warn('bad 2d code'); - this.addPixels(columns, 0); - this.err = true; - break; + while (refLine[refPos] <= codingLine[this.codingPos] && + refLine[refPos] < columns) + refPos += 2; + } + break; + case EOF: + this.addPixels(columns, 0); + this.eof = true; + break; + default: + warn('bad 2d code'); + this.addPixels(columns, 0); + this.err = true; } } } else { @@ -1844,7 +1876,7 @@ var CCITTFaxStream = (function() { for (var i = 0; i < 4; ++i) { code1 = this.lookBits(12); if (code1 != 1) - warning('bad rtc code'); + warn('bad rtc code: ' + code1); this.eatBits(12); if (this.encoding > 0) { this.lookBits(1); @@ -1983,7 +2015,7 @@ var CCITTFaxStream = (function() { } } for (var n = 11; n <= 12; ++n) { - code == this.lookBits(n); + code = this.lookBits(n); if (code == EOF) return 1; if (n < 12) @@ -2407,11 +2439,6 @@ var Lexer = (function() { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx ]; - var MIN_INT = (1 << 31) | 0; - var MAX_INT = (MIN_INT - 1) | 0; - var MIN_UINT = 0; - var MAX_UINT = ((1 << 30) * 4) - 1; - function ToHexDigit(ch) { if (ch >= '0' && ch <= '9') return ch.charCodeAt(0) - 48; @@ -2459,79 +2486,77 @@ var Lexer = (function() { do { ch = stream.getChar(); switch (ch) { - case undefined: - warn('Unterminated string'); - done = true; - break; - case '(': - ++numParen; - str += ch; - break; - case ')': - if (--numParen == 0) { - done = true; - } else { - str += ch; - } - break; - case '\\': - ch = stream.getChar(); - switch (ch) { case undefined: warn('Unterminated string'); done = true; break; - case 'n': - str += '\n'; - break; - case 'r': - str += '\r'; - break; - case 't': - str += '\t'; - break; - case 'b': - str += '\b'; - break; - case 'f': - str += '\f'; - break; - case '\\': case '(': - case ')': + ++numParen; str += ch; break; - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - var x = ch - '0'; - ch = stream.lookChar(); - if (ch >= '0' && ch <= '7') { - stream.skip(); - x = (x << 3) + (ch - '0'); - ch = stream.lookChar(); - if (ch >= '0' && ch <= '7') { - stream.skip(); - x = (x << 3) + (ch - '0'); - } + case ')': + if (--numParen == 0) { + done = true; + } else { + str += ch; } + break; + case '\\': + ch = stream.getChar(); + switch (ch) { + case undefined: + warn('Unterminated string'); + done = true; + break; + case 'n': + str += '\n'; + break; + case 'r': + str += '\r'; + break; + case 't': + str += '\t'; + break; + case 'b': + str += '\b'; + break; + case 'f': + str += '\f'; + break; + case '\\': + case '(': + case ')': + str += ch; + break; + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + var x = ch - '0'; + ch = stream.lookChar(); + if (ch >= '0' && ch <= '7') { + stream.skip(); + x = (x << 3) + (ch - '0'); + ch = stream.lookChar(); + if (ch >= '0' && ch <= '7') { + stream.skip(); + x = (x << 3) + (ch - '0'); + } + } - str += String.fromCharCode(x); - break; - case '\r': - ch = stream.lookChar(); - if (ch == '\n') - stream.skip(); - break; - case '\n': + str += String.fromCharCode(x); + break; + case '\r': + ch = stream.lookChar(); + if (ch == '\n') + stream.skip(); + break; + case '\n': + break; + default: + str += ch; + } break; default: str += ch; - break; - } - break; - default: - str += ch; - break; } } while (!done); return str; @@ -2612,41 +2637,41 @@ var Lexer = (function() { // start reading token switch (ch) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - case '+': case '-': case '.': - return this.getNumber(ch); - case '(': - return this.getString(); - case '/': - return this.getName(ch); - // array punctuation - case '[': - case ']': - return new Cmd(ch); - // hex string or dict punctuation - case '<': - ch = stream.lookChar(); - if (ch == '<') { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '+': case '-': case '.': + return this.getNumber(ch); + case '(': + return this.getString(); + case '/': + return this.getName(ch); + // array punctuation + case '[': + case ']': + return new Cmd(ch); + // hex string or dict punctuation + case '<': + ch = stream.lookChar(); + if (ch == '<') { + // dict punctuation + stream.skip(); + return new Cmd('<<'); + } + return this.getHexString(ch); // dict punctuation - stream.skip(); - return new Cmd('<<'); - } - return this.getHexString(ch); - // dict punctuation - case '>': - ch = stream.lookChar(); - if (ch == '>') { - stream.skip(); - return new Cmd('>>'); - } - case '{': - case '}': - return new Cmd(ch); - // fall through - case ')': - error('Illegal character: ' + ch); - return Error; + case '>': + ch = stream.lookChar(); + if (ch == '>') { + stream.skip(); + return new Cmd('>>'); + } + case '{': + case '}': + return new Cmd(ch); + // fall through + case ')': + error('Illegal character: ' + ch); + return Error; } // command @@ -2865,6 +2890,8 @@ var Parser = (function() { if (IsArray(paramsArray) && (i in paramsArray)) params = paramsArray[i]; stream = this.makeFilter(stream, filter.name, length, params); + // after the first stream the length variable is invalid + length = null; } } } @@ -3077,7 +3104,6 @@ var XRef = (function() { }, readXRefStream: function readXRefStream(stream) { var streamParameters = stream.parameters; - var length = streamParameters.get('Length'); var byteWidths = streamParameters.get('W'); var range = streamParameters.get('Index'); if (!range) @@ -3109,17 +3135,16 @@ var XRef = (function() { entry.offset = offset; entry.gen = generation; switch (type) { - case 0: - entry.free = true; - break; - case 1: - entry.uncompressed = true; - break; - case 2: - break; - default: - error('Invalid XRef entry type: ' + type); - break; + case 0: + entry.free = true; + break; + case 1: + entry.uncompressed = true; + break; + case 2: + break; + default: + error('Invalid XRef entry type: ' + type); } if (!this.entries[first + i]) this.entries[first + i] = entry; @@ -3162,7 +3187,7 @@ var XRef = (function() { return obj; return this.fetch(obj); }, - fetch: function(ref) { + fetch: function(ref, suppressEncryption) { var num = ref.num; var e = this.cache[num]; if (e) @@ -3193,8 +3218,15 @@ var XRef = (function() { } error('bad XRef entry'); } - if (this.encrypt) { - e = parser.getObj(this.encrypt.createCipherTransform(num, gen)); + if (this.encrypt && !suppressEncryption) { + try { + e = parser.getObj(this.encrypt.createCipherTransform(num, gen)); + } catch (ex) { + // almost all streams must be encrypted, but sometimes + // they are not probably due to some broken generators + // re-trying without encryption + return this.fetch(ref, true); + } } else { e = parser.getObj(); } @@ -3326,7 +3358,7 @@ var Page = (function() { } return shadow(this, 'rotate', rotate); }, - startRendering: function(canvasCtx, continuation, onerror) { + startRendering: function(canvasCtx, continuation) { var self = this; var stats = self.stats; stats.compile = stats.fonts = stats.render = 0; @@ -3349,7 +3381,7 @@ var Page = (function() { } catch (e) { exc = e.toString(); } - continuation(exc); + if (continuation) continuation(exc); }); }; @@ -3446,7 +3478,6 @@ var Page = (function() { break; default: TODO('other link types'); - break; } } else if (annotation.has('Dest')) { // simple destination link @@ -3676,8 +3707,9 @@ var PDFDoc = (function() { if (find(stream, 'startxref', 1024, true)) { stream.skip(9); var ch; - while (Lexer.isSpace(ch = stream.getChar())) -; + do { + ch = stream.getChar(); + } while (Lexer.isSpace(ch)); var str = ''; while ((ch - '0') <= 9) { str += ch; @@ -3725,8 +3757,6 @@ var PDFDoc = (function() { return shadow(this, 'numPages', num); }, getPage: function(n) { - var linearization = this.linearization; - // assert(!linearization, "linearized page access not implemented"); return this.catalog.getPage(n); } }; @@ -3736,38 +3766,42 @@ var PDFDoc = (function() { 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', + 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', + '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', + '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', @@ -3777,168 +3811,177 @@ var Encodings = { ]); }, 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', + 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' + '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' + 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' + 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' + 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', + 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', + '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', @@ -3949,36 +3992,39 @@ var Encodings = { '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' + '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' + 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' ]); } }; @@ -4112,7 +4158,7 @@ var PartialEvaluator = (function() { }; constructor.prototype = { - eval: function(stream, xref, resources, fonts, images) { + evaluate: function(stream, xref, resources, fonts, images) { resources = xref.fetchIfRef(resources) || new Dict(); var xobjs = xref.fetchIfRef(resources.get('XObject')) || new Dict(); var patterns = xref.fetchIfRef(resources.get('Pattern')) || new Dict(); @@ -4136,8 +4182,9 @@ var PartialEvaluator = (function() { var dict = IsStream(pattern) ? pattern.dict : pattern; var typeNum = dict.get('PatternType'); if (typeNum == 1) { - patternName.code = this.eval(pattern, xref, - dict.get('Resources'), fonts); + patternName.code = this.evaluate(pattern, xref, + dict.get('Resources'), + fonts); } } } @@ -4156,8 +4203,9 @@ var PartialEvaluator = (function() { ); if ('Form' == type.name) { - args[0].code = this.eval(xobj, xref, xobj.dict.get('Resources'), - fonts, images); + args[0].code = this.evaluate(xobj, xref, + xobj.dict.get('Resources'), fonts, + images); } if (xobj instanceof JpegStream) images.bind(xobj); // monitoring image load @@ -4195,10 +4243,34 @@ var PartialEvaluator = (function() { }, extractEncoding: function(dict, xref, properties) { - var type = properties.type; + var type = properties.type, encoding; if (properties.composite) { - // XXX only CIDFontType2 supported for now if (type == 'CIDFontType2') { + 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; + var cidToGidMap = dict.get('CIDToGIDMap'); if (!cidToGidMap || !IsRef(cidToGidMap)) return GlyphsUnicode; @@ -4208,22 +4280,23 @@ var PartialEvaluator = (function() { var glyphsData = glyphsStream.getBytes(0); // Glyph ids are big-endian 2-byte values - var encoding = properties.encoding; + encoding = properties.encoding; // Set encoding 0 to later verify the font has an encoding - encoding[0] = { unicode: 0 }; + 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; - encoding[j >> 1] = { + var code = j >> 1; + var width = glyphsWidths[code]; + encoding[code] = { unicode: glyphID, - width: 0 + width: IsNum(width) ? width : defaultWidth }; } } else if (type == 'CIDFontType0') { - var encoding = xref.fetchIfRef(dict.get('Encoding')); if (IsName(encoding)) { // Encoding is a predefined CMap if (encoding.name == 'Identity-H') { @@ -4244,7 +4317,7 @@ var PartialEvaluator = (function() { var map = properties.encoding; var baseEncoding = null; if (dict.has('Encoding')) { - var encoding = xref.fetchIfRef(dict.get('Encoding')); + encoding = xref.fetchIfRef(dict.get('Encoding')); if (IsDict(encoding)) { var baseName = encoding.get('BaseEncoding'); if (baseName) @@ -4276,21 +4349,28 @@ var PartialEvaluator = (function() { baseEncoding = Encodings.StandardEncoding.slice(); break; default: - warn('Unknown type of font: ' + type); - break; + warn('Unknown type of font: ' + type); } } // 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] || baseEncoding[i]; + var glyph = differences[i]; + if (!glyph) { + glyph = baseEncoding[i]; + // skipping already specified by difference glyphs + if (differences.indexOf(glyph) >= 0) + continue; + } var index = GlyphsUnicode[glyph] || i; + var width = widths[i] || widths[glyph]; map[i] = { unicode: index, - width: properties.widths[i] || properties.defaultWidth + width: IsNum(width) ? width : properties.defaultWidth }; if (glyph) @@ -4307,7 +4387,10 @@ var PartialEvaluator = (function() { } if (type == 'TrueType' && dict.has('ToUnicode') && differences) { - var cmapObj = xref.fetchIfRef(dict.get('ToUnicode')); + 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)) { @@ -4367,7 +4450,6 @@ var PartialEvaluator = (function() { token = parseInt(token, 10); // a number tokens.push(token); token = ''; - break; } switch (byte) { case 0x5B: @@ -4378,9 +4460,9 @@ var PartialEvaluator = (function() { // collect array items var items = [], item; while (tokens.length && - (item = tokens.pop()) != beginArrayToken) - items.unshift(item); - tokens.push(items); + (item = tokens.pop()) != beginArrayToken) + items.unshift(item); + tokens.push(items); break; } } else if (byte == 0x3E) { @@ -4403,7 +4485,7 @@ var PartialEvaluator = (function() { var type = dict.get('Subtype'); assertWellFormed(IsName(type), 'invalid font Subtype'); - var composite = false + var composite = false; if (type.name == 'Type0') { // If font is a composite // - get the descendant font @@ -4424,7 +4506,8 @@ var PartialEvaluator = (function() { } // 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. + // FontDescriptor was not required. + // This case is here for compatibility. var descriptor = xref.fetchIfRef(dict.get('FontDescriptor')); if (!descriptor) { var baseFontName = dict.get('BaseFont'); @@ -4444,11 +4527,18 @@ var PartialEvaluator = (function() { } } + var defaultWidth = 0; + var widths = Metrics[stdFontMap[baseFontName] || baseFontName]; + if (IsNum(widths)) { + defaultWidth = widths; + widths = null; + } var properties = { type: type.name, encoding: map, differences: [], - widths: {}, + widths: widths || {}, + defaultWidth: defaultWidth, firstChar: 0, lastChar: 256 }; @@ -4464,7 +4554,7 @@ var PartialEvaluator = (function() { // 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 + // 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; @@ -4581,9 +4671,6 @@ function ScratchCanvas(width, height) { } var CanvasGraphics = (function() { - var kScalePrecision = 50; - var kRasterizerMin = 14; - function constructor(canvasCtx, imageCanvas) { this.ctx = canvasCtx; this.current = new CanvasExtraState(); @@ -4622,7 +4709,7 @@ var CanvasGraphics = (function() { compile: function(stream, xref, resources, fonts, images) { var pe = new PartialEvaluator(); - return pe.eval(stream, xref, resources, fonts, images); + return pe.evaluate(stream, xref, resources, fonts, images); }, execute: function(code, xref, resources) { @@ -4661,13 +4748,13 @@ var CanvasGraphics = (function() { this.ctx.mozDashOffset = dashPhase; }, setRenderingIntent: function(intent) { - TODO('set rendering intent'); + TODO('set rendering intent: ' + intent); }, setFlatness: function(flatness) { - TODO('set flatness'); + TODO('set flatness: ' + flatness); }, setGState: function(dictName) { - TODO('set graphics state from dict'); + TODO('set graphics state from dict: ' + dictName); }, save: function() { this.ctx.save(); @@ -4841,25 +4928,16 @@ var CanvasGraphics = (function() { font = font.get(fontRef.name); font = this.xref.fetchIfRef(font); if (!font) - return; + error('Referenced font is not found'); var fontObj = font.fontObj; - var name = fontObj.loadedName; - if (!name) { - // TODO: fontDescriptor is not available, fallback to default font - name = 'sans-serif'; - } - this.current.font = fontObj; this.current.fontSize = size; + var name = fontObj.loadedName || 'sans-serif'; if (this.ctx.$setFont) { this.ctx.$setFont(name, size); } else { - FontMeasure.setActive(fontObj, size); - - size = (size <= kRasterizerMin) ? size * kScalePrecision : size; - var bold = fontObj.black ? (fontObj.bold ? 'bolder' : 'bold') : (fontObj.bold ? 'bold' : 'normal'); @@ -4871,10 +4949,10 @@ var CanvasGraphics = (function() { } }, setTextRenderingMode: function(mode) { - TODO('text rendering mode'); + TODO('text rendering mode: ' + mode); }, setTextRise: function(rise) { - TODO('text rise'); + TODO('text rise: ' + rise); }, moveText: function(x, y) { this.current.x = this.current.lineX += x; @@ -4902,51 +4980,42 @@ var CanvasGraphics = (function() { showText: function(text) { var ctx = this.ctx; var current = this.current; + var font = current.font; ctx.save(); ctx.transform.apply(ctx, current.textMatrix); ctx.scale(1, -1); - ctx.translate(current.x, -1 * current.y); + ctx.transform.apply(ctx, font.textMatrix || IDENTITY_MATRIX); - var scaleFactorX = 1, scaleFactorY = 1; - var font = current.font; - var baseText= text; - if (font) { - if (current.fontSize <= kRasterizerMin) { - scaleFactorX = scaleFactorY = kScalePrecision; - ctx.scale(1 / scaleFactorX, 1 / scaleFactorY); - } - ctx.transform.apply(ctx, font.textMatrix || IDENTITY_MATRIX); - text = font.charsToUnicode(text); - } - - var encoding = current.font.encoding; - var size = current.fontSize; + var glyphs = font.charsToGlyphs(text); + var fontSize = current.fontSize; var charSpacing = current.charSpacing; var wordSpacing = current.wordSpacing; var textHScale = current.textHScale; + ctx.scale(1 / textHScale, 1); - if (charSpacing != 0 || wordSpacing != 0 || textHScale != 1) { - scaleFactorX *= textHScale; - ctx.scale(1 / textHScale, 1); - var width = 0; - - for (var i = 0, ii = text.length; i < ii; ++i) { - var c = baseText.charAt(i); - ctx.fillText(c, 0, 0); - var charWidth = FontMeasure.measureText(c, encoding, size); - charWidth += charSpacing; - if (c.charCodeAt(0) == 32) - charWidth += wordSpacing; - ctx.translate(charWidth * scaleFactorX, 0); - width += charWidth; + var width = 0; + for (var i = 0; i < glyphs.length; i++) { + var glyph = glyphs[i]; + if (glyph === null) { + // word break + width += wordSpacing; + continue; } - current.x += width; - } else { - ctx.fillText(text, 0, 0); - current.x += FontMeasure.measureText(baseText, encoding, size); + + var unicode = glyph.unicode; + var char = unicode >= 0x10000 ? + String.fromCharCode(0xD800 | ((unicode - 0x10000) >> 10), + 0xDC00 | (unicode & 0x3FF)) : String.fromCharCode(unicode); + + var charWidth = glyph.width * fontSize * 0.001; + charWidth += charSpacing; + + ctx.fillText(char, width, 0); + width += charWidth; } + current.x += width; this.ctx.restore(); }, @@ -4979,10 +5048,13 @@ var CanvasGraphics = (function() { // Type3 fonts setCharWidth: function(xWidth, yWidth) { - TODO("type 3 fonts ('d0' operator)"); + TODO('type 3 fonts ("d0" operator) xWidth: ' + xWidth + ' yWidth: ' + + yWidth); }, setCharWidthAndBounds: function(xWidth, yWidth, llx, lly, urx, ury) { - TODO("type 3 fonts ('d1' operator)"); + TODO('type 3 fonts ("d1" operator) xWidth: ' + xWidth + ' yWidth: ' + + yWidth + ' llx: ' + llx + ' lly: ' + lly + ' urx: ' + urx + + ' ury ' + ury); }, // Color @@ -5327,68 +5399,67 @@ var ColorSpace = (function() { this.mode = mode; switch (mode) { - case 'DeviceGray': - case 'G': - return new DeviceGrayCS(); - case 'DeviceRGB': - case 'RGB': - return new DeviceRgbCS(); - case 'DeviceCMYK': - case 'CMYK': - return new DeviceCmykCS(); - case 'Pattern': - return new PatternCS(null); - default: - error('unrecognized colorspace ' + mode); + case 'DeviceGray': + case 'G': + return new DeviceGrayCS(); + case 'DeviceRGB': + case 'RGB': + return new DeviceRgbCS(); + case 'DeviceCMYK': + case 'CMYK': + return new DeviceCmykCS(); + case 'Pattern': + return new PatternCS(null); + default: + error('unrecognized colorspace ' + mode); } } else if (IsArray(cs)) { var mode = cs[0].name; this.mode = mode; switch (mode) { - case 'DeviceGray': - case 'G': - return new DeviceGrayCS(); - case 'DeviceRGB': - case 'RGB': - return new DeviceRgbCS(); - case 'DeviceCMYK': - case 'CMYK': - return new DeviceCmykCS(); - case 'CalGray': - return new DeviceGrayCS(); - case 'CalRGB': - return new DeviceRgbCS(); - case 'ICCBased': - var stream = xref.fetchIfRef(cs[1]); - var dict = stream.dict; - var numComps = dict.get('N'); - if (numComps == 1) + case 'DeviceGray': + case 'G': return new DeviceGrayCS(); - if (numComps == 3) + case 'DeviceRGB': + case 'RGB': return new DeviceRgbCS(); - if (numComps == 4) + case 'DeviceCMYK': + case 'CMYK': return new DeviceCmykCS(); - break; - case 'Pattern': - var baseCS = cs[1]; - if (baseCS) - baseCS = ColorSpace.parse(baseCS, xref, res); - return new PatternCS(baseCS); - case 'Indexed': - var base = ColorSpace.parse(cs[1], xref, res); - var hiVal = cs[2] + 1; - var lookup = xref.fetchIfRef(cs[3]); - return new IndexedCS(base, hiVal, lookup); - case 'Separation': - var name = cs[1]; - var alt = ColorSpace.parse(cs[2], xref, res); - var tintFn = new PDFFunction(xref, xref.fetchIfRef(cs[3])); - return new SeparationCS(alt, tintFn); - case 'Lab': - case 'DeviceN': - default: - error('unimplemented color space object "' + mode + '"'); + case 'CalGray': + return new DeviceGrayCS(); + case 'CalRGB': + return new DeviceRgbCS(); + case 'ICCBased': + var stream = xref.fetchIfRef(cs[1]); + var dict = stream.dict; + var numComps = dict.get('N'); + if (numComps == 1) + return new DeviceGrayCS(); + if (numComps == 3) + return new DeviceRgbCS(); + if (numComps == 4) + return new DeviceCmykCS(); + break; + case 'Pattern': + var baseCS = cs[1]; + if (baseCS) + baseCS = ColorSpace.parse(baseCS, xref, res); + return new PatternCS(baseCS); + case 'Indexed': + var base = ColorSpace.parse(cs[1], xref, res); + var hiVal = cs[2] + 1; + var lookup = xref.fetchIfRef(cs[3]); + return new IndexedCS(base, hiVal, lookup); + case 'Separation': + var alt = ColorSpace.parse(cs[2], xref, res); + var tintFn = new PDFFunction(xref, xref.fetchIfRef(cs[3])); + return new SeparationCS(alt, tintFn); + case 'Lab': + case 'DeviceN': + default: + error('unimplemented color space object "' + mode + '"'); } } else { error('unrecognized color space object: "' + cs + '"'); @@ -5419,12 +5490,12 @@ var SeparationCS = (function() { var base = this.base; var scale = 1 / ((1 << bits) - 1); - var length = 3 * input.length; + var length = input.length; var pos = 0; var numComps = base.numComps; - var baseBuf = new Uint8Array(numComps * input.length); - for (var i = 0, ii = input.length; i < ii; ++i) { + var baseBuf = new Uint8Array(numComps * length); + for (var i = 0; i < length; ++i) { var scaled = input[i] * scale; var tinted = tintFn.func([scaled]); for (var j = 0; j < numComps; ++j) @@ -5671,26 +5742,26 @@ var Pattern = (function() { var typeNum = dict.get('PatternType'); switch (typeNum) { - case 1: - var base = cs.base; - var color; - if (base) { - var baseComps = base.numComps; + case 1: + var base = cs.base; + var color; + if (base) { + var baseComps = base.numComps; - color = []; - for (var i = 0; i < baseComps; ++i) - color.push(args[i]); + color = []; + for (var i = 0; i < baseComps; ++i) + color.push(args[i]); - color = base.getRgb(color); - } - var code = patternName.code; - return new TilingPattern(pattern, code, dict, color, xref, ctx); - case 2: - var shading = xref.fetchIfRef(dict.get('Shading')); - var matrix = dict.get('Matrix'); - return Pattern.parseShading(shading, matrix, xref, res, ctx); - default: - error('Unknown type of pattern: ' + typeNum); + color = base.getRgb(color); + } + var code = patternName.code; + return new TilingPattern(pattern, code, dict, color, xref, ctx); + case 2: + var shading = xref.fetchIfRef(dict.get('Shading')); + var matrix = dict.get('Matrix'); + return Pattern.parseShading(shading, matrix, xref, res, ctx); + default: + error('Unknown type of pattern: ' + typeNum); } return null; }; @@ -5702,12 +5773,12 @@ var Pattern = (function() { var type = dict.get('ShadingType'); switch (type) { - case 2: - case 3: - // both radial and axial shadings are handled by RadialAxial shading - return new RadialAxialShading(dict, matrix, xref, res, ctx); - default: - return new DummyShading(); + case 2: + case 3: + // both radial and axial shadings are handled by RadialAxial shading + return new RadialAxialShading(dict, matrix, xref, res, ctx); + default: + return new DummyShading(); } }; return constructor; @@ -5730,8 +5801,6 @@ var DummyShading = (function() { var RadialAxialShading = (function() { function constructor(dict, matrix, xref, res, ctx) { this.matrix = matrix; - var bbox = dict.get('BBox'); - var background = dict.get('Background'); this.coordsArr = dict.get('Coords'); this.shadingType = dict.get('ShadingType'); this.type = 'Pattern'; @@ -5789,15 +5858,17 @@ var RadialAxialShading = (function() { getPattern: function() { var coordsArr = this.coordsArr; var type = this.shadingType; + var p0, p1, r0, r1; if (type == 2) { - var p0 = [coordsArr[0], coordsArr[1]]; - var p1 = [coordsArr[2], coordsArr[3]]; + p0 = [coordsArr[0], coordsArr[1]]; + p1 = [coordsArr[2], coordsArr[3]]; } else if (type == 3) { - var p0 = [coordsArr[0], coordsArr[1]]; - var p1 = [coordsArr[3], coordsArr[4]]; - var r0 = coordsArr[2], r1 = coordsArr[5]; + p0 = [coordsArr[0], coordsArr[1]]; + p1 = [coordsArr[3], coordsArr[4]]; + r0 = coordsArr[2]; + r1 = coordsArr[5]; } else { - error(); + error('getPattern type unknown: ' + type); } var matrix = this.matrix; @@ -5820,11 +5891,11 @@ var RadialAxialShading = (function() { p1 = Util.applyTransform(p1, userMatrix); } - var colorStops = this.colorStops; + var colorStops = this.colorStops, grad; if (type == 2) - var grad = ctx.createLinearGradient(p0[0], p0[1], p1[0], p1[1]); + grad = ctx.createLinearGradient(p0[0], p0[1], p1[0], p1[1]); else if (type == 3) - var grad = ctx.createRadialGradient(p0[0], p0[1], r0, p1[0], p1[1], r1); + grad = ctx.createRadialGradient(p0[0], p0[1], r0, p1[0], p1[1], r1); for (var i = 0, ii = colorStops.length; i < ii; ++i) { var c = colorStops[i]; @@ -5888,17 +5959,17 @@ var TilingPattern = (function() { var paintType = dict.get('PaintType'); switch (paintType) { - case PAINT_TYPE_COLORED: - tmpCtx.fillStyle = ctx.fillStyle; - tmpCtx.strokeStyle = ctx.strokeStyle; - break; - case PAINT_TYPE_UNCOLORED: - color = Util.makeCssRgb.apply(this, color); - tmpCtx.fillStyle = color; - tmpCtx.strokeStyle = color; - break; - default: - error('Unsupported paint type: ' + paintType); + case PAINT_TYPE_COLORED: + tmpCtx.fillStyle = ctx.fillStyle; + tmpCtx.strokeStyle = ctx.strokeStyle; + break; + case PAINT_TYPE_UNCOLORED: + color = Util.makeCssRgb.apply(this, color); + tmpCtx.fillStyle = color; + tmpCtx.strokeStyle = color; + break; + default: + error('Unsupported paint type: ' + paintType); } var scale = [width / xstep, height / ystep]; @@ -5991,8 +6062,8 @@ var PDFImage = (function() { this.decode = dict.get('Decode', 'D'); - var mask = xref.fetchIfRef(image.dict.get('Mask')); - var smask = xref.fetchIfRef(image.dict.get('SMask')); + var mask = xref.fetchIfRef(dict.get('Mask')); + var smask = xref.fetchIfRef(dict.get('SMask')); if (mask) { TODO('masked images'); @@ -6015,6 +6086,7 @@ var PDFImage = (function() { var bufferPos = 0; var output = bpc <= 8 ? new Uint8Array(length) : bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length); + var rowComps = width * numComps; if (bpc == 1) { var valueZero = 0, valueOne = 1; @@ -6022,7 +6094,6 @@ var PDFImage = (function() { valueZero = decodeMap[0] ? 1 : 0; valueOne = decodeMap[1] ? 1 : 0; } - var rowComps = width * numComps; var mask = 0; var buf = 0; @@ -6044,8 +6115,7 @@ var PDFImage = (function() { } else { if (decodeMap != null) TODO('interpolate component values'); - var rowComps = width * numComps; - var bits, buf; + var bits = 0, buf = 0; for (var i = 0, ii = length; i < ii; ++i) { if (i % rowComps == 0) { buf = 0; @@ -6250,14 +6320,14 @@ var PDFFunction = (function() { floor *= outputSize; ceil *= outputSize; - var output = []; + var output = [], v = 0; for (var i = 0; i < outputSize; ++i) { if (ceil == floor) { - var v = samples[ceil + i]; + v = samples[ceil + i]; } else { var low = samples[floor + i]; var high = samples[ceil + i]; - var v = low * scale + high * (1 - scale); + v = low * scale + high * (1 - scale); } var i2 = i * 2; diff --git a/test/driver.js b/test/driver.js index 265de0852..7d6c54509 100644 --- a/test/driver.js +++ b/test/driver.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: */ /* @@ -8,6 +8,7 @@ 'use strict'; var appPath, browser, canvas, currentTaskIdx, manifest, stdout; +var inFlightRequests = 0; function queryParams() { var qs = window.location.search.substring(1); @@ -42,12 +43,12 @@ function load() { if (r.readyState == 4) { log('done\n'); manifest = JSON.parse(r.responseText); - currentTaskIdx = 0, nextTask(); + currentTaskIdx = 0; + nextTask(); } }; r.send(null); } -window.onload = load; function nextTask() { if (currentTaskIdx == manifest.length) { @@ -73,7 +74,8 @@ function nextTask() { failure = 'load PDF doc : ' + e.toString(); } - task.pageNum = 1, nextPage(task, failure); + task.pageNum = 1; + nextPage(task, failure); } }; r.send(null); @@ -89,7 +91,8 @@ function nextPage(task, loadError) { if (!task.pdfDoc) { sendTaskResult(canvas.toDataURL('image/png'), task, failure); log('done' + (failure ? ' (failed !: ' + failure + ')' : '') + '\n'); - ++currentTaskIdx, nextTask(); + ++currentTaskIdx; + nextTask(); return; } @@ -98,7 +101,8 @@ function nextPage(task, loadError) { log(' Round ' + (1 + task.round) + '\n'); task.pageNum = 1; } else { - ++currentTaskIdx, nextTask(); + ++currentTaskIdx; + nextTask(); return; } } @@ -123,7 +127,7 @@ function nextPage(task, loadError) { page.startRendering( ctx, function(e) { - snapshotCurrentPage(page, task, (!failure && e) ? + snapshotCurrentPage(task, (!failure && e) ? ('render : ' + e) : failure); } ); @@ -135,11 +139,11 @@ function nextPage(task, loadError) { if (failure) { // Skip right to snapshotting if there was a failure, since the // fonts might be in an inconsistent state. - snapshotCurrentPage(page, task, failure); + snapshotCurrentPage(task, failure); } } -function snapshotCurrentPage(page, task, failure) { +function snapshotCurrentPage(task, failure) { log('done, snapshotting... '); sendTaskResult(canvas.toDataURL('image/png'), task, failure); @@ -149,7 +153,8 @@ function snapshotCurrentPage(page, task, failure) { var backoff = (inFlightRequests > 0) ? inFlightRequests * 10 : 0; setTimeout( function() { - ++task.pageNum, nextPage(task); + ++task.pageNum; + nextPage(task); }, backoff ); @@ -182,7 +187,6 @@ function done() { } } -var inFlightRequests = 0; function sendTaskResult(snapshot, task, failure) { var result = { browser: browser, id: task.id, @@ -201,7 +205,7 @@ function sendTaskResult(snapshot, task, failure) { if (r.readyState == 4) { inFlightRequests--; } - } + }; document.getElementById('inFlightCount').innerHTML = inFlightRequests++; r.send(JSON.stringify(result)); } diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 95de9fb8e..77c89ece6 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -1,3 +1,13 @@ -pdf.pdf +DiwanProfile.pdf +artofwar.pdf +cable.pdf +ecma262.pdf +hmm.pdf +i9.pdf intelisa.pdf openweb_tm-PRINT.pdf +pdf.pdf +pdkids.pdf +shavian.pdf +jai.pdf + diff --git a/test/pdfs/artofwar.pdf.link b/test/pdfs/artofwar.pdf.link new file mode 100644 index 000000000..f70b9e235 --- /dev/null +++ b/test/pdfs/artofwar.pdf.link @@ -0,0 +1 @@ +http://www.puppetpress.com/classics/ArtofWarbySunTzu.pdf diff --git a/test/pdfs/fips197.pdf.link b/test/pdfs/fips197.pdf.link new file mode 100644 index 000000000..815eb1d48 --- /dev/null +++ b/test/pdfs/fips197.pdf.link @@ -0,0 +1 @@ +http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf diff --git a/test/pdfs/wdsg_fitc.pdf.link b/test/pdfs/wdsg_fitc.pdf.link new file mode 100644 index 000000000..77d3b590d --- /dev/null +++ b/test/pdfs/wdsg_fitc.pdf.link @@ -0,0 +1 @@ +http://www.airgid.com/book/wdsg_fitc.pdf diff --git a/test/pdfs/wnv_chinese.pdf.link b/test/pdfs/wnv_chinese.pdf.link new file mode 100644 index 000000000..fbbc81760 --- /dev/null +++ b/test/pdfs/wnv_chinese.pdf.link @@ -0,0 +1 @@ +http://www.cdc.gov/ncidod/dvbid/westnile/languages/chinese.pdf diff --git a/test/resources/browser_manifests/.gitignore b/test/resources/browser_manifests/.gitignore new file mode 100644 index 000000000..ca57ac505 --- /dev/null +++ b/test/resources/browser_manifests/.gitignore @@ -0,0 +1,2 @@ +browser_manifest.json + diff --git a/test/test_manifest.json b/test/test_manifest.json index 1155195cb..44955eefa 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -69,6 +69,12 @@ "rounds": 1, "type": "load" }, + { "id": "wnv_chinese-pdf", + "file": "pdfs/wnv_chinese.pdf", + "link": true, + "rounds": 1, + "type": "eq" + }, { "id": "i9-pdf", "file": "pdfs/i9.pdf", "link": true, @@ -109,5 +115,23 @@ "link": true, "rounds": 1, "type": "eq" + }, + { "id": "artofwar", + "file": "pdfs/artofwar.pdf", + "link": true, + "rounds": 1, + "type": "eq" + }, + { "id": "wdsg_fitc", + "file": "pdfs/wdsg_fitc.pdf", + "link": true, + "rounds": 1, + "type": "eq" + }, + { "id": "fips197", + "file": "pdfs/fips197.pdf", + "link": true, + "rounds": 1, + "type": "load" } ] diff --git a/test/test_slave.html b/test/test_slave.html index f6d1f7f48..91b8a6850 100644 --- a/test/test_slave.html +++ b/test/test_slave.html @@ -6,6 +6,7 @@ + diff --git a/utils/cffStandardStrings.js b/utils/cffStandardStrings.js index 09c408ee7..8a6570551 100644 --- a/utils/cffStandardStrings.js +++ b/utils/cffStandardStrings.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'; @@ -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..a51469c53 100644 --- a/utils/fonts_utils.js +++ b/utils/fonts_utils.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'; @@ -69,7 +69,7 @@ function readCharstringEncoding(aString) { } else if (value <= 31) { token = CFFEncodingMap[value]; } else if (value < 247) { - token = parseInt(value) - 139; + token = parseInt(value, 10) - 139; } else if (value < 251) { token = ((value - 247) * 256) + aString[i++] + 108; } else if (value < 255) { @@ -113,7 +113,7 @@ function readFontDictData(aString, aMap) { while (!parsed) { var byte = aString[i++]; - var nibbles = [parseInt(byte / 16), parseInt(byte % 16)]; + var nibbles = [parseInt(byte / 16, 10), parseInt(byte % 16, 10)]; for (var j = 0; j < nibbles.length; j++) { var nibble = nibbles[j]; switch (nibble) { @@ -144,7 +144,7 @@ function readFontDictData(aString, aMap) { } else if (value <= 31) { token = aMap[value]; } else if (value <= 246) { - token = parseInt(value) - 139; + token = parseInt(value, 10) - 139; } else if (value <= 250) { token = ((value - 247) * 256) + aString[i++] + 108; } else if (value <= 254) { @@ -193,7 +193,7 @@ function readFontIndexData(aStream, aIsByte) { } error(offsize + ' is not a valid offset size'); return null; - }; + } var offsets = []; for (var i = 0; i < count + 1; i++) @@ -236,7 +236,7 @@ var Type2Parser = function(aFilePath) { function dump(aStr) { if (debug) log(aStr); - }; + } function parseAsToken(aString, aMap) { var decoded = readFontDictData(aString, aMap); @@ -277,7 +277,7 @@ var Type2Parser = function(aFilePath) { } } } - }; + } this.parse = function(aStream) { font.set('major', aStream.getByte()); @@ -353,7 +353,7 @@ var Type2Parser = function(aFilePath) { aStream.pos = charsetEntry; var charset = readCharset(aStream, charStrings); } - } + }; }; /* diff --git a/web/compatibility.js b/web/compatibility.js old mode 100755 new mode 100644 index e9a769163..2301678d5 --- a/web/compatibility.js +++ b/web/compatibility.js @@ -1,6 +1,8 @@ -/* -*- 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'; + // Checking if the typed arrays are supported (function() { if (typeof Uint8Array !== 'undefined') @@ -10,8 +12,9 @@ return this.slice(start, end); } - function set_(array, offset) { - if (arguments.length < 2) offset = 0; + function set_function(array, offset) { + if (arguments.length < 2) + offset = 0; for (var i = 0, n = array.length; i < n; ++i, ++offset) this[offset] = array[i] & 0xFF; } @@ -19,15 +22,17 @@ function TypedArray(arg1) { var result; if (typeof arg1 === 'number') { - result = new Array(arg1); - for (var i = 0; i < arg1; ++i) - result[i] = 0; + result = []; + for (var i = 0; i < arg1; ++i) + result[i] = 0; } else - result = arg1.slice(0); + result = arg1.slice(0); + result.subarray = subarray; result.buffer = result; result.byteLength = result.length; - result.set = set_; + result.set = set_function; + if (typeof arg1 === 'object' && arg1.buffer) result.buffer = arg1.buffer; diff --git a/web/viewer.css b/web/viewer.css old mode 100755 new mode 100644 diff --git a/web/viewer.html b/web/viewer.html index d37270661..a53593df3 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -10,6 +10,7 @@ + diff --git a/web/viewer.js b/web/viewer.js index c5d79c541..520cf4efa 100644 --- a/web/viewer.js +++ b/web/viewer.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'; @@ -98,7 +98,7 @@ var PDFView = { }, get page() { - return parseInt(document.location.hash.substring(1)) || 1; + return parseInt(document.location.hash.substring(1), 10) || 1; }, open: function(url, scale) { @@ -170,7 +170,7 @@ var PDFView = { } this.setScale(scale || kDefaultScale, true); - this.page = parseInt(document.location.hash.substring(1)) || 1; + this.page = parseInt(document.location.hash.substring(1), 10) || 1; this.pagesRefMap = pagesRefMap; this.destinations = pdf.catalog.destinations; if (pdf.catalog.documentOutline) { @@ -209,7 +209,7 @@ var PDFView = { var currentHeight = kBottomMargin; var windowTop = window.pageYOffset; - for (var i = 1; i <= pages.length; i++) { + for (var i = 1; i <= pages.length; ++i) { var page = pages[i - 1]; var pageHeight = page.height * page.scale + kBottomMargin; if (currentHeight + pageHeight > windowTop) @@ -219,10 +219,11 @@ var PDFView = { } var windowBottom = window.pageYOffset + window.innerHeight; - for (; i <= pages.length && currentHeight < windowBottom; i++) { - var page = pages[i - 1]; - visiblePages.push({ id: page.id, y: currentHeight, view: page }); - currentHeight += page.height * page.scale + kBottomMargin; + for (; i <= pages.length && currentHeight < windowBottom; ++i) { + var singlePage = pages[i - 1]; + visiblePages.push({ id: singlePage.id, y: currentHeight, + view: singlePage }); + currentHeight += singlePage.height * singlePage.scale + kBottomMargin; } return visiblePages; @@ -256,13 +257,13 @@ var PageView = function(container, content, id, width, height, div.removeAttribute('data-loaded'); }; - function setupLinks(canvas, content, scale) { + function setupLinks(content, scale) { function bindLink(link, dest) { link.onclick = function() { if (dest) PDFView.navigateTo(dest); return false; - } + }; } var links = content.getLinks(); for (var i = 0; i < links.length; i++) { @@ -283,8 +284,6 @@ var PageView = function(container, content, id, width, height, var width = 0, height = 0, widthScale, heightScale; var scale = 0; switch (dest[1].name) { - default: - return; case 'XYZ': x = dest[2]; y = dest[3]; @@ -315,6 +314,8 @@ var PageView = function(container, content, id, width, height, height / kCssUnits; scale = Math.min(widthScale, heightScale); break; + default: + return; } var boundingRect = [ @@ -369,7 +370,7 @@ var PageView = function(container, content, id, width, height, stats.begin = Date.now(); this.content.startRendering(ctx, this.updateStats); - setupLinks(canvas, this.content, this.scale); + setupLinks(this.content, this.scale); div.setAttribute('data-loaded', true); return true; @@ -593,7 +594,7 @@ window.addEventListener('pagechange', function pagechange(evt) { }, true); window.addEventListener('keydown', function keydown(evt) { - switch(evt.keyCode) { + switch (evt.keyCode) { case 61: // FF/Mac '=' case 107: // FF '+' and '=' case 187: // Chrome '+' diff --git a/worker/canvas.js b/worker/canvas.js index c2a9f4763..d8b0dd338 100644 --- a/worker/canvas.js +++ b/worker/canvas.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'; @@ -39,7 +39,7 @@ function GradientProxy(cmdQueue, x0, y0, x1, y1) { cmdQueue.push(['$createLinearGradient', [x0, y0, x1, y1]]); this.addColorStop = function(i, rgba) { cmdQueue.push(['$addColorStop', [i, rgba]]); - } + }; } // Really simple PatternProxy. @@ -72,7 +72,7 @@ function CanvasProxy(width, height) { throw 'CanvasProxy can only provide a 2d context.'; } return ctx; - } + }; // Expose only the minimum of the canvas object - there is no dom to do // more here. @@ -127,7 +127,7 @@ function CanvasProxy(width, height) { return function() { // console.log("funcCall", name) cmdQueue.push([name, Array.prototype.slice.call(arguments)]); - } + }; } var name; for (var i = 0; i < ctxFunc.length; i++) { @@ -139,11 +139,11 @@ function CanvasProxy(width, height) { ctx.createPattern = function(object, kind) { return new PatternProxy(cmdQueue, object, kind); - } + }; ctx.createLinearGradient = function(x0, y0, x1, y1) { return new GradientProxy(cmdQueue, x0, y0, x1, y1); - } + }; ctx.getImageData = function(x, y, w, h) { return { @@ -151,11 +151,11 @@ function CanvasProxy(width, height) { height: h, data: Uint8ClampedArray(w * h * 4) }; - } + }; ctx.putImageData = function(data, x, y, width, height) { cmdQueue.push(['$putImageData', [data, x, y, width, height]]); - } + }; ctx.drawImage = function(image, x, y, width, height, sx, sy, swidth, sheight) { @@ -168,7 +168,7 @@ function CanvasProxy(width, height) { } else { throw 'unkown type to drawImage'; } - } + }; // Setup property access to `ctx`. var ctxProp = { @@ -195,14 +195,14 @@ function CanvasProxy(width, height) { function buildGetter(name) { return function() { return ctx['$' + name]; - } + }; } function buildSetter(name) { return function(value) { cmdQueue.push(['$', name, value]); - return ctx['$' + name] = value; - } + return (ctx['$' + name] = value); + }; } // Setting the value to `stroke|fillStyle` needs special handling, as it @@ -215,9 +215,9 @@ function CanvasProxy(width, height) { cmdQueue.push(['$' + name + 'Pattern', [value.id]]); } else { cmdQueue.push(['$', name, value]); - return ctx['$' + name] = value; + return (ctx['$' + name] = value); } - } + }; } for (var name in ctxProp) { diff --git a/worker/client.js b/worker/client.js index a00eab59e..a51484c64 100644 --- a/worker/client.js +++ b/worker/client.js @@ -1,25 +1,28 @@ -/* -*- 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'; -if (typeof console.time == 'undefined') { +var consoleUtils = (function() { var consoleTimer = {}; - console.time = function(name) { + + var obj = {}; + obj.time = function(name) { consoleTimer[name] = Date.now(); }; - - console.timeEnd = function(name) { + obj.timeEnd = function(name) { var time = consoleTimer[name]; if (time == null) { throw 'Unkown timer name ' + name; } - this.log('Timer:', name, Date.now() - time); + console.log('Timer:', name, Date.now() - time); }; -} + + return obj; +})(); function FontWorker() { - this.worker = new Worker('worker/font.js'); + this.worker = new Worker('../worker/font.js'); this.fontsWaiting = 0; this.fontsWaitingCallbacks = []; @@ -58,7 +61,7 @@ FontWorker.prototype = { 'fonts': function(data) { // console.log("got processed fonts from worker", Object.keys(data)); - for (name in data) { + for (var name in data) { // Update the encoding property. var font = Fonts.lookup(name); font.properties = { @@ -96,7 +99,7 @@ FontWorker.prototype = { this.fontsWaiting++; } - console.time('ensureFonts'); + consoleUtils.time('ensureFonts'); // If there are fonts, that need to get loaded, tell the FontWorker to get // started and push the callback on the waiting-callback-stack. if (notLoaded.length != 0) { @@ -124,7 +127,7 @@ function WorkerPDFDoc(canvas) { this.ctx = canvas.getContext('2d'); this.canvas = canvas; - this.worker = new Worker('worker/pdf.js'); + this.worker = new Worker('../worker/pdf.js'); this.fontWorker = new FontWorker(); this.waitingForFonts = false; this.waitingForFontsCallback = []; @@ -167,7 +170,8 @@ function WorkerPDFDoc(canvas) { }, '$putImageData': function(imageData, x, y) { - var imgData = this.getImageData(0, 0, imageData.width, imageData.height); + var imgData = this.getImageData(0, 0, + imageData.width, imageData.height); // Store the .data property to avaid property lookups. var imageRealData = imageData.data; @@ -176,7 +180,7 @@ function WorkerPDFDoc(canvas) { // Copy over the imageData. var len = imageRealData.length; while (len--) - imgRealData[len] = imageRealData[len]; + imgRealData[len] = imageRealData[len]; this.putImageData(imgData, x, y); }, @@ -273,7 +277,7 @@ function WorkerPDFDoc(canvas) { }, 'pdf_num_pages': function(data) { - this.numPages = parseInt(data); + this.numPages = parseInt(data, 10); if (this.loadCallback) { this.loadCallback(); } @@ -302,8 +306,8 @@ function WorkerPDFDoc(canvas) { 'setup_page': function(data) { var size = data.split(','); var canvas = this.canvas, ctx = this.ctx; - canvas.width = parseInt(size[0]); - canvas.height = parseInt(size[1]); + canvas.width = parseInt(size[0], 10); + canvas.height = parseInt(size[1], 10); }, 'fonts': function(data) { @@ -339,7 +343,7 @@ function WorkerPDFDoc(canvas) { var renderData = function() { if (id == 0) { - console.time('main canvas rendering'); + consoleUtils.time('main canvas rendering'); var ctx = this.ctx; ctx.save(); ctx.fillStyle = 'rgb(255, 255, 255)'; @@ -348,8 +352,8 @@ function WorkerPDFDoc(canvas) { } renderProxyCanvas(canvasList[id], cmdQueue); if (id == 0) { - console.timeEnd('main canvas rendering'); - console.timeEnd('>>> total page display time:'); + consoleUtils.timeEnd('main canvas rendering'); + consoleUtils.timeEnd('>>> total page display time:'); } }.bind(this); @@ -368,50 +372,52 @@ function WorkerPDFDoc(canvas) { }; // Listen to the WebWorker for data and call actionHandler on it. - this.worker.onmessage = function(event) { + this.worker.addEventListener('message', function(event) { var data = event.data; if (data.action in actionHandler) { actionHandler[data.action].call(this, data.data); } else { throw 'Unkown action from worker: ' + data.action; } - }.bind(this); + }.bind(this)); } -WorkerPDFDoc.prototype.open = function(url, callback) { - var req = new XMLHttpRequest(); - req.open('GET', url); - req.mozResponseType = req.responseType = 'arraybuffer'; - req.expected = (document.URL.indexOf('file:') == 0) ? 0 : 200; - req.onreadystatechange = function() { - if (req.readyState == 4 && req.status == req.expected) { - var data = req.mozResponseArrayBuffer || req.mozResponse || - req.responseArrayBuffer || req.response; +WorkerPDFDoc.prototype = { + open: function(url, callback) { + var req = new XMLHttpRequest(); + req.open('GET', url); + req.mozResponseType = req.responseType = 'arraybuffer'; + req.expected = (document.URL.indexOf('file:') == 0) ? 0 : 200; + req.onreadystatechange = function() { + if (req.readyState == 4 && req.status == req.expected) { + var data = req.mozResponseArrayBuffer || req.mozResponse || + req.responseArrayBuffer || req.response; - this.loadCallback = callback; - this.worker.postMessage(data); - this.showPage(this.numPage); + this.loadCallback = callback; + this.worker.postMessage(data); + this.showPage(this.numPage); + } + }.bind(this); + req.send(null); + }, + + showPage: function(numPage) { + this.numPage = parseInt(numPage, 10); + console.log('=== start rendering page ' + numPage + ' ==='); + consoleUtils.time('>>> total page display time:'); + this.worker.postMessage(numPage); + if (this.onChangePage) { + this.onChangePage(numPage); } - }.bind(this); - req.send(null); -}; + }, -WorkerPDFDoc.prototype.showPage = function(numPage) { - this.numPage = parseInt(numPage); - console.log('=== start rendering page ' + numPage + ' ==='); - console.time('>>> total page display time:'); - this.worker.postMessage(numPage); - if (this.onChangePage) { - this.onChangePage(numPage); + nextPage: function() { + if (this.numPage != this.numPages) + this.showPage(++this.numPage); + }, + + prevPage: function() { + if (this.numPage != 1) + this.showPage(--this.numPage); } }; - -WorkerPDFDoc.prototype.nextPage = function() { - if (this.numPage == this.numPages) return; - this.showPage(++this.numPage); -}; - -WorkerPDFDoc.prototype.prevPage = function() { - if (this.numPage == 1) return; - this.showPage(--this.numPage); -}; diff --git a/worker/console.js b/worker/console.js index 29f511407..43ec1af88 100644 --- a/worker/console.js +++ b/worker/console.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'; @@ -25,3 +25,4 @@ var console = { this.log('Timer:', name, Date.now() - time); } }; + diff --git a/worker/font.js b/worker/font.js index 32e22198c..4319de7b9 100644 --- a/worker/font.js +++ b/worker/font.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'; @@ -56,11 +56,12 @@ var actionHandler = { }; // Listen to the MainThread for data and call actionHandler on it. -this.onmessage = function(event) { +addEventListener('message', function(event) { var data = event.data; if (data.action in actionHandler) { actionHandler[data.action].call(this, data.data); } else { throw 'Unkown action from worker: ' + data.action; } -}; +}); + diff --git a/worker/pdf.js b/worker/pdf.js index 0d5008d80..f205547ab 100644 --- a/worker/pdf.js +++ b/worker/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'; @@ -11,8 +11,10 @@ var console = { action: 'log', data: args }); - }, + } +}; +var consoleUtils = { time: function(name) { consoleTimer[name] = Date.now(); }, @@ -22,7 +24,7 @@ var console = { if (time == null) { throw 'Unkown timer name ' + name; } - this.log('Timer:', name, Date.now() - time); + console.log('Timer:', name, Date.now() - time); } }; @@ -42,7 +44,7 @@ var canvas = new CanvasProxy(1224, 1584); // Listen for messages from the main thread. var pdfDocument = null; -onmessage = function(event) { +addEventListener('message', function(event) { var data = event.data; // If there is no pdfDocument yet, then the sent data is the PDFDocument. if (!pdfDocument) { @@ -55,10 +57,10 @@ onmessage = function(event) { } // User requested to render a certain page. else { - console.time('compile'); + consoleUtils.time('compile'); // Let's try to render the first page... - var page = pdfDocument.getPage(parseInt(data)); + var page = pdfDocument.getPage(parseInt(data, 10)); var pdfToCssUnitsCoef = 96.0 / 72.0; var pageWidth = (page.mediaBox[2] - page.mediaBox[0]) * pdfToCssUnitsCoef; @@ -77,19 +79,19 @@ onmessage = function(event) { var fonts = []; var gfx = new CanvasGraphics(canvas.getContext('2d'), CanvasProxy); page.compile(gfx, fonts); - console.timeEnd('compile'); + consoleUtils.timeEnd('compile'); // Send fonts to the main thread. - console.time('fonts'); + consoleUtils.time('fonts'); postMessage({ action: 'fonts', data: fonts }); - console.timeEnd('fonts'); + consoleUtils.timeEnd('fonts'); - console.time('display'); + consoleUtils.time('display'); page.display(gfx); canvas.flush(); - console.timeEnd('display'); + consoleUtils.timeEnd('display'); } -}; +});