Merge worker_pull with master

This commit is contained in:
Julian Viereck 2011-10-08 14:18:23 +02:00
commit 3054102d3b
44 changed files with 10119 additions and 1922 deletions

View File

@ -8,6 +8,7 @@
Justin D'Arcangelo <justindarc@gmail.com>
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"),

View File

@ -12,6 +12,8 @@ PDF_JS_FILES = \
pdf.js \
crypto.js \
fonts.js \
metrics.js \
charsets.js \
glyphlist.js \
$(NULL)
@ -55,30 +57,30 @@ browser-test:
--browserManifestFile=$(PDF_BROWSERS) \
--manifestFile=$(PDF_TESTS)
# make shell-test
# # 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
#
# 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."
# 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
#
@ -86,7 +88,8 @@ font-test:
# To install gjslint, see:
#
# <http://code.google.com/closure/utilities/docs/linter_howto.html>
SRC_DIRS := . utils worker web test
SRC_DIRS := . utils worker web test examples/helloworld extensions/firefox \
extensions/firefox/components
GJSLINT_FILES = $(foreach DIR,$(SRC_DIRS),$(wildcard $(DIR)/*.js))
lint:
gjslint $(GJSLINT_FILES)
@ -133,18 +136,18 @@ $(GH_PAGES)/web/%: web/%
$(GH_PAGES)/web/images/%: web/images/%
@cp $< $@
# make compiler
# # 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
#
# 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;
# 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
#
@ -163,9 +166,9 @@ PDF_WEB_FILES = \
extension:
# Copy a standalone version of pdf.js inside the content directory
@rm -Rf $(EXTENSION_SRC)/$(CONTENT_DIR)/
@mkdir $(EXTENSION_SRC)/$(CONTENT_DIR)/
@mkdir -p $(EXTENSION_SRC)/$(CONTENT_DIR)/web
@cp $(PDF_JS_FILES) $(EXTENSION_SRC)/$(CONTENT_DIR)/
@cp -r $(PDF_WEB_FILES) $(EXTENSION_SRC)/$(CONTENT_DIR)/
@cp -r $(PDF_WEB_FILES) $(EXTENSION_SRC)/$(CONTENT_DIR)/web/
# Create the xpi
@cd $(EXTENSION_SRC); zip -r $(EXTENSION_NAME) *

177
README.md
View File

@ -1,32 +1,177 @@
# 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.
### Getting the code
To get a local copy of the current code, clone it using git:
$ git clone git://github.com/andreasgal/pdf.js.git pdfjs
$ cd pdfjs
Next, you need to start a local web server as some browsers don't allow opening
PDF files for a file:// url:
$ make server
If everything worked out, you can now serve
+ http://localhost:8888/web/viewer.html
You can also view all the test pdf files on the right side serving
+ http://localhost:8888/test/pdfs/?frame
### Learning
Here are some initial pointers to help contributors get off the ground.
Additional resources are available in a separate section below.
#### Introductory video
Check out the presentation by our contributor Julian Viereck on the inner
workings of PDF and pdf.js:
+ http://www.youtube.com/watch?v=Iv15UY-4Fg8
#### Hello world
For a "hello world" example, take a look at:
+ [examples/helloworld/hello.js](https://github.com/andreasgal/pdf.js/blob/master/examples/helloworld/hello.js)
This example illustrates the bare minimum ingredients for integrating pdf.js
in a custom project.
## Contributing
pdf.js is a community-driven project, so contributors are always welcome.
Simply fork our repo and contribute away. A great place to start is our
[open issues](https://github.com/andreasgal/pdf.js/issues). For better consistency and
long-term stability, please do look around the code and try to follow our conventions.
More information about the contributor process can be found on the
[contributor wiki page](https://github.com/andreasgal/pdf.js/wiki/Contributing).
If you don't want to hack on the project or have little spare time, __you still
can help!__ Just open PDFs in the
[online demo](http://andreasgal.github.com/pdf.js/web/viewer.html) and report
any breakage in rendering.
Our Github contributors so far:
+ https://github.com/andreasgal/pdf.js/contributors
You can add your name to it! :)
## 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.
## Running tests through our bot
If you are a reviewer, you can use our remote bot to issue comprehensive tests
against reference images before merging pull requests.
See the bot repo for details:
+ https://github.com/arturadib/pdf.js-bot
## 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:
http://andreasgal.com/2011/06/15/pdf-js/
+ http://andreasgal.com/2011/06/15/pdf-js/
+ http://blog.mozilla.com/cjones/2011/06/15/overview-of-pdf-js-guts/
http://blog.mozilla.com/cjones/2011/06/15/overview-of-pdf-js-guts/
Talk to us on IRC:
follow us on twitter: @pdfjs
+ #pdfjs on irc.mozilla.org
http://twitter.com/#!/pdfjs
Join our mailing list:
join our mailing list:
+ dev-pdf-js@lists.mozilla.org
dev-pdf-js@lists.mozilla.org
Subscribe either using lists.mozilla.org or Google Groups:
and talk to us on IRC:
+ https://lists.mozilla.org/listinfo/dev-pdf-js
+ https://groups.google.com/group/mozilla.dev.pdf-js/topics
#pdfjs on irc.mozilla.org
Follow us on twitter: @pdfjs
+ http://twitter.com/#!/pdfjs
## PDF-related resources
A really basic overview of PDF is described here:
+ http://partners.adobe.com/public/developer/en/livecycle/lc_pdf_overview_format.pdf
A more detailed file example:
+ http://gnupdf.org/Introduction_to_PDF
The PDF specification itself is an ISO and not freely available. However, there is
a "PDF Reference" from Adobe:
+ http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/pdf_reference_1-7.pdf
Recommended chapters to read: "2. Overview", "3.4 File Structure",
"4.1 Graphics Objects" that lists the PDF commands.

101
charsets.js Normal file
View File

@ -0,0 +1,101 @@
var ISOAdobeCharset = [
'.notdef', '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', 'onesuperior', 'logicalnot', 'mu',
'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', 'onequarter',
'divide', 'brokenbar', 'degree', 'thorn', 'threequarters', 'twosuperior',
'registered', 'minus', 'eth', 'multiply', 'threesuperior', 'copyright',
'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', 'Atilde',
'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', 'Iacute',
'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', 'Ocircumflex',
'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', 'Ucircumflex',
'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', 'aacute',
'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla',
'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex',
'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis',
'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis',
'ugrave', 'yacute', 'ydieresis', 'zcaron'
];
var ExpertCharset = [
'.notdef', 'space', 'exclamsmall', 'Hungarumlautsmall', 'dollaroldstyle',
'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior',
'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma',
'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle',
'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle',
'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle',
'colon', 'semicolon', 'commasuperior', 'threequartersemdash',
'periodsuperior', 'questionsmall', 'asuperior', 'bsuperior',
'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior',
'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',
'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior',
'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall',
'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall',
'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall',
'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall',
'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary',
'onefitted', 'rupiah', 'Tildesmall', 'exclamdownsmall', 'centoldstyle',
'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall',
'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall',
'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall',
'Cedillasmall', 'onequarter', 'onehalf', 'threequarters',
'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths',
'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior',
'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior',
'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior',
'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior',
'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior',
'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior',
'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall',
'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall',
'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall',
'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall',
'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall',
'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall',
'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall',
'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall',
'Ydieresissmall'
];
var ExpertSubsetCharset = [
'.notdef', 'space', 'dollaroldstyle', 'dollarsuperior',
'parenleftsuperior', 'parenrightsuperior', 'twodotenleader',
'onedotenleader', 'comma', 'hyphen', 'period', 'fraction',
'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle',
'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle',
'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', 'commasuperior',
'threequartersemdash', 'periodsuperior', 'asuperior', 'bsuperior',
'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior',
'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',
'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior',
'parenrightinferior', 'hyphensuperior', 'colonmonetary', 'onefitted',
'rupiah', 'centoldstyle', 'figuredash', 'hypheninferior', 'onequarter',
'onehalf', 'threequarters', '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'
];

6932
cidmaps.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
'use strict';
var ARCFourCipher = (function() {
var ARCFourCipher = (function arcFourCipher() {
function constructor(key) {
this.a = 0;
this.b = 0;
@ -21,7 +21,7 @@ var ARCFourCipher = (function() {
}
constructor.prototype = {
encryptBlock: function(data) {
encryptBlock: function arcFourCipherEncryptBlock(data) {
var i, n = data.length, tmp, tmp2;
var a = this.a, b = this.b, s = this.s;
var output = new Uint8Array(n);
@ -45,7 +45,7 @@ var ARCFourCipher = (function() {
return constructor;
})();
var md5 = (function() {
var calculateMD5 = (function calculateMD5() {
var r = new Uint8Array([
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
@ -129,12 +129,12 @@ var md5 = (function() {
return hash;
})();
var NullCipher = (function() {
var NullCipher = (function nullCipher() {
function constructor() {
}
constructor.prototype = {
decryptBlock: function(data) {
decryptBlock: function nullCipherDecryptBlock(data) {
return data;
}
};
@ -142,7 +142,7 @@ var NullCipher = (function() {
return constructor;
})();
var AES128Cipher = (function() {
var AES128Cipher = (function aes128Cipher() {
var rcon = new Uint8Array([
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a,
@ -372,7 +372,7 @@ var AES128Cipher = (function() {
}
constructor.prototype = {
decryptBlock: function(data) {
decryptBlock: function aes128CipherDecryptBlock(data) {
var i, sourceLength = data.length;
var buffer = this.buffer, bufferLength = this.bufferPosition;
// waiting for IV values -- they are at the start of the stream
@ -395,19 +395,21 @@ var AES128Cipher = (function() {
return constructor;
})();
var CipherTransform = (function() {
var CipherTransform = (function cipherTransform() {
function constructor(stringCipherConstructor, streamCipherConstructor) {
this.stringCipherConstructor = stringCipherConstructor;
this.streamCipherConstructor = streamCipherConstructor;
}
constructor.prototype = {
createStream: function(stream) {
createStream: function cipherTransformCreateStream(stream) {
var cipher = new this.streamCipherConstructor();
return new DecryptStream(stream, function(data) {
return cipher.decryptBlock(data);
});
return new DecryptStream(stream,
function cipherTransformDecryptStream(data) {
return cipher.decryptBlock(data);
}
);
},
decryptString: function(s) {
decryptString: function cipherTransformDecryptString(s) {
var cipher = new this.stringCipherConstructor();
var data = stringToBytes(s);
data = cipher.decryptBlock(data);
@ -417,7 +419,7 @@ var CipherTransform = (function() {
return constructor;
})();
var CipherTransformFactory = (function() {
var CipherTransformFactory = (function cipherTransformFactory() {
function prepareKeyData(fileId, password, ownerPassword, userPassword,
flags, revision, keyLength, encryptMetadata) {
var defaultPasswordBytes = new Uint8Array([
@ -450,11 +452,11 @@ var CipherTransformFactory = (function() {
hashData[i++] = 0xFF;
hashData[i++] = 0xFF;
}
var hash = md5(hashData, 0, i);
var hash = calculateMD5(hashData, 0, i);
var keyLengthInBytes = keyLength >> 3;
if (revision >= 3) {
for (j = 0; j < 50; ++j) {
hash = md5(hash, 0, keyLengthInBytes);
hash = calculateMD5(hash, 0, keyLengthInBytes);
}
}
var encryptionKey = hash.subarray(0, keyLengthInBytes);
@ -467,7 +469,7 @@ var CipherTransformFactory = (function() {
for (j = 0, n = fileId.length; j < n; ++j)
hashData[i++] = fileId[j];
cipher = new ARCFourCipher(encryptionKey);
var checkData = cipher.encryptBlock(md5(hashData, 0, i));
var checkData = cipher.encryptBlock(calculateMD5(hashData, 0, i));
n = encryptionKey.length;
var derrivedKey = new Uint8Array(n), k;
for (j = 1; j <= 19; ++j) {
@ -491,16 +493,16 @@ var CipherTransformFactory = (function() {
function constructor(dict, fileId, password) {
var filter = dict.get('Filter');
if (!IsName(filter) || filter.name != 'Standard')
if (!isName(filter) || filter.name != 'Standard')
error('unknown encryption method');
this.dict = dict;
var algorithm = dict.get('V');
if (!IsInt(algorithm) ||
if (!isInt(algorithm) ||
(algorithm != 1 && algorithm != 2 && algorithm != 4))
error('unsupported encryption algorithm');
this.algorithm = algorithm;
var keyLength = dict.get('Length') || 40;
if (!IsInt(keyLength) ||
if (!isInt(keyLength) ||
keyLength < 40 || (keyLength % 8) != 0)
error('invalid key length');
// prepare keys
@ -542,7 +544,7 @@ var CipherTransformFactory = (function() {
key[i++] = 0x6C;
key[i++] = 0x54;
}
var hash = md5(key, 0, i);
var hash = calculateMD5(key, 0, i);
return hash.subarray(0, Math.min(encryptionKey.length + 5, 16));
}
@ -552,18 +554,18 @@ var CipherTransformFactory = (function() {
if (cryptFilter != null)
cfm = cryptFilter.get('CFM');
if (!cfm || cfm.name == 'None') {
return function() {
return function cipherTransformFactoryBuildCipherConstructorNone() {
return new NullCipher();
};
}
if ('V2' == cfm.name) {
return function() {
return function cipherTransformFactoryBuildCipherConstructorV2() {
return new ARCFourCipher(
buildObjectKey(num, gen, key, false));
};
}
if ('AESV2' == cfm.name) {
return function() {
return function cipherTransformFactoryBuildCipherConstructorAESV2() {
return new AES128Cipher(
buildObjectKey(num, gen, key, true));
};
@ -573,7 +575,8 @@ var CipherTransformFactory = (function() {
}
constructor.prototype = {
createCipherTransform: function(num, gen) {
createCipherTransform: function buildCipherCreateCipherTransform(num,
gen) {
if (this.algorithm == 4) {
return new CipherTransform(
buildCipherConstructor(this.cf, this.stmf,
@ -583,7 +586,7 @@ var CipherTransformFactory = (function() {
}
// algorithms 1 and 2
var key = buildObjectKey(num, gen, this.encryptionKey, false);
var cipherConstructor = function() {
var cipherConstructor = function buildCipherCipherConstructor() {
return new ARCFourCipher(key);
};
return new CipherTransform(cipherConstructor, cipherConstructor);

View File

@ -0,0 +1,18 @@
## "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)

View File

@ -0,0 +1,31 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
//
// See README for overview
//
'use strict';
getPdf('helloworld.pdf', function getPdfHelloWorld(data) {
//
// Instantiate PDFDoc with PDF data
//
var pdf = new PDFDoc(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);
});

View File

@ -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

View File

@ -0,0 +1,18 @@
<!doctype html>
<html>
<head>
<!-- PDF.js-specific -->
<script type="text/javascript" src="../../pdf.js"></script>
<script type="text/javascript" src="../../metrics.js"></script>
<script type="text/javascript" src="../../fonts.js"></script>
<script type="text/javascript" src="../../glyphlist.js"></script>
<script type="text/javascript" src="hello.js"></script>
</head>
<body>
<canvas id="the-canvas" style="border:1px solid black;"/>
</body>
</html>

View File

@ -1,31 +1,36 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
'use strict';
let Cc = Components.classes;
let Ci = Components.interfaces;
let Cm = Components.manager;
let Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import('resource://gre/modules/Services.jsm');
function log(str) {
dump(str + "\n");
};
dump(str + '\n');
}
function startup(aData, aReason) {
let manifestPath = "chrome.manifest";
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
let manifestPath = 'chrome.manifest';
let file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsILocalFile);
try {
file.initWithPath(aData.installPath.path);
file.append(manifestPath);
Cm.QueryInterface(Ci.nsIComponentRegistrar).autoRegister(file);
} catch(e) {
} catch (e) {
log(e);
}
};
}
function shutdown(aData, aReason) {
};
}
function install(aData, aReason) {
let url = "chrome://pdf.js/content/web/viewer.html?file=%s";
Services.prefs.setCharPref("extensions.pdf.js.url", url);
};
let url = 'chrome://pdf.js/content/web/viewer.html?file=%s';
Services.prefs.setCharPref('extensions.pdf.js.url', url);
}

View File

@ -1,55 +1,68 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
'use strict';
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;
const PDF_CONTENT_TYPE = "application/pdf";
const PDF_CONTENT_TYPE = 'application/pdf';
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
// TODO
// Add some download progress event
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
function log(aMsg) {
let msg = "pdfContentHandler.js: " + (aMsg.join ? aMsg.join("") : aMsg);
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService)
let msg = 'pdfContentHandler.js: ' + (aMsg.join ? aMsg.join('') : aMsg);
Cc['@mozilla.org/consoleservice;1'].getService(Ci.nsIConsoleService)
.logStringMessage(msg);
dump(msg + "\n");
};
dump(msg + '\n');
}
function fireEventTo(aName, aData, aWindow) {
let window = aWindow.wrappedJSObject;
let evt = window.document.createEvent('CustomEvent');
evt.initCustomEvent('pdf' + aName, false, false, aData);
window.document.dispatchEvent(evt);
}
function loadDocument(aWindow, aDocumentUrl) {
let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
let xhr = Cc['@mozilla.org/xmlextras/xmlhttprequest;1']
.createInstance(Ci.nsIXMLHttpRequest);
xhr.open("GET", aDocumentUrl);
xhr.mozResponseType = xhr.responseType = "arraybuffer";
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
let data = (xhr.mozResponseArrayBuffer || xhr.mozResponse ||
xhr.responseArrayBuffer || xhr.response);
try {
var view = new Uint8Array(data);
xhr.onprogress = function updateProgress(evt) {
if (evt.lengthComputable)
fireEventTo(evt.type, evt.loaded / evt.total, aWindow);
};
// I think accessing aWindow.wrappedJSObject returns a
// XPCSafeJSObjectWrapper and so it is safe but mrbkap can confirm that
let window = aWindow.wrappedJSObject;
var arrayBuffer = new window.ArrayBuffer(data.byteLength);
var view2 = new window.Uint8Array(arrayBuffer);
view2.set(view);
xhr.onerror = function error(evt) {
fireEventTo(evt.type, false, aWindow);
};
let evt = window.document.createEvent("CustomEvent");
evt.initCustomEvent("pdfloaded", false, false, arrayBuffer);
window.document.dispatchEvent(evt);
} catch(e) {
log("Error - " + e);
}
xhr.onload = function load(evt) {
let data = (xhr.mozResponseArrayBuffer || xhr.mozResponse ||
xhr.responseArrayBuffer || xhr.response);
try {
let view = new Uint8Array(data);
let window = aWindow.wrappedJSObject;
let arrayBuffer = new window.ArrayBuffer(data.byteLength);
let view2 = new window.Uint8Array(arrayBuffer);
view2.set(view);
fireEventTo(evt.type, arrayBuffer, aWindow);
} catch (e) {
log('Error - ' + e);
}
};
xhr.open('GET', aDocumentUrl);
xhr.responseType = 'arraybuffer';
xhr.send(null);
};
}
let WebProgressListener = {
init: function(aWindow, aUrl) {
init: function WebProgressListenerInit(aWindow, aUrl) {
this._locationHasChanged = false;
this._documentUrl = aUrl;
@ -64,11 +77,12 @@ let WebProgressListener = {
.getInterface(Ci.nsIWebProgress);
try {
webProgress.removeProgressListener(this);
} catch(e) {}
} catch (e) {}
webProgress.addProgressListener(this, flags);
},
onStateChange: function onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
onStateChange: function onStateChange(aWebProgress, aRequest, aStateFlags,
aStatus) {
const complete = Ci.nsIWebProgressListener.STATE_IS_WINDOW +
Ci.nsIWebProgressListener.STATE_STOP;
if ((aStateFlags & complete) == complete && this._locationHasChanged) {
@ -77,14 +91,17 @@ let WebProgressListener = {
}
},
onProgressChange: function onProgressChange(aWebProgress, aRequest, aCurSelf, aMaxSelf, aCurTotal, aMaxTotal) {
onProgressChange: function onProgressChange(aWebProgress, aRequest, aCurSelf,
aMaxSelf, aCurTotal, aMaxTotal) {
},
onLocationChange: function onLocationChange(aWebProgress, aRequest, aLocationURI) {
onLocationChange: function onLocationChange(aWebProgress, aRequest,
aLocationURI) {
this._locationHasChanged = true;
},
onStatusChange: function onStatusChange(aWebProgress, aRequest, aStatus, aMessage) {
onStatusChange: function onStatusChange(aWebProgress, aRequest, aStatus,
aMessage) {
},
onSecurityChange: function onSecurityChange(aWebProgress, aRequest, aState) {
@ -127,16 +144,16 @@ pdfContentHandler.prototype = {
WebProgressListener.init(window, uri.spec);
try {
let url = Services.prefs.getCharPref("extensions.pdf.js.url");
url = url.replace("%s", uri.spec);
let url = Services.prefs.getCharPref('extensions.pdf.js.url');
url = url.replace('%s', uri.spec);
window.location = url;
} catch(e) {
log("Error - " + e);
} catch (e) {
log('Error retrieving the pdf.js base url - ' + e);
}
},
classID: Components.ID("{2278dfd0-b75c-11e0-8257-1ba3d93c9f1a}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentHandler]),
classID: Components.ID('{2278dfd0-b75c-11e0-8257-1ba3d93c9f1a}'),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentHandler])
};
var NSGetFactory = XPCOMUtils.generateNSGetFactory([pdfContentHandler]);

View File

@ -12,7 +12,7 @@
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>6.0</em:minVersion>
<em:maxVersion>9.0.*</em:maxVersion>
<em:maxVersion>10.0.*</em:maxVersion>
</Description>
</em:targetApplication>
<em:bootstrap>true</em:bootstrap>

528
fonts.js Executable file → Normal file
View File

@ -11,6 +11,11 @@ var kMaxWaitForFontFace = 1000;
// Unicode Private Use Area
var kCmapGlyphOffset = 0xE000;
var kSizeOfGlyphArea = 0x1900;
// PDF Glyph Space Units are one Thousandth of a TextSpace Unit
// except for Type 3 fonts
var kPDFGlyphSpaceUnits = 1000;
// Until hinting is fully supported this constant can be used
var kHintingEnabled = false;
@ -611,8 +616,12 @@ var Font = (function Font() {
var constructor = function font_constructor(name, file, properties) {
this.name = name;
this.encoding = properties.encoding;
this.glyphs = properties.glyphs;
// Glyhps are no needed anymore? MERGE
// this.glyphs = properties.glyphs;
this.loadedName = properties.loadedName;
this.coded = properties.coded;
this.resources = properties.resources;
this.sizes = [];
var names = name.split('+');
@ -627,6 +636,12 @@ var Font = (function Font() {
this.loading = false;
return;
}
this.fontMatrix = properties.fontMatrix;
if (properties.type == 'Type3')
return;
// Trying to fix encoding using glyph widths and CIDSystemInfo.
this.fixWidths(properties);
if (!file) {
// The file data is not specified. Trying to fix the font name
@ -640,18 +655,23 @@ var Font = (function Font() {
// name ArialBlack for example will be replaced by Helvetica.
this.black = (name.search(/Black/g) != -1);
this.defaultWidth = properties.defaultWidth;
// MERGE
// this.loadedName = fontName.split('-')[0];
this.composite = properties.composite;
this.loading = false;
return;
}
var data;
switch (properties.type) {
var type = properties.type;
switch (type) {
case 'Type1':
case 'CIDFontType0':
this.mimetype = 'font/opentype';
var subtype = properties.subtype;
var cff = (subtype === 'Type1C') ?
var cff = (subtype == 'Type1C' || subtype == 'CIDFontType0C') ?
new Type2CFF(file, properties) : new CFF(name, file, properties);
// Wrap the CFF data inside an OTF font file
@ -673,8 +693,12 @@ var Font = (function Font() {
}
this.data = data;
this.type = properties.type;
this.textMatrix = properties.textMatrix;
// MERGE
//this.textMatrix = properties.textMatrix;
this.type = type;
this.fontMatrix = properties.fontMatrix;
this.defaultWidth = properties.defaultWidth;
this.loadedName = properties.loadedName;
this.composite = properties.composite;
// TODO: Remove this once we can be sure nothing got broken to du changes
@ -738,6 +762,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;
@ -791,19 +819,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 fontGetRangesSort(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;
@ -832,22 +865,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';
@ -867,7 +917,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;
@ -898,6 +950,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
@ -926,11 +996,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
@ -1037,9 +1107,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,
@ -1077,7 +1149,7 @@ var Font = (function Font() {
}
// Check that table are sorted by platformID then encodingID,
records.sort(function(a, b) {
records.sort(function fontReplaceCMapTableSort(a, b) {
return ((a.platformID << 16) + a.encodingID) -
((b.platformID << 16) + b.encodingID);
});
@ -1205,6 +1277,49 @@ var Font = (function Font() {
}
};
function sanitizeGlyphLocations(loca, glyf, numGlyphs,
isGlyphLocationsLong) {
var itemSize, itemDecode, itemEncode;
if (isGlyphLocationsLong) {
itemSize = 4;
itemDecode = function fontItemDecodeLong(data, offset) {
return (data[offset] << 24) | (data[offset + 1] << 16) |
(data[offset + 2] << 8) | data[offset + 3];
};
itemEncode = function fontItemEncodeLong(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 fontItemDecode(data, offset) {
return (data[offset] << 9) | (data[offset + 1] << 1);
};
itemEncode = function fontItemEncode(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'];
@ -1212,7 +1327,7 @@ var Font = (function Font() {
var header = readOpenTypeHeader(font);
var numTables = header.numTables;
var cmap, maxp, hhea, hmtx, vhea, vmtx;
var cmap, maxp, hhea, hmtx, vhea, vmtx, head, loca, glyf;
var tables = [];
for (var i = 0; i < numTables; i++) {
var table = readTableEntry(font);
@ -1226,6 +1341,8 @@ 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 {
@ -1233,6 +1350,10 @@ var Font = (function Font() {
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);
}
@ -1252,9 +1373,19 @@ 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))
});
}
@ -1267,6 +1398,11 @@ var Font = (function Font() {
sanitizeMetrics(font, hhea, hmtx, numGlyphs);
sanitizeMetrics(font, vhea, vmtx, numGlyphs);
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
// Sometimes it's 0. That needs to be fixed
if (hhea.data[10] == 0 && hhea.data[11] == 0) {
@ -1291,26 +1427,25 @@ var Font = (function Font() {
tables.push(cmap);
}
var encoding = properties.encoding;
if (!encoding[0]) {
// the font is directly characters to glyphs with no encoding
// so create an identity encoding
var widths = properties.widths;
for (i = 0; i < numGlyphs; i++) {
var width = widths[i];
encoding[i] = {
unicode: i + kCmapGlyphOffset,
width: IsNum(width) ? width : properties.defaultWidth
};
var encoding = properties.encoding, i;
// offsetting glyphs to avoid problematic unicode ranges
for (i in encoding) {
if (encoding.hasOwnProperty(i)) {
var unicode = encoding[i].unicode;
if (unicode <= 0x1f ||
(unicode >= 127 && unicode < kSizeOfGlyphArea))
encoding[i].unicode += kCmapGlyphOffset;
}
} else {
for (var code in encoding)
encoding[code].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 < kSizeOfGlyphArea) ?
i + kCmapGlyphOffset : i
});
}
cmap.data = createCMapTable(glyphs);
} else {
replaceCMapTable(cmap, font, properties);
@ -1398,7 +1533,7 @@ var Font = (function Font() {
'cmap': createCMapTable(charstrings.slice(), font.glyphIds),
// Font header
'head': (function() {
'head': (function fontFieldsHead() {
return stringToArray(
'\x00\x01\x00\x00' + // Version number
'\x00\x00\x10\x00' + // fontRevision
@ -1420,7 +1555,7 @@ var Font = (function Font() {
})(),
// Horizontal header
'hhea': (function() {
'hhea': (function fontFieldsHhea() {
return stringToArray(
'\x00\x01\x00\x00' + // Version number
string16(properties.ascent) + // Typographic Ascent
@ -1443,7 +1578,7 @@ var Font = (function Font() {
})(),
// Horizontal metrics
'hmtx': (function() {
'hmtx': (function fontFieldsHmtx() {
var hmtx = '\x00\x00\x00\x00'; // Fake .notdef
for (var i = 0; i < charstrings.length; i++) {
hmtx += string16(charstrings[i].width) + string16(0);
@ -1452,7 +1587,7 @@ var Font = (function Font() {
})(),
// Maximum profile
'maxp': (function() {
'maxp': (function fontFieldsMaxp() {
return stringToArray(
'\x00\x00\x50\x00' + // Version number
string16(charstrings.length + 1)); // Num of glyphs
@ -1474,6 +1609,153 @@ var Font = (function Font() {
}
return stringToArray(otf.file);
},
fixWidths: function font_fixWidths(properties) {
if (properties.type !== 'CIDFontType0' &&
properties.type !== 'CIDFontType2')
return;
var encoding = properties.encoding;
if (encoding[0])
return;
var glyphsWidths = properties.widths;
if (!glyphsWidths)
return;
var defaultWidth = properties.defaultWidth;
var cidSystemInfo = properties.cidSystemInfo;
var cidToUnicode;
if (cidSystemInfo) {
cidToUnicode = CIDToUnicodeMaps[
cidSystemInfo.registry + '-' + cidSystemInfo.ordering];
}
if (!cidToUnicode) {
// the font is directly characters to glyphs with no encoding
// so create an identity encoding
for (i = 0; i < 0xD800; i++) {
var width = glyphsWidths[i];
encoding[i] = {
unicode: i,
width: isNum(width) ? width : defaultWidth
};
}
// skipping surrogates + 256-user defined
for (i = 0xE100; i <= 0xFFFF; i++) {
var width = glyphsWidths[i];
encoding[i] = {
unicode: i,
width: isNum(width) ? width : defaultWidth
};
}
return;
}
encoding[0] = { unicode: 0, width: 0 };
var glyph = 1, i, j, k;
for (i = 0; i < cidToUnicode.length; ++i) {
var unicode = cidToUnicode[i];
var width;
if (isArray(unicode)) {
var length = unicode.length;
width = glyphsWidths[glyph];
for (j = 0; j < length; j++) {
k = unicode[j];
encoding[k] = {
unicode: k,
width: isNum(width) ? width : defaultWidth
};
}
glyph++;
} else if (typeof unicode === 'object') {
var fillLength = unicode.f;
if (fillLength) {
k = unicode.c;
for (j = 0; j < fillLength; ++j) {
width = glyphsWidths[glyph++];
encoding[k] = {
unicode: k,
width: isNum(width) ? width : defaultWidth
};
k++;
}
} else
glyph += unicode.s;
} else if (unicode) {
width = glyphsWidths[glyph++];
encoding[unicode] = {
unicode: unicode,
width: isNum(width) ? width : defaultWidth
};
} else
glyph++;
}
},
charsToGlyphs: function fonts_chars2Glyphs(chars) {
var charsCache = this.charsCache;
var glyphs;
// if we translated this string before, just grab it from the cache
if (charsCache) {
glyphs = charsCache[chars];
if (glyphs)
return glyphs;
}
// lazily create the translation cache
if (!charsCache)
charsCache = this.charsCache = Object.create(null);
// translate the string using the font's encoding
var encoding = this.encoding;
if (!encoding)
return chars;
glyphs = [];
if (this.composite) {
// composite fonts have multi-byte strings convert the string from
// single-byte to multi-byte
// XXX assuming CIDFonts are two-byte - later need to extract the
// correct byte encoding according to the PDF spec
var length = chars.length - 1; // looping over two bytes at a time so
// 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 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 glyph = encoding[charcode];
if ('undefined' == typeof(glyph)) {
warn('Unencoded charcode ' + charcode);
glyph = {
unicode: charcode,
width: this.defaultWidth
};
}
glyphs.push(glyph);
if (charcode == 0x20)
glyphs.push(null);
}
}
// Enter the translated string into the cache
return (charsCache[chars] = glyphs);
}
};
@ -1485,7 +1767,7 @@ var Font = (function Font() {
* program. Some of its logic depends on the Type2 charstrings
* structure.
*/
var Type1Parser = function() {
var Type1Parser = function type1Parser() {
/*
* Decrypt a Sequence of Ciphertext Bytes to Produce the Original Sequence
* of Plaintext Bytes. The function took a key as a parameter which can be
@ -1908,7 +2190,7 @@ var Type1Parser = function() {
// Make the angle into the right direction
matrix[2] *= -1;
properties.textMatrix = matrix;
properties.fontMatrix = matrix;
break;
case '/Encoding':
var size = parseInt(getToken(), 10);
@ -2013,7 +2295,7 @@ var CFFStrings = [
var type1Parser = new Type1Parser();
var CFF = function(name, file, properties) {
var CFF = function cffCFF(name, file, properties) {
// Get the data block containing glyphs and subrs informations
var headerBlock = file.getBytes(properties.length1);
type1Parser.extractFontHeader(headerBlock, properties);
@ -2186,7 +2468,7 @@ CFF.prototype = {
var cmd = map[command];
assert(cmd, 'Unknow command: ' + command);
if (IsArray(cmd))
if (isArray(cmd))
charstring.splice(i++, 1, cmd[0], cmd[1]);
else
charstring[i] = cmd;
@ -2213,7 +2495,7 @@ CFF.prototype = {
'names': this.createCFFIndexHeader([name]),
'topDict': (function topDict(self) {
return function() {
return function cffWrapTopDict() {
var header = '\x00\x01\x01\x01';
var dict =
'\xf8\x1b\x00' + // version
@ -2290,7 +2572,7 @@ CFF.prototype = {
'charstrings': this.createCFFIndexHeader([[0x8B, 0x0E]].concat(glyphs),
true),
'private': (function(self) {
'private': (function cffWrapPrivate(self) {
var data =
'\x8b\x14' + // defaultWidth
'\x8b\x15'; // nominalWidth
@ -2312,7 +2594,7 @@ CFF.prototype = {
continue;
var value = properties.private[field];
if (IsArray(value)) {
if (isArray(value)) {
data += self.encodeNumber(value[0]);
for (var i = 1; i < value.length; i++)
data += self.encodeNumber(value[i] - value[i - 1]);
@ -2343,7 +2625,7 @@ CFF.prototype = {
}
};
var Type2CFF = (function() {
var Type2CFF = (function type2CFF() {
// TODO: replace parsing code with the Type2Parser in font_utils.js
function constructor(file, properties) {
var bytes = file.getBytes();
@ -2368,16 +2650,21 @@ var Type2CFF = (function() {
var strings = this.getStrings(stringIndex);
var baseDict = this.parseDict(dictIndex.get(0));
var baseDict = this.parseDict(dictIndex.get(0).data);
var topDict = this.getTopDict(baseDict, strings);
var bytes = this.bytes;
var privateDict = {};
var privateInfo = topDict.Private;
var privOffset = privateInfo[1], privLength = privateInfo[0];
var privBytes = bytes.subarray(privOffset, privOffset + privLength);
baseDict = this.parseDict(privBytes);
var privDict = this.getPrivDict(baseDict, strings);
if (privateInfo) {
var privOffset = privateInfo[1], privLength = privateInfo[0];
var privBytes = bytes.subarray(privOffset, privOffset + privLength);
baseDict = this.parseDict(privBytes);
privateDict = this.getPrivDict(baseDict, strings);
} else {
privateDict.defaultWidthX = properties.defaultWidth;
}
var charStrings = this.parseIndex(topDict.CharStrings);
var charset = this.parseCharsets(topDict.charset,
@ -2393,10 +2680,37 @@ var Type2CFF = (function() {
if (hasSupplement)
bytes[topDict.Encoding] = 0;
// The CFF specification state that the 'dotsection' command
// (12, 0) is deprecated and treated as a no-op, but all Type2
// charstrings processors should support them. Unfortunately
// the font sanitizer don't. As a workaround the sequence (12, 0)
// is replaced by a useless (0, hmoveto).
var count = charStrings.length;
for (var i = 0; i < count; i++) {
var charstring = charStrings.get(i);
var start = charstring.start;
var data = charstring.data;
var length = data.length;
for (var j = 0; j <= length; j) {
var value = data[j++];
if (value == 12 && data[j++] == 0) {
bytes[start + j - 2] = 139;
bytes[start + j - 1] = 22;
} else if (value === 28) {
j += 2;
} else if (value >= 247 && value <= 254) {
j++;
} else if (value == 255) {
j += 4;
}
}
}
// charstrings contains info about glyphs (one element per glyph
// containing mappings for {unicode, width})
var charstrings = this.getCharStrings(charset, charStrings,
privDict, this.properties);
privateDict, this.properties);
// create the mapping between charstring and glyph id
var glyphIds = [];
@ -2413,13 +2727,11 @@ var Type2CFF = (function() {
},
getCharStrings: function cff_charstrings(charsets, charStrings,
privDict, properties) {
var defaultWidth = privDict['defaultWidthX'];
var nominalWidth = privDict['nominalWidthX'];
privateDict, properties) {
var defaultWidth = privateDict['defaultWidthX'];
var charstrings = [];
var differences = properties.differences;
var index = 0;
var index = properties.firstChar || 0;
for (var i = 1; i < charsets.length; i++) {
var code = -1;
var glyph = charsets[i];
@ -2431,7 +2743,8 @@ var Type2CFF = (function() {
}
}
var mapping = properties.glyphs[glyph] || {};
var mapping =
properties.glyphs[glyph] || properties.glyphs[index] || {};
if (code == -1)
index = code = mapping.unicode || index;
@ -2441,7 +2754,7 @@ var Type2CFF = (function() {
var width = mapping.width;
properties.glyphs[glyph] = properties.encoding[index] = {
unicode: code,
width: IsNum(width) ? width : defaultWidth
width: isNum(width) ? width : defaultWidth
};
charstrings.push({
@ -2453,7 +2766,9 @@ var Type2CFF = (function() {
}
// sort the array by the unicode value
charstrings.sort(function(a, b) {return a.unicode - b.unicode});
charstrings.sort(function type2CFFGetCharStringsSort(a, b) {
return a.unicode - b.unicode;
});
return charstrings;
},
@ -2473,8 +2788,8 @@ var Type2CFF = (function() {
if (pos == 0 || pos == 1) {
var gid = 1;
var baseEncoding =
pos ? Encodings.ExpertEncoding : Encodings.StandardEncoding;
var baseEncoding = pos ? Encodings.ExpertEncoding.slice() :
Encodings.StandardEncoding.slice();
for (var i = 0; i < charset.length; i++) {
var index = baseEncoding.indexOf(charset[i]);
if (index != -1)
@ -2519,37 +2834,42 @@ var Type2CFF = (function() {
},
parseCharsets: function cff_parsecharsets(pos, length, strings) {
if (pos == 0) {
return ISOAdobeCharset.slice();
} else if (pos == 1) {
return ExpertCharset.slice();
} else if (pos == 2) {
return ExpertSubsetCharset.slice();
}
var bytes = this.bytes;
var format = bytes[pos++];
var charset = ['.notdef'];
// subtract 1 for the .notdef glyph
length -= 1;
switch (format) {
case 0:
for (var i = 0; i < length; ++i) {
var id = bytes[pos++];
id = (id << 8) | bytes[pos++];
charset.push(strings[id]);
for (var i = 0; i < length; i++) {
var sid = (bytes[pos++] << 8) | bytes[pos++];
charset.push(strings[sid]);
}
break;
case 1:
while (charset.length <= length) {
var first = bytes[pos++];
first = (first << 8) | bytes[pos++];
var numLeft = bytes[pos++];
for (var i = 0; i <= numLeft; ++i)
charset.push(strings[first++]);
var sid = (bytes[pos++] << 8) | bytes[pos++];
var count = bytes[pos++];
for (var i = 0; i <= count; i++)
charset.push(strings[sid++]);
}
break;
case 2:
while (charset.length <= length) {
var first = bytes[pos++];
first = (first << 8) | bytes[pos++];
var numLeft = bytes[pos++];
numLeft = (numLeft << 8) | bytes[pos++];
for (var i = 0; i <= numLeft; ++i)
charset.push(strings[first++]);
var sid = (bytes[pos++] << 8) | bytes[pos++];
var count = (bytes[pos++] << 8) | bytes[pos++];
for (var i = 0; i <= count; i++)
charset.push(strings[sid++]);
}
break;
default:
@ -2624,20 +2944,20 @@ var Type2CFF = (function() {
}
return dict;
},
getStrings: function cff_getstrings(stringIndex) {
function bytesToString(bytesArr) {
var s = '';
for (var i = 0, ii = bytesArr.length; i < ii; ++i)
s += String.fromCharCode(bytesArr[i]);
return s;
getStrings: function cff_getStrings(stringIndex) {
function bytesToString(bytesArray) {
var str = '';
for (var i = 0, length = bytesArray.length; i < length; i++)
str += String.fromCharCode(bytesArray[i]);
return str;
}
var stringArray = [];
for (var i = 0, ii = CFFStrings.length; i < ii; ++i)
for (var i = 0, length = CFFStrings.length; i < length; i++)
stringArray.push(CFFStrings[i]);
for (var i = 0, ii = stringIndex.length; i < ii; ++i)
stringArray.push(bytesToString(stringIndex.get(i)));
for (var i = 0, length = stringIndex.length; i < length; i++)
stringArray.push(bytesToString(stringIndex.get(i).data));
return stringArray;
},
@ -2683,7 +3003,7 @@ var Type2CFF = (function() {
} else if (value <= 254) {
return -((value - 251) * 256) - dict[pos++] - 108;
} else {
error('Incorrect byte');
error('255 is not a valid DICT command');
}
return -1;
}
@ -2760,7 +3080,11 @@ var Type2CFF = (function() {
var start = offsets[index];
var end = offsets[index + 1];
return bytes.subarray(start, end);
return {
start: start,
end: end,
data: bytes.subarray(start, end)
};
},
length: count,
endPos: end

2565
pdf.js

File diff suppressed because it is too large Load Diff

View File

@ -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);
@ -38,16 +39,28 @@ function load() {
var r = new XMLHttpRequest();
r.open('GET', manifestFile, false);
r.onreadystatechange = function(e) {
r.onreadystatechange = function loadOnreadystatechange(e) {
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 cleanup() {
var styleSheet = document.styleSheets[0];
if (styleSheet) {
while (styleSheet.cssRules.length > 0)
styleSheet.deleteRule(0);
}
var guard = document.getElementById('content-end');
var body = document.body;
while (body.lastChild !== guard)
body.removeChild(body.lastChild);
}
function nextTask() {
// If there is a pdfDoc on the last task executed, destroy it to free memory.
@ -55,6 +68,8 @@ function nextTask() {
task.pdfDoc.destroy();
delete task.pdfDoc;
}
cleanup();
if (currentTaskIdx == manifest.length) {
return done();
}
@ -63,39 +78,34 @@ function nextTask() {
log('Loading file "' + task.file + '"\n');
var r = new XMLHttpRequest();
r.open('GET', task.file);
r.mozResponseType = r.responseType = 'arraybuffer';
r.onreadystatechange = function() {
getPdf(task.file, function nextTaskGetPdf(data) {
var failure;
if (r.readyState == 4) {
var data = r.mozResponseArrayBuffer || r.mozResponse ||
r.responseArrayBuffer || r.response;
try {
task.pdfDoc = new WorkerPDFDoc(data);
// task.pdfDoc = new PDFDoc(new Stream(data));
} catch (e) {
failure = 'load PDF doc : ' + e.toString();
}
task.pageNum = task.firstPage || 1, nextPage(task, failure);
try {
task.pdfDoc = new PDFDoc(data);
} catch (e) {
failure = 'load PDF doc : ' + e.toString();
}
};
r.send(null);
task.pageNum = task.firstPage || 1;
nextPage(task, failure);
});
}
function isLastPage(task) {
return (task.pageNum > task.pdfDoc.numPages);
return task.pageNum > task.pdfDoc.numPages || task.pageNum > task.pageLimit;
}
function canvasToDataURL() {
return canvas.toDataURL('image/png');
}
function nextPage(task, loadError) {
var failure = loadError || '';
if (!task.pdfDoc) {
sendTaskResult(canvas.toDataURL('image/png'), task, failure);
sendTaskResult(canvasToDataURL(), task, failure);
log('done' + (failure ? ' (failed !: ' + failure + ')' : '') + '\n');
++currentTaskIdx, nextTask();
++currentTaskIdx;
nextTask();
return;
}
@ -104,11 +114,19 @@ function nextPage(task, loadError) {
log(' Round ' + (1 + task.round) + '\n');
task.pageNum = 1;
} else {
++currentTaskIdx, nextTask();
++currentTaskIdx;
nextTask();
return;
}
}
if (task.skipPages && task.skipPages.indexOf(task.pageNum) >= 0) {
log(' skipping page ' + task.pageNum + '/' + task.pdfDoc.numPages +
'... ');
snapshotCurrentPage(task, '');
return;
}
var page = null;
if (!failure) {
@ -128,8 +146,8 @@ function nextPage(task, loadError) {
page.startRendering(
ctx,
function(e) {
snapshotCurrentPage(page, task, (!failure && e) ?
function nextPageStartRendering(e) {
snapshotCurrentPage(task, (!failure && e) ?
('render : ' + e) : failure);
}
);
@ -141,21 +159,22 @@ 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);
sendTaskResult(canvasToDataURL(), task, failure);
log('done' + (failure ? ' (failed !: ' + failure + ')' : '') + '\n');
// Set up the next request
var backoff = (inFlightRequests > 0) ? inFlightRequests * 10 : 0;
setTimeout(
function() {
++task.pageNum, nextPage(task);
function snapshotCurrentPageSetTimeout() {
++task.pageNum;
nextPage(task);
},
backoff
);
@ -188,11 +207,11 @@ function done() {
}
}
var inFlightRequests = 0;
function sendTaskResult(snapshot, task, failure) {
var result = { browser: browser,
id: task.id,
numPages: task.pdfDoc ? task.pdfDoc.numPages : 0,
numPages: task.pdfDoc ?
(task.pageLimit || task.pdfDoc.numPages) : 0,
failure: failure,
file: task.file,
round: task.round,
@ -203,11 +222,11 @@ function sendTaskResult(snapshot, task, failure) {
// (The POST URI is ignored atm.)
r.open('POST', '/submit_task_results', true);
r.setRequestHeader('Content-Type', 'application/json');
r.onreadystatechange = function(e) {
r.onreadystatechange = function sendTaskResultOnreadystatechange(e) {
if (r.readyState == 4) {
inFlightRequests--;
}
}
};
document.getElementById('inFlightCount').innerHTML = inFlightRequests++;
r.send(JSON.stringify(result));
}

18
test/pdfs/.gitignore vendored
View File

@ -1,3 +1,15 @@
pdf.pdf
intelisa.pdf
openweb_tm-PRINT.pdf
*.pdf
!tracemonkey.pdf
!ArabicCIDTrueType.pdf
!ThuluthFeatures.pdf
!arial_unicode_ab_cidfont.pdf
!arial_unicode_en_cidfont.pdf
!asciihexdecode.pdf
!canvas.pdf
!complex_ttf_font.pdf
!extgstate.pdf
!rotation.pdf
!simpletype3font.pdf
!sizes.pdf

BIN
test/pdfs/ThuluthFeatures.pdf Executable file

Binary file not shown.

105
test/pdfs/extgstate.pdf Normal file
View File

@ -0,0 +1,105 @@
%PDF-1.4
%öäüß
1 0 obj
<<
/Type /Catalog
/Version /1.4
/Pages 2 0 R
>>
endobj
2 0 obj
<<
/Type /Pages
/Kids [3 0 R]
/Count 1
>>
endobj
3 0 obj
<<
/Type /Page
/MediaBox [0 0 612 792]
/Resources 4 0 R
/Parent 2 0 R
/Contents 5 0 R
>>
endobj
4 0 obj
<<
/ExtGState 6 0 R
/Font 7 0 R
/XObject <<
>>
>>
endobj
5 0 obj
<<
/Length 8 0 R
>>
stream
/GS1 gs
/F0 12 Tf
BT
100 700 Td
(I should be courier!) Tj
ET
50 600 m
400 600 l
S
endstream
endobj
6 0 obj
<<
/GS1 9 0 R
>>
endobj
7 0 obj
<<
/F0 10 0 R
>>
endobj
8 0 obj
82
endobj
9 0 obj
<<
/Type /ExtGState
/LW 10
/LC 1
/LJ 2
/ML 0.3000000119
/D [[0.0917000026 183.3300018311]
0]
/Font [10 0 R 36]
>>
endobj
10 0 obj
<<
/Type /Font
/Subtype /Type1
/BaseFont /Courier
/Encoding /WinAnsiEncoding
>>
endobj
xref
0 11
0000000000 65535 f
0000000015 00000 n
0000000078 00000 n
0000000135 00000 n
0000000239 00000 n
0000000304 00000 n
0000000441 00000 n
0000000473 00000 n
0000000505 00000 n
0000000523 00000 n
0000000653 00000 n
trailer
<<
/Root 1 0 R
/ID [<BFFF29B7D1C75EC69AC080682C2AFC5B> <BFFF29B7D1C75EC69AC080682C2AFC5B>]
/Size 11
>>
startxref
749
%%EOF

1
test/pdfs/f1040.pdf.link Normal file
View File

@ -0,0 +1 @@
http://www.irs.gov/pub/irs-pdf/f1040.pdf

View File

@ -0,0 +1 @@
http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf

View File

@ -0,0 +1 @@
https://issues.apache.org/jira/secure/attachment/12421789/survey.pdf

View File

@ -0,0 +1 @@
http://www.bottledwater.org/public/pdf/IBWA05ModelCode_Mar2.pdf

View File

@ -0,0 +1,141 @@
%PDF-1.4
%öäüß
1 0 obj
<<
/Type /Catalog
/Version /1.4
/Pages 2 0 R
>>
endobj
2 0 obj
<<
/Type /Pages
/Kids [3 0 R]
/Count 1
>>
endobj
3 0 obj
<<
/Type /Page
/MediaBox [0 0 612 792]
/Parent 2 0 R
/Resources 4 0 R
/Contents 5 0 R
>>
endobj
4 0 obj
<<
/Font 6 0 R
/XObject <<
>>
>>
endobj
5 0 obj
<<
/Length 7 0 R
>>
stream
/F0 12 Tf
BT
100 700 Td
(ababab) Tj
ET
endstream
endobj
6 0 obj
<<
/F0 8 0 R
>>
endobj
7 0 obj
39
endobj
8 0 obj
<<
/Type /Font
/Subtype /Type3
/FontBBox [0 0 750 750]
/FontMatrix [0.001 0 0 0.001 0 0]
/CharProcs 9 0 R
/Encoding 10 0 R
/FirstChar 97
/LastChar 98
/Widths [1000 1000]
/FontDescriptor 11 0 R
>>
endobj
9 0 obj
<<
/square 12 0 R
/triangle 13 0 R
>>
endobj
10 0 obj
<<
/Type /Encoding
/Differences [97 /square /triangle]
>>
endobj
11 0 obj
<<
/Type /FontDescriptor
/FontName /SandT
/Flags 262178
/Ascent 0
/CapHeight 0
/Descent 0
/ItalicAngle 0
/StemV 0
/FontBBox [0 0 750 750]
>>
endobj
12 0 obj
<<
/Length 14 0 R
>>
stream
1000 0 0 0 750 750 d1 0 0 750 750 re f
endstream
endobj
13 0 obj
<<
/Length 15 0 R
>>
stream
1000 0 0 0 750 750 d1 0 0 m 375 750 l 750 0 l f
endstream
endobj
14 0 obj
38
endobj
15 0 obj
47
endobj
xref
0 16
0000000000 65535 f
0000000015 00000 n
0000000078 00000 n
0000000135 00000 n
0000000239 00000 n
0000000287 00000 n
0000000381 00000 n
0000000412 00000 n
0000000430 00000 n
0000000641 00000 n
0000000694 00000 n
0000000768 00000 n
0000000925 00000 n
0000001020 00000 n
0000001124 00000 n
0000001143 00000 n
trailer
<<
/Root 1 0 R
/ID [<DD02410A8B7AD4A0EE0D50E4180FABAC> <DD02410A8B7AD4A0EE0D50E4180FABAC>]
/Size 16
>>
startxref
1162
%%EOF

View File

@ -0,0 +1 @@
http://www.tcpdf.org/examples/example_033.pdf

View File

@ -0,0 +1 @@
http://www.sanface.com/pdf/test.pdf

View File

@ -0,0 +1 @@
https://docs.rice.edu/confluence/download/attachments/4588376/unix01.pdf?version=1

View File

@ -0,0 +1 @@
http://www.mit.edu/~6.033/writing-samples/usmanm_dp1.pdf

1
test/pdfs/vesta.pdf.link Normal file
View File

@ -0,0 +1 @@
http://www-csag.ucsd.edu/~jburke/Vesta/Vesta_Overview.pdf

View File

@ -0,0 +1 @@
http://www.airgid.com/book/wdsg_fitc.pdf

View File

@ -0,0 +1 @@
http://www.cdc.gov/ncidod/dvbid/westnile/languages/chinese.pdf

View File

@ -0,0 +1,2 @@
browser_manifest.json

View File

@ -23,6 +23,8 @@ class TestOptions(OptionParser):
OptionParser.__init__(self, **kwargs)
self.add_option("-m", "--masterMode", action="store_true", dest="masterMode",
help="Run the script in master mode.", default=False)
self.add_option("--noPrompts", action="store_true", dest="noPrompts",
help="Uses default answers (intended for CLOUD TESTS only!).", default=False)
self.add_option("--manifestFile", action="store", type="string", dest="manifestFile",
help="A JSON file in the form of test_manifest.json (the default).")
self.add_option("-b", "--browser", action="store", type="string", dest="browser",
@ -321,7 +323,7 @@ def setUp(options):
if options.masterMode and os.path.isdir(TMPDIR):
print 'Temporary snapshot dir tmp/ is still around.'
print 'tmp/ can be removed if it has nothing you need.'
if prompt('SHOULD THIS SCRIPT REMOVE tmp/? THINK CAREFULLY'):
if options.noPrompts or prompt('SHOULD THIS SCRIPT REMOVE tmp/? THINK CAREFULLY'):
subprocess.call(( 'rm', '-rf', 'tmp' ))
assert not os.path.isdir(TMPDIR)
@ -414,8 +416,9 @@ def checkEq(task, results, browser, masterMode):
path = os.path.join(pfx, str(page + 1))
if not os.access(path, os.R_OK):
print 'WARNING: no reference snapshot', path
State.numEqNoSnapshot += 1
if not masterMode:
print 'WARNING: no reference snapshot', path
else:
f = open(path)
ref = f.read()
@ -432,9 +435,9 @@ def checkEq(task, results, browser, masterMode):
# NB: this follows the format of Mozilla reftest
# output so that we can reuse its reftest-analyzer
# script
print >>eqLog, 'REFTEST TEST-UNEXPECTED-FAIL |', browser +'-'+ taskId +'-page'+ str(page + 1), '| image comparison (==)'
print >>eqLog, 'REFTEST IMAGE 1 (TEST):', snapshot
print >>eqLog, 'REFTEST IMAGE 2 (REFERENCE):', ref
eqLog.write('REFTEST TEST-UNEXPECTED-FAIL | ' + browser +'-'+ taskId +'-page'+ str(page + 1) + ' | image comparison (==)\n')
eqLog.write('REFTEST IMAGE 1 (TEST): ' + snapshot + '\n')
eqLog.write('REFTEST IMAGE 2 (REFERENCE): ' + ref + '\n')
passed = False
State.numEqFailures += 1
@ -444,7 +447,8 @@ def checkEq(task, results, browser, masterMode):
try:
os.makedirs(tmpTaskDir)
except OSError, e:
print >>sys.stderr, 'Creating', tmpTaskDir, 'failed!'
if e.errno != 17: # file exists
print >>sys.stderr, 'Creating', tmpTaskDir, 'failed!'
of = open(os.path.join(tmpTaskDir, str(page + 1)), 'w')
of.write(snapshot)
@ -453,7 +457,6 @@ def checkEq(task, results, browser, masterMode):
if passed:
print 'TEST-PASS | eq test', task['id'], '| in', browser
def checkFBF(task, results, browser):
round0, round1 = results[0], results[1]
assert len(round0) == len(round1)
@ -503,10 +506,10 @@ def maybeUpdateRefImages(options, browser):
print ' Yes! The references in tmp/ can be synced with ref/.'
if options.reftest:
startReftest(browser, options)
if not prompt('Would you like to update the master copy in ref/?'):
if options.noPrompts or not prompt('Would you like to update the master copy in ref/?'):
print ' OK, not updating.'
else:
sys.stdout.write(' Updating ... ')
sys.stdout.write(' Updating ref/ ... ')
# XXX unclear what to do on errors here ...
# NB: do *NOT* pass --delete to rsync. That breaks this
@ -539,7 +542,8 @@ def runTests(options, browsers):
teardownBrowsers(browsers)
t2 = time.time()
print "Runtime was", int(t2 - t1), "seconds"
if State.eqLog:
State.eqLog.close();
if options.masterMode:
maybeUpdateRefImages(options, browsers[0])
elif options.reftest and State.numEqFailures > 0:

View File

@ -69,6 +69,17 @@
"rounds": 1,
"type": "load"
},
{ "id": "thuluthfont-pdf",
"file": "pdfs/ThuluthFeatures.pdf",
"rounds": 1,
"type": "eq"
},
{ "id": "wnv_chinese-pdf",
"file": "pdfs/wnv_chinese.pdf",
"link": true,
"rounds": 1,
"type": "eq"
},
{ "id": "i9-pdf",
"file": "pdfs/i9.pdf",
"link": true,
@ -115,5 +126,78 @@
"link": true,
"rounds": 1,
"type": "eq"
},
{ "id": "wdsg_fitc",
"file": "pdfs/wdsg_fitc.pdf",
"link": true,
"rounds": 1,
"type": "eq"
},
{ "id": "unix01",
"file": "pdfs/unix01.pdf",
"link": true,
"rounds": 1,
"type": "eq"
},
{ "id": "fips197",
"file": "pdfs/fips197.pdf",
"link": true,
"rounds": 1,
"type": "load"
},
{ "id": "txt2pdf",
"file": "pdfs/txt2pdf.pdf",
"link": true,
"rounds": 1,
"type": "load"
},
{ "id": "f1040",
"file": "pdfs/f1040.pdf",
"link": true,
"rounds": 1,
"type": "load"
},
{ "id": "hudsonsurvey",
"file": "pdfs/hudsonsurvey.pdf",
"link": true,
"rounds": 1,
"type": "load"
},
{ "id": "extgstate",
"file": "pdfs/extgstate.pdf",
"link": false,
"rounds": 1,
"type": "load"
},
{ "id": "usmanm-bad",
"file": "pdfs/usmanm-bad.pdf",
"link": true,
"rounds": 1,
"type": "eq"
},
{ "id": "vesta-bad",
"file": "pdfs/vesta.pdf",
"link": true,
"rounds": 1,
"type": "load"
},
{ "id": "ibwa-bad",
"file": "pdfs/ibwa-bad.pdf",
"link": true,
"rounds": 1,
"skipPages": [ 16 ],
"type": "load"
},
{ "id": "tcpdf_033",
"file": "pdfs/tcpdf_033.pdf",
"link": true,
"rounds": 1,
"type": "eq"
},
{ "id": "simpletype3font",
"file": "pdfs/simpletype3font.pdf",
"link": false,
"rounds": 1,
"type": "eq"
}
]

View File

@ -7,6 +7,8 @@
<script type="text/javascript" src="/crypto.js"></script>
<script type="text/javascript" src="/glyphlist.js"></script>
<script type="text/javascript" src="/metrics.js"></script>
<script type="text/javascript" src="/charsets.js"></script>
<script type="text/javascript" src="/cidmaps.js"></script>
<script type="text/javascript" src="driver.js"></script>
<script type="text/javascript" src="../worker.js"></script>
<script type="text/javascript" src="../worker/message_handler.js"></script>
@ -17,6 +19,7 @@
<body onload="load();">
<pre style="width:800; height:800; overflow: scroll;"id="stdout"></pre>
<p>Inflight requests: <span id="inFlightCount"></span></p>
<div id="content-end"><!-- cleanup() guard --></div>
</body>
</html>

View File

@ -3,400 +3,6 @@
'use strict';
var CFFStrings = [
'.notdef',
'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',
'onesuperior',
'logicalnot',
'mu',
'trademark',
'Eth',
'onehalf',
'plusminus',
'Thorn',
'onequarter',
'divide',
'brokenbar',
'degree',
'thorn',
'threequarters',
'twosuperior',
'registered',
'minus',
'eth',
'multiply',
'threesuperior',
'copyright',
'Aacute',
'Acircumflex',
'Adieresis',
'Agrave',
'Aring',
'Atilde',
'Ccedilla',
'Eacute',
'Ecircumflex',
'Edieresis',
'Egrave',
'Iacute',
'Icircumflex',
'Idieresis',
'Igrave',
'Ntilde',
'Oacute',
'Ocircumflex',
'Odieresis',
'Ograve',
'Otilde',
'Scaron',
'Uacute',
'Ucircumflex',
'Udieresis',
'Ugrave',
'Yacute',
'Ydieresis',
'Zcaron',
'aacute',
'acircumflex',
'adieresis',
'agrave',
'aring',
'atilde',
'ccedilla',
'eacute',
'ecircumflex',
'edieresis',
'egrave',
'iacute',
'icircumflex',
'idieresis',
'igrave',
'ntilde',
'oacute',
'ocircumflex',
'odieresis',
'ograve',
'otilde',
'scaron',
'uacute',
'ucircumflex',
'udieresis',
'ugrave',
'yacute',
'ydieresis',
'zcaron',
'exclamsmall',
'Hungarumlautsmall',
'dollaroldstyle',
'dollarsuperior',
'ampersandsmall',
'Acutesmall',
'parenleftsuperior',
'parenrightsuperior',
'266 ff',
'onedotenleader',
'zerooldstyle',
'oneoldstyle',
'twooldstyle',
'threeoldstyle',
'fouroldstyle',
'fiveoldstyle',
'sixoldstyle',
'sevenoldstyle',
'eightoldstyle',
'nineoldstyle',
'commasuperior',
'threequartersemdash',
'periodsuperior',
'questionsmall',
'asuperior',
'bsuperior',
'centsuperior',
'dsuperior',
'esuperior',
'isuperior',
'lsuperior',
'msuperior',
'nsuperior',
'osuperior',
'rsuperior',
'ssuperior',
'tsuperior',
'ff',
'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',
'questiondownsmall',
'oneeighth',
'threeeighths',
'fiveeighths',
'seveneighths',
'onethird',
'twothirds',
'zerosuperior',
'foursuperior',
'fivesuperior',
'sixsuperior',
'sevensuperior',
'eightsuperior',
'ninesuperior',
'zeroinferior',
'oneinferior',
'twoinferior',
'threeinferior',
'fourinferior',
'fiveinferior',
'sixinferior',
'seveninferior',
'eightinferior',
'nineinferior',
'centinferior',
'dollarinferior',
'periodinferior',
'commainferior',
'Agravesmall',
'Aacutesmall',
'Acircumflexsmall',
'Atildesmall',
'Adieresissmall',
'Aringsmall',
'AEsmall',
'Ccedillasmall',
'Egravesmall',
'Eacutesmall',
'Ecircumflexsmall',
'Edieresissmall',
'Igravesmall',
'Iacutesmall',
'Icircumflexsmall',
'Idieresissmall',
'Ethsmall',
'Ntildesmall',
'Ogravesmall',
'Oacutesmall',
'Ocircumflexsmall',
'Otildesmall',
'Odieresissmall',
'OEsmall',
'Oslashsmall',
'Ugravesmall',
'Uacutesmall',
'Ucircumflexsmall',
'Udieresissmall',
'Yacutesmall',
'Thornsmall',
'Ydieresissmall',
'001.000',
'001.001',
'001.002',
'001.003',
'Black',
'Bold',
'Book',
'Light',
'Medium',
'Regular',
'Roman',
'Semibold'
];
var CFFEncodingMap = {
'0': '-reserved-',
'1': 'hstem',
@ -560,7 +166,7 @@ var CFFDictDataMap = {
'18': {
name: 'ExpansionFactor'
},
'9': {
'19': {
name: 'initialRandomSeed'
},
'20': {

View File

@ -20,17 +20,27 @@ function readCharset(aStream, aCharstrings) {
var charset = {};
var format = aStream.getByte();
var count = aCharstrings.length - 1;
if (format == 0) {
charset['.notdef'] = readCharstringEncoding(aCharstrings[0]);
var count = aCharstrings.length - 1;
for (var i = 1; i < count + 1; i++) {
var sid = aStream.getByte() << 8 | aStream.getByte();
charset[CFFStrings[sid]] = readCharstringEncoding(aCharstrings[i]);
//log(CFFStrings[sid] + "::" + charset[CFFStrings[sid]]);
}
} else if (format == 1) {
error('Charset Range are not supported');
for (var i = 1; i < count + 1; i++) {
var first = aStream.getByte();
first = (first << 8) | aStream.getByte();
var numLeft = aStream.getByte();
for (var j = 0; j <= numLeft; j++) {
var sid = first++;
if (CFFStrings[sid] == 'three')
log(aCharstrings[j]);
charset[CFFStrings[sid]] = readCharstringEncoding(aCharstrings[j]);
}
}
} else {
error('Invalid charset format');
}
@ -44,6 +54,9 @@ function readCharset(aStream, aCharstrings) {
* chapter 3.1.
*/
function readCharstringEncoding(aString) {
if (!aString)
return '';
var charstringTokens = [];
var count = aString.length;
@ -69,11 +82,11 @@ 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;
token = (value - 247) * 256 + aString[i++] + 108;
} else if (value < 255) {
token = -((value - 251) * 256) - aString[i++] - 108;
token = -(value - 251) * 256 - aString[i++] - 108;
} else {// value == 255
token = aString[i++] << 24 | aString[i++] << 16 |
aString[i++] << 8 | aString[i];
@ -113,7 +126,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,11 +157,11 @@ 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;
token = (value - 247) * 256 + aString[i++] + 108;
} else if (value <= 254) {
token = -((value - 251) * 256) - aString[i++] - 108;
token = -(value - 251) * 256 - aString[i++] - 108;
} else if (value == 255) {
error('255 is not a valid DICT command');
}
@ -193,13 +206,13 @@ function readFontIndexData(aStream, aIsByte) {
}
error(offsize + ' is not a valid offset size');
return null;
};
}
var offsets = [];
for (var i = 0; i < count + 1; i++)
offsets.push(getNextOffset());
log('Found ' + count + ' objects at offsets :' +
dump('Found ' + count + ' objects at offsets :' +
offsets + ' (offsize: ' + offsize + ')');
// Now extract the objects
@ -219,7 +232,7 @@ function readFontIndexData(aStream, aIsByte) {
return objects;
}
var Type2Parser = function(aFilePath) {
var Type2Parser = function type2Parser(aFilePath) {
var font = new Dict();
var xhr = new XMLHttpRequest();
@ -236,7 +249,7 @@ var Type2Parser = function(aFilePath) {
function dump(aStr) {
if (debug)
log(aStr);
};
}
function parseAsToken(aString, aMap) {
var decoded = readFontDictData(aString, aMap);
@ -245,7 +258,7 @@ var Type2Parser = function(aFilePath) {
var count = decoded.length;
for (var i = 0; i < count; i++) {
var token = decoded[i];
if (IsNum(token)) {
if (isNum(token)) {
stack.push(token);
} else {
switch (token.operand) {
@ -277,31 +290,28 @@ var Type2Parser = function(aFilePath) {
}
}
}
};
}
this.parse = function(aStream) {
this.parse = function type2ParserParse(aStream) {
font.set('major', aStream.getByte());
font.set('minor', aStream.getByte());
font.set('hdrSize', aStream.getByte());
font.set('offsize', aStream.getByte());
// Move the cursor after the header
aStream.skip(font.get('hdrSize') - aStream.pos);
// Read the NAME Index
dump('Reading Index: Names');
font.set('Names', readFontIndexData(aStream));
log('Names: ' + font.get('Names'));
dump('Names: ' + font.get('Names'));
// Read the Top Dict Index
dump('Reading Index: TopDict');
var topDict = readFontIndexData(aStream, true);
log('TopDict: ' + topDict);
dump('TopDict: ' + topDict);
// Read the String Index
dump('Reading Index: Strings');
var strings = readFontIndexData(aStream);
log('strings: ' + strings);
dump('strings: ' + strings);
// Fill up the Strings dictionary with the new unique strings
for (var i = 0; i < strings.length; i++)
@ -321,7 +331,7 @@ var Type2Parser = function(aFilePath) {
// Reading Private Dict
var priv = font.get('Private');
log('Reading Private Dict (offset: ' + priv.offset +
dump('Reading Private Dict (offset: ' + priv.offset +
' size: ' + priv.size + ')');
aStream.pos = priv.offset;
@ -353,7 +363,7 @@ var Type2Parser = function(aFilePath) {
aStream.pos = charsetEntry;
var charset = readCharset(aStream, charStrings);
}
}
};
};
/*

58
web/compatibility.js Executable file → Normal file
View File

@ -1,8 +1,10 @@
/* -*- 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() {
(function checkTypedArrayCompatibility() {
if (typeof Uint8Array !== 'undefined')
return;
@ -10,8 +12,9 @@
return this.slice(start, end);
}
function set_(array, offset) {
if (arguments.length < 2) offset = 0;
function setArrayOffset(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 = setArrayOffset;
if (typeof arg1 === 'object' && arg1.buffer)
result.buffer = arg1.buffer;
@ -44,31 +49,31 @@
})();
// Object.create() ?
(function() {
(function checkObjectCreateCompatibility() {
if (typeof Object.create !== 'undefined')
return;
Object.create = function(proto) {
var constructor = function() {};
Object.create = function objectCreate(proto) {
var constructor = function objectCreateConstructor() {};
constructor.prototype = proto;
return new constructor();
};
})();
// Object.defineProperty() ?
(function() {
(function checkObjectDefinePropertyCompatibility() {
if (typeof Object.defineProperty !== 'undefined')
return;
Object.defineProperty = function(obj, name, def) {
Object.defineProperty = function objectDefineProperty(obj, name, def) {
delete obj[name];
if ('get' in def)
obj.__defineGetter__(name, def['get']);
if ('set' in def)
obj.__defineSetter__(name, def['set']);
if ('value' in def) {
obj.__defineSetter__(name, function(value) {
this.__defineGetter__(name, function() {
obj.__defineSetter__(name, function objectDefinePropertySetter(value) {
this.__defineGetter__(name, function objectDefinePropertyGetter() {
return value;
});
return value;
@ -79,7 +84,7 @@
})();
// No XMLHttpRequest.response ?
(function() {
(function checkXMLHttpRequestResponseCompatibility() {
var xhrPrototype = XMLHttpRequest.prototype;
if ('response' in xhrPrototype ||
'mozResponseArrayBuffer' in xhrPrototype ||
@ -89,7 +94,7 @@
// IE ?
if (typeof VBArray !== 'undefined') {
Object.defineProperty(xhrPrototype, 'response', {
get: function() {
get: function xmlHttpRequestResponseGet() {
return new Uint8Array(new VBArray(this.responseBody).toArray());
}
});
@ -117,14 +122,14 @@
})();
// window.btoa (base64 encode function) ?
(function() {
(function checkWindowBtoaCompatibility() {
if ('btoa' in window)
return;
var digits =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
window.btoa = function(chars) {
window.btoa = function windowBtoa(chars) {
var buffer = '';
var i, n;
for (i = 0, n = chars.length; i < n; i += 3) {
@ -142,13 +147,13 @@
})();
// Function.prototype.bind ?
(function() {
(function checkFunctionPrototypeBindCompatibility() {
if (typeof Function.prototype.bind !== 'undefined')
return;
Function.prototype.bind = function(obj) {
Function.prototype.bind = function functionPrototypeBind(obj) {
var fn = this, headArgs = Array.prototype.slice.call(arguments, 1);
var bound = function() {
var bound = function functionPrototypeBindBound() {
var args = Array.prototype.concat.apply(headArgs, arguments);
return fn.apply(obj, args);
};
@ -157,15 +162,15 @@
})();
// IE9 text/html data URI
(function() {
(function checkDocumentDocumentModeCompatibility() {
if (document.documentMode !== 9)
return;
// overriding the src property
var originalSrcDescriptor = Object.getOwnPropertyDescriptor(
HTMLIFrameElement.prototype, 'src');
Object.defineProperty(HTMLIFrameElement.prototype, 'src', {
get: function() { return this.$src; },
set: function(src) {
get: function htmlIFrameElementPrototypeSrcGet() { return this.$src; },
set: function htmlIFrameElementPrototypeSrcSet(src) {
this.$src = src;
if (src.substr(0, 14) != 'data:text/html') {
originalSrcDescriptor.set.call(this, src);
@ -174,7 +179,7 @@
// for text/html, using blank document and then
// document's open, write, and close operations
originalSrcDescriptor.set.call(this, 'about:blank');
setTimeout((function() {
setTimeout((function htmlIFrameElementPrototypeSrcOpenWriteClose() {
var doc = this.contentDocument;
doc.open('text/html');
doc.write(src.substr(src.indexOf(',') + 1));
@ -184,3 +189,4 @@
enumerable: true
});
})();

15
web/viewer.css Executable file → Normal file
View File

@ -119,6 +119,7 @@ span#info {
margin-right:auto;
line-height: 134px;
text-align: center;
overflow: hidden;
}
.thumbnail:not([data-loaded]) {
@ -195,16 +196,17 @@ span#info {
canvas {
margin: auto;
display: block;
box-shadow: 0px 4px 10px #000;
-moz-box-shadow: 0px 4px 10px #000;
-webkit-box-shadow: 0px 4px 10px #000;
}
.page {
width: 816px;
height: 1056px;
margin: 10px auto;
position:relative;
position: relative;
overflow: hidden;
box-shadow: 0px 4px 10px #000;
-moz-box-shadow: 0px 4px 10px #000;
-webkit-box-shadow: 0px 4px 10px #000;
}
.page > a {
@ -271,3 +273,8 @@ canvas {
page-break-after: always;
}
}
#loading {
margin: 100px 0;
text-align: center;
}

View File

@ -11,6 +11,8 @@
<script type="text/javascript" src="../crypto.js"></script>
<script type="text/javascript" src="../glyphlist.js"></script>
<script type="text/javascript" src="../metrics.js"></script>
<script type="text/javascript" src="../charsets.js"></script>
<script type="text/javascript" src="../cidmaps.js"></script>
<script type="text/javascript" src="../worker.js"></script>
<script type="text/javascript" src="../worker/message_handler.js"></script>
<script type="text/javascript" src="../worker/processor_handler.js"></script>
@ -30,7 +32,7 @@
<div class="separator"></div>
<input type="text" id="pageNumber" onchange="PDFView.page = this.value;" value="1" size="4"/>
<input type="number" id="pageNumber" onchange="PDFView.page = this.value;" value="1" size="4" min="1" />
<span>/</span>
<span id="numPages">--</span>
@ -93,6 +95,7 @@
</div>
</div>
<div id="loading">Loading... 0%</div>
<div id="viewer"></div>
</body>
</html>

View File

@ -9,11 +9,13 @@ var kDefaultScaleDelta = 1.1;
var kCacheSize = 20;
var kCssUnits = 96.0 / 72.0;
var kScrollbarPadding = 40;
var kMinScale = 0.25;
var kMaxScale = 4.0;
var Cache = function(size) {
var Cache = function cacheCache(size) {
var data = [];
this.push = function(view) {
this.push = function cachePush(view) {
data.push(view);
if (data.length > size)
data.shift().update();
@ -21,23 +23,22 @@ var Cache = function(size) {
};
var cache = new Cache(kCacheSize);
var currentPageNumber = 1;
var PDFView = {
pages: [],
thumbnails: [],
currentScale: kDefaultScale,
initialBookmark: document.location.hash.substring(1),
setScale: function(val, resetAutoSettings) {
setScale: function pdfViewSetScale(val, resetAutoSettings) {
var pages = this.pages;
for (var i = 0; i < pages.length; i++)
pages[i].update(val * kCssUnits);
this.currentScale = val;
if (document.location.hash == '#' + this.page)
this.pages[this.page - 1].draw();
else
// Jump the scroll position to the correct page.
document.location.hash = this.page;
this.pages[this.page - 1].scrollIntoView();
this.pages[this.page - 1].draw();
var event = document.createEvent('UIEvents');
event.initUIEvent('scalechange', false, false, window, 0);
@ -46,7 +47,7 @@ var PDFView = {
window.dispatchEvent(event);
},
parseScale: function(value, resetAutoSettings) {
parseScale: function pdfViewParseScale(value, resetAutoSettings) {
if ('custom' == value)
return;
@ -58,9 +59,9 @@ var PDFView = {
var currentPage = this.pages[this.page - 1];
var pageWidthScale = (window.innerWidth - kScrollbarPadding) /
currentPage.width / kCssUnits;
currentPage.width / kCssUnits;
var pageHeightScale = (window.innerHeight - kScrollbarPadding) /
currentPage.height / kCssUnits;
currentPage.height / kCssUnits;
if ('page-width' == value)
this.setScale(pageWidthScale, resetAutoSettings);
if ('page-height' == value)
@ -71,12 +72,14 @@ var PDFView = {
}
},
zoomIn: function() {
this.setScale(this.currentScale * kDefaultScaleDelta, true);
zoomIn: function pdfViewZoomIn() {
var newScale = Math.min(kMaxScale, this.currentScale * kDefaultScaleDelta);
this.setScale(newScale, true);
},
zoomOut: function() {
this.setScale(this.currentScale / kDefaultScaleDelta, true);
zoomOut: function pdfViewZoomOut() {
var newScale = Math.max(kMinScale, this.currentScale / kDefaultScaleDelta);
this.setScale(newScale, true);
},
set page(val) {
@ -87,44 +90,41 @@ var PDFView = {
return;
}
document.location.hash = val;
currentPageNumber = val;
document.getElementById('previous').disabled = (val == 1);
document.getElementById('next').disabled = (val == pages.length);
if (input.value == val)
return;
if (input.value != val) {
input.value = val;
}
input.value = val;
pages[val - 1].draw();
pages[val - 1].scrollIntoView();
},
get page() {
return parseInt(document.location.hash.substring(1)) || 1;
return currentPageNumber;
},
open: function(url, scale) {
open: function pdfViewOpen(url, scale) {
if (url.indexOf('http') == 0)
return;
document.title = url;
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);
getPdf(
{
url: url,
progress: function getPdfProgress(evt) {
if (evt.lengthComputable)
PDFView.progress(evt.loaded / evt.total);
},
error: PDFView.error
},
function getPdfLoad(data) {
PDFView.load(data, scale);
}
};
xhr.send(null);
});
},
navigateTo: function(dest) {
navigateTo: function pdfViewNavigateTo(dest) {
if (typeof dest === 'string')
dest = this.destinations[dest];
if (!(dest instanceof Array))
@ -140,7 +140,36 @@ var PDFView = {
}
},
load: function(data, scale) {
getDestinationHash: function pdfViewGetDestinationHash(dest) {
if (typeof dest === 'string')
return '#' + escape(dest);
if (dest instanceof Array) {
var destRef = dest[0]; // see nevigateTo method for dest format
var pageNumber = destRef instanceof Object ?
this.pagesRefMap[destRef.num + ' ' + destRef.gen + ' R'] :
(destRef + 1);
if (pageNumber) {
return '#page=' + pageNumber + '&dest=' + dest.slice(1).join(',');
}
}
return '';
},
error: function pdfViewError() {
var loadingIndicator = document.getElementById('loading');
loadingIndicator.innerHTML = 'Error';
},
progress: function pdfViewProgress(level) {
var percent = Math.round(level * 100);
var loadingIndicator = document.getElementById('loading');
loadingIndicator.innerHTML = 'Loading... ' + percent + '%';
},
load: function pdfViewLoad(data, scale) {
var loadingIndicator = document.getElementById('loading');
loadingIndicator.style.display = 'none';
var sidebar = document.getElementById('sidebarView');
sidebar.parentNode.scrollTop = 0;
@ -152,15 +181,10 @@ var PDFView = {
while (container.hasChildNodes())
container.removeChild(container.lastChild);
var pdf;
if (true /* Use Worker */) {
pdf = new WorkerPDFDoc(data);
} else {
pdf = new PDFDoc(new Stream(data));
}
var pdf = new WorkerPDFDoc(data);
var pagesCount = pdf.numPages;
document.getElementById('numPages').innerHTML = pagesCount;
document.getElementById('pageNumber').max = pagesCount;
var pages = this.pages = [];
var pagesRefMap = {};
@ -169,14 +193,14 @@ var PDFView = {
var page = pdf.getPage(i);
pages.push(new PageView(container, page, i, page.width, page.height,
page.stats, this.navigateTo.bind(this)));
thumbnails.push(new ThumbnailView(sidebar, pages[i - 1],
thumbnails.push(new ThumbnailView(sidebar, page, i,
page.width / page.height));
var pageRef = page.ref;
pagesRefMap[pageRef.num + ' ' + pageRef.gen + ' R'] = i;
}
this.setScale(scale || kDefaultScale, true);
this.page = parseInt(document.location.hash.substring(1)) || 1;
this.pagesRefMap = pagesRefMap;
this.destinations = pdf.catalog.destinations;
if (pdf.catalog.documentOutline) {
@ -185,9 +209,31 @@ var PDFView = {
outlineSwitchButton.removeAttribute('disabled');
this.switchSidebarView('outline');
}
if (this.initialBookmark) {
this.setHash(this.initialBookmark);
this.initialBookmark = null;
}
else
this.page = 1;
},
switchSidebarView: function(view) {
setHash: function pdfViewSetHash(hash) {
if (!hash)
return;
if (hash.indexOf('=') >= 0) {
// TODO more complex hashes, for now catching page=XX only
var m = /\bpage=(\d+)/.exec(hash);
if (m && m[1] > 0)
this.page = m[1];
} else if (/^\d+$/.test(hash)) // page number
this.page = hash;
else // named destination
PDFView.navigateTo(unescape(hash));
},
switchSidebarView: function pdfViewSwitchSidebarView(view) {
var thumbsScrollView = document.getElementById('sidebarScrollView');
var outlineScrollView = document.getElementById('outlineScrollView');
var thumbsSwitchButton = document.getElementById('thumbsSwitch');
@ -208,14 +254,14 @@ var PDFView = {
}
},
getVisiblePages: function() {
getVisiblePages: function pdfViewGetVisiblePages() {
var pages = this.pages;
var kBottomMargin = 10;
var visiblePages = [];
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)
@ -225,23 +271,28 @@ 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;
}
};
var PageView = function(container, content, id, width, height,
stats, navigateTo) {
this.width = width;
this.height = height;
var PageView = function pageView(container, content, id, pageWidth, pageHeight,
stats, navigateTo) {
this.id = id;
this.content = content;
var view = this.content.view;
this.x = view.x;
this.y = view.y;
this.width = view.width;
this.height = view.height;
var anchor = document.createElement('a');
anchor.name = '' + this.id;
@ -252,7 +303,7 @@ var PageView = function(container, content, id, width, height,
container.appendChild(anchor);
container.appendChild(div);
this.update = function(scale) {
this.update = function pageViewUpdate(scale) {
this.scale = scale || this.scale;
div.style.width = (this.width * this.scale) + 'px';
div.style.height = (this.height * this.scale) + 'px';
@ -262,19 +313,21 @@ 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() {
link.href = PDFView.getDestinationHash(dest);
link.onclick = function pageViewSetupLinksOnclick() {
if (dest)
PDFView.navigateTo(dest);
return false;
}
};
}
var links = content.getLinks();
for (var i = 0; i < links.length; i++) {
var link = document.createElement('a');
link.style.left = Math.floor(links[i].x * scale) + 'px';
link.style.top = Math.floor(links[i].y * scale) + 'px';
link.style.left = (Math.floor(links[i].x - view.x) * scale) + 'px';
link.style.top = (Math.floor(links[i].y - view.y) * scale) + 'px';
link.style.width = Math.ceil(links[i].width * scale) + 'px';
link.style.height = Math.ceil(links[i].height * scale) + 'px';
link.href = links[i].url || '';
@ -284,13 +337,16 @@ var PageView = function(container, content, id, width, height,
}
}
this.scrollIntoView = function(dest) {
this.scrollIntoView = function pageViewScrollIntoView(dest) {
if (!dest) {
div.scrollIntoView(true);
return;
}
var x = 0, y = 0;
var width = 0, height = 0, widthScale, heightScale;
var scale = 0;
switch (dest[1].name) {
default:
return;
case 'XYZ':
x = dest[2];
y = dest[3];
@ -321,6 +377,8 @@ var PageView = function(container, content, id, width, height,
height / kCssUnits;
scale = Math.min(widthScale, heightScale);
break;
default:
return;
}
var boundingRect = [
@ -331,7 +389,7 @@ var PageView = function(container, content, id, width, height,
if (scale)
PDFView.setScale(scale, true);
setTimeout(function() {
setTimeout(function pageViewScrollIntoViewRelayout() {
// letting page to re-layout before scrolling
var scale = PDFView.currentScale;
var x = Math.min(boundingRect[0].x, boundingRect[1].x);
@ -352,7 +410,7 @@ var PageView = function(container, content, id, width, height,
}, 0);
};
this.draw = function() {
this.draw = function pageviewDraw() {
if (div.hasChildNodes()) {
this.updateStats();
return false;
@ -362,8 +420,9 @@ var PageView = function(container, content, id, width, height,
canvas.id = 'page' + this.id;
canvas.mozOpaque = true;
canvas.width = this.width * this.scale;
canvas.height = this.height * this.scale;
var scale = this.scale;
canvas.width = pageWidth * scale;
canvas.height = pageHeight * scale;
div.appendChild(canvas);
var ctx = canvas.getContext('2d');
@ -371,17 +430,18 @@ var PageView = function(container, content, id, width, height,
ctx.fillStyle = 'rgb(255, 255, 255)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.restore();
ctx.translate(-this.x * scale, -this.y * scale);
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;
};
this.updateStats = function() {
this.updateStats = function pageViewUpdateStats() {
var t1 = stats.compile, t2 = stats.fonts, t3 = stats.render;
var str = 'Time to compile/fonts/render: ' +
(t1 - stats.begin) + '/' + (t2 - t1) + '/' + (t3 - t2) + ' ms';
@ -389,23 +449,27 @@ var PageView = function(container, content, id, width, height,
};
};
var ThumbnailView = function(container, page, pageRatio) {
var ThumbnailView = function thumbnailView(container, page, id, pageRatio) {
var anchor = document.createElement('a');
anchor.href = '#' + page.id;
anchor.href = '#' + id;
anchor.onclick = function stopNivigation() {
PDFView.page = id;
return false;
};
var div = document.createElement('div');
div.id = 'thumbnailContainer' + page.id;
div.id = 'thumbnailContainer' + id;
div.className = 'thumbnail';
anchor.appendChild(div);
container.appendChild(anchor);
this.draw = function() {
this.draw = function thumbnailViewDraw() {
if (div.hasChildNodes())
return;
var canvas = document.createElement('canvas');
canvas.id = 'thumbnail' + page.id;
canvas.id = 'thumbnail' + id;
canvas.mozOpaque = true;
var maxThumbSize = 134;
@ -423,16 +487,24 @@ var ThumbnailView = function(container, page, pageRatio) {
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.restore();
page.content.startRendering(ctx, function() { });
var view = page.view;
var scaleX = (canvas.width / page.width);
var scaleY = (canvas.height / page.height);
ctx.translate(-view.x * scaleX, -view.y * scaleY);
div.style.width = (view.width * scaleX) + 'px';
div.style.height = (view.height * scaleY) + 'px';
div.style.lineHeight = (view.height * scaleY) + 'px';
page.startRendering(ctx, function thumbnailViewDrawStartRendering() {});
};
};
var DocumentOutlineView = function(outline) {
var DocumentOutlineView = function documentOutlineView(outline) {
var outlineView = document.getElementById('outlineView');
function bindItemLink(domObj, item) {
domObj.href = '';
domObj.onclick = function(e) {
domObj.href = PDFView.getDestinationHash(item.dest);
domObj.onclick = function documentOutlineViewOnclick(e) {
PDFView.navigateTo(item.dest);
return false;
};
@ -463,7 +535,7 @@ var DocumentOutlineView = function(outline) {
}
};
window.addEventListener('load', function(evt) {
window.addEventListener('load', function webViewerLoad(evt) {
var params = document.location.search.substring(1).split('&');
for (var i = 0; i < params.length; i++) {
var param = params[i].split('=');
@ -478,10 +550,18 @@ window.addEventListener('load', function(evt) {
document.getElementById('fileInput').value = null;
}, true);
window.addEventListener('pdfloaded', function(evt) {
window.addEventListener('pdfload', function webViewerPdfload(evt) {
PDFView.load(evt.detail);
}, true);
window.addEventListener('pdfprogress', function webViewerPdfProgress(evt) {
PDFView.progress(evt.detail);
}, true);
window.addEventListener('pdferror', function webViewerPdfError(evt) {
PDFView.error();
}, true);
function updateViewarea() {
var visiblePages = PDFView.getVisiblePages();
for (var i = 0; i < visiblePages.length; i++) {
@ -502,29 +582,29 @@ function updateViewarea() {
PDFView.page = firstPage.id;
}
window.addEventListener('scroll', function onscroll(evt) {
window.addEventListener('scroll', function webViewerScroll(evt) {
updateViewarea();
}, true);
window.addEventListener('resize', function onscroll(evt) {
window.addEventListener('resize', function webViewerResize(evt) {
if (document.getElementById('pageWidthOption').selected ||
document.getElementById('pageFitOption').selected)
PDFView.parseScale(document.getElementById('scaleSelect').value);
updateViewarea();
});
window.addEventListener('hashchange', function(evt) {
PDFView.page = PDFView.page;
window.addEventListener('hashchange', function webViewerHashchange(evt) {
PDFView.setHash(document.location.hash.substring(1));
});
window.addEventListener('change', function(evt) {
window.addEventListener('change', function webViewerChange(evt) {
var files = evt.target.files;
if (!files || files.length == 0)
return;
// Read the local file into a Uint8Array.
var fileReader = new FileReader();
fileReader.onload = function(evt) {
fileReader.onload = function webViewerChangeFileReaderOnload(evt) {
var data = evt.target.result;
var buffer = new ArrayBuffer(data.length);
var uint8Array = new Uint8Array(buffer);
@ -540,10 +620,9 @@ window.addEventListener('change', function(evt) {
fileReader.readAsBinaryString(file);
document.title = file.name;
document.location.hash = 1;
}, true);
window.addEventListener('transitionend', function(evt) {
window.addEventListener('transitionend', function webViewerTransitionend(evt) {
var pageIndex = 0;
var pagesCount = PDFView.pages.length;
@ -592,13 +671,19 @@ window.addEventListener('scalechange', function scalechange(evt) {
window.addEventListener('pagechange', function pagechange(evt) {
var page = evt.detail;
document.location.hash = page;
document.getElementById('pageNumber').value = page;
document.getElementById('previous').disabled = (page == 1);
document.getElementById('next').disabled = (page == PDFView.pages.length);
}, true);
window.addEventListener('keydown', function keydown(evt) {
var curElement = document.activeElement;
var controlsElement = document.getElementById('controls');
while (curElement) {
if (curElement === controlsElement)
return; // ignoring if the 'controls' element is focused
curElement = curElement.parentNode;
}
switch (evt.keyCode) {
case 61: // FF/Mac '='
case 107: // FF '+' and '='

View File

@ -9,16 +9,15 @@
var pdfDoc;
window.onload = function() {
window.onload = function webViewerWorkerOnload() {
window.canvas = document.getElementById("canvas");
window.ctx = canvas.getContext("2d");
pdfDoc = new WorkerPDFDoc(window.canvas);
pdfDoc.onChangePage = function(numPage) {
pdfDoc.onChangePage = function webViewerWorkerOnChangePage(numPage) {
document.getElementById("pageNumber").value = numPage;
}
// pdfDoc.open("canvas.pdf", function() {
pdfDoc.open("compressed.tracemonkey-pldi-09.pdf", function() {
pdfDoc.open("compressed.tracemonkey-pldi-09.pdf", function webViewerWorkerOpen() {
document.getElementById("numPages").innerHTML = "/" + pdfDoc.numPages;
})
}

View File

@ -28,6 +28,10 @@ var WorkerPage = (function() {
return this.page.stats;
},
get view() {
return this.page.view;
},
startRendering: function(ctx, callback, errback) {
this.ctx = ctx;
this.callback = callback;

View File

@ -33,3 +33,4 @@ var console = {
this.log('Timer:', name, Date.now() - time);
}
};