Merge with upstream
This commit is contained in:
		
						commit
						068bfa0bfe
					
				
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,3 +1,5 @@
 | 
				
			|||||||
 | 
					*~
 | 
				
			||||||
pdf.pdf
 | 
					pdf.pdf
 | 
				
			||||||
intelisa.pdf
 | 
					intelisa.pdf
 | 
				
			||||||
openweb_tm-PRINT.pdf
 | 
					openweb_tm-PRINT.pdf
 | 
				
			||||||
 | 
					local.mk
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										163
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,163 @@
 | 
				
			|||||||
 | 
					REPO = git@github.com:andreasgal/pdf.js.git
 | 
				
			||||||
 | 
					BUILD_DIR := build
 | 
				
			||||||
 | 
					DEFAULT_BROWSERS := resources/browser_manifests/browser_manifest.json
 | 
				
			||||||
 | 
					DEFAULT_TESTS := test_manifest.json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Let folks define custom rules for their clones.
 | 
				
			||||||
 | 
					-include local.mk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# JS files needed for pdf.js.
 | 
				
			||||||
 | 
					# This list doesn't account for the 'worker' directory.
 | 
				
			||||||
 | 
					PDF_JS_FILES = \
 | 
				
			||||||
 | 
						pdf.js \
 | 
				
			||||||
 | 
						crypto.js \
 | 
				
			||||||
 | 
						fonts.js \
 | 
				
			||||||
 | 
						glyphlist.js \
 | 
				
			||||||
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# not sure what to do for all yet
 | 
				
			||||||
 | 
					all: help
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# make server
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This target starts a local web server at localhost:8888. This can be
 | 
				
			||||||
 | 
					# used for testing all browsers.
 | 
				
			||||||
 | 
					server:
 | 
				
			||||||
 | 
						@cd test; python test.py --port=8888;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test: shell-test browser-test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# make browser-test
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This target runs in-browser tests using two primary arguments: a
 | 
				
			||||||
 | 
					# test manifest file, and a browser manifest file. Both are simple
 | 
				
			||||||
 | 
					# JSON formats, and examples can be found in the test/ directory. The
 | 
				
			||||||
 | 
					# target will inspect the environment for the PDF_TESTS and
 | 
				
			||||||
 | 
					# PDF_BROWSERS variables, and use those if found. Otherwise, the
 | 
				
			||||||
 | 
					# defaults at the top of this file are used.
 | 
				
			||||||
 | 
					ifeq ($(PDF_TESTS),)
 | 
				
			||||||
 | 
					PDF_TESTS := $(DEFAULT_TESTS)
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					ifeq ($(PDF_BROWSERS),)
 | 
				
			||||||
 | 
					PDF_BROWSERS := $(DEFAULT_BROWSERS)
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					browser-test:
 | 
				
			||||||
 | 
						@if [ ! -f "test/$(PDF_BROWSERS)" ]; then \
 | 
				
			||||||
 | 
						echo "Browser manifest file $(PDF_BROWSERS) does not exist."; \
 | 
				
			||||||
 | 
						echo "Try copying one of the examples" \
 | 
				
			||||||
 | 
					              "in test/resources/browser_manifests/"; \
 | 
				
			||||||
 | 
						exit 1; \
 | 
				
			||||||
 | 
						fi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cd test; \
 | 
				
			||||||
 | 
						python test.py --reftest \
 | 
				
			||||||
 | 
						--browserManifestFile=$(PDF_BROWSERS) \
 | 
				
			||||||
 | 
						--manifestFile=$(PDF_TESTS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# make shell-test
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This target runs all of the tests that can be run in a JS shell.
 | 
				
			||||||
 | 
					# The shell used is taken from the JS_SHELL environment variable. If
 | 
				
			||||||
 | 
					# that variable is not defined, the script will attempt to use the copy
 | 
				
			||||||
 | 
					# of Rhino that comes with the Closure compiler used for producing the
 | 
				
			||||||
 | 
					# website.
 | 
				
			||||||
 | 
					SHELL_TARGET = $(NULL)
 | 
				
			||||||
 | 
					ifeq ($(JS_SHELL),)
 | 
				
			||||||
 | 
					JS_SHELL := "java -cp $(BUILD_DIR)/compiler.jar"
 | 
				
			||||||
 | 
					JS_SHELL += "com.google.javascript.jscomp.mozilla.rhino.tools.shell.Main"
 | 
				
			||||||
 | 
					SHELL_TARGET = compiler
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					shell-test: shell-msg $(SHELL_TARGET) font-test
 | 
				
			||||||
 | 
					shell-msg:
 | 
				
			||||||
 | 
					ifeq ($(SHELL_TARGET), compiler)
 | 
				
			||||||
 | 
						@echo "No JS_SHELL env variable present."
 | 
				
			||||||
 | 
						@echo "The default is to find a copy of Rhino and try that."
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
						@echo "JS shell command is: $(JS_SHELL)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					font-test:
 | 
				
			||||||
 | 
						@echo "font test stub."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# make lint
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This target runs the Closure Linter on most of our JS files.
 | 
				
			||||||
 | 
					# To install gjslint, see:
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# <http://code.google.com/closure/utilities/docs/linter_howto.html>
 | 
				
			||||||
 | 
					SRC_DIRS := . utils worker web
 | 
				
			||||||
 | 
					GJSLINT_FILES = $(foreach DIR,$(SRC_DIRS),$(wildcard $(DIR)/*.js))
 | 
				
			||||||
 | 
					lint:
 | 
				
			||||||
 | 
						gjslint $(GJSLINT_FILES)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# make web
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This target produces the website for the project, by checking out
 | 
				
			||||||
 | 
					# the gh-pages branch underneath the build directory, and then move
 | 
				
			||||||
 | 
					# the various viewer files into place.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# TODO: Use the Closure compiler to optimize the pdf.js files.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					GH_PAGES = $(BUILD_DIR)/gh-pages
 | 
				
			||||||
 | 
					web: | compiler pages-repo \
 | 
				
			||||||
 | 
						$(addprefix $(GH_PAGES)/, $(PDF_JS_FILES)) \
 | 
				
			||||||
 | 
						$(addprefix $(GH_PAGES)/, $(wildcard web/*.*)) \
 | 
				
			||||||
 | 
						$(addprefix $(GH_PAGES)/, $(wildcard web/images/*.*))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@cp $(GH_PAGES)/web/index.html.template $(GH_PAGES)/index.html;
 | 
				
			||||||
 | 
						@cd $(GH_PAGES); git add -A;
 | 
				
			||||||
 | 
						@echo "Website built in $(GH_PAGES)."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# make pages-repo
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This target clones the gh-pages repo into the build directory. It
 | 
				
			||||||
 | 
					# deletes the current contents of the repo, since we overwrite
 | 
				
			||||||
 | 
					# everything with data from the master repo. The 'make web' target
 | 
				
			||||||
 | 
					# then uses 'git add -A' to track additions, modifications, moves,
 | 
				
			||||||
 | 
					# and deletions.
 | 
				
			||||||
 | 
					pages-repo: | $(BUILD_DIR)
 | 
				
			||||||
 | 
						@if [ ! -d "$(GH_PAGES)" ]; then \
 | 
				
			||||||
 | 
						git clone -b gh-pages $(REPO) $(GH_PAGES); \
 | 
				
			||||||
 | 
						rm -rf $(GH_PAGES)/*; \
 | 
				
			||||||
 | 
						fi;
 | 
				
			||||||
 | 
						@mkdir -p $(GH_PAGES)/web;
 | 
				
			||||||
 | 
						@mkdir -p $(GH_PAGES)/web/images;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(GH_PAGES)/%.js: %.js
 | 
				
			||||||
 | 
						@cp $< $@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(GH_PAGES)/web/%: web/%
 | 
				
			||||||
 | 
						@cp $< $@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(GH_PAGES)/web/images/%: web/images/%
 | 
				
			||||||
 | 
						@cp $< $@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# make compiler
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This target downloads the Closure compiler, and places it in the
 | 
				
			||||||
 | 
					# build directory. This target is also useful when the user doesn't
 | 
				
			||||||
 | 
					# have a JS shell available--we can have them use the Rhino shell that
 | 
				
			||||||
 | 
					# comes with Closure.
 | 
				
			||||||
 | 
					COMPILER_URL = http://closure-compiler.googlecode.com/files/compiler-latest.zip
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					compiler: $(BUILD_DIR)/compiler.zip
 | 
				
			||||||
 | 
					$(BUILD_DIR)/compiler.zip: | $(BUILD_DIR)
 | 
				
			||||||
 | 
						curl $(COMPILER_URL) > $(BUILD_DIR)/compiler.zip;
 | 
				
			||||||
 | 
						cd $(BUILD_DIR); unzip compiler.zip compiler.jar;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Make sure there's a build directory.
 | 
				
			||||||
 | 
					$(BUILD_DIR):
 | 
				
			||||||
 | 
						mkdir -p $(BUILD_DIR)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					clean:
 | 
				
			||||||
 | 
						rm -rf $(BUILD_DIR)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# make help
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This target just prints out a message to read these comments. :)
 | 
				
			||||||
 | 
					help:
 | 
				
			||||||
 | 
						@echo "Read the comments in the Makefile for guidance.";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.PHONY:: all test browser-test font-test shell-test \
 | 
				
			||||||
 | 
						shell-msg lint clean web compiler help server
 | 
				
			||||||
							
								
								
									
										84
									
								
								crypto.js
									
									
									
									
									
								
							
							
						
						
									
										84
									
								
								crypto.js
									
									
									
									
									
								
							@ -1,7 +1,7 @@
 | 
				
			|||||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 | 
					/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 | 
				
			||||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
					/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"use strict";
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var ARCFourCipher = (function() {
 | 
					var ARCFourCipher = (function() {
 | 
				
			||||||
  function constructor(key) {
 | 
					  function constructor(key) {
 | 
				
			||||||
@ -30,7 +30,7 @@ var ARCFourCipher = (function() {
 | 
				
			|||||||
        a = (a + 1) & 0xFF;
 | 
					        a = (a + 1) & 0xFF;
 | 
				
			||||||
        tmp = s[a];
 | 
					        tmp = s[a];
 | 
				
			||||||
        b = (b + tmp) & 0xFF;
 | 
					        b = (b + tmp) & 0xFF;
 | 
				
			||||||
        tmp2 = s[b]
 | 
					        tmp2 = s[b];
 | 
				
			||||||
        s[a] = tmp2;
 | 
					        s[a] = tmp2;
 | 
				
			||||||
        s[b] = tmp;
 | 
					        s[b] = tmp;
 | 
				
			||||||
        output[i] = data[i] ^ s[(tmp + tmp2) & 0xFF];
 | 
					        output[i] = data[i] ^ s[(tmp + tmp2) & 0xFF];
 | 
				
			||||||
@ -47,21 +47,22 @@ var ARCFourCipher = (function() {
 | 
				
			|||||||
var md5 = (function() {
 | 
					var md5 = (function() {
 | 
				
			||||||
  var r = new Uint8Array([
 | 
					  var r = new Uint8Array([
 | 
				
			||||||
    7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
 | 
					    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,
 | 
					    5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
 | 
				
			||||||
    4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
 | 
					    4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
 | 
				
			||||||
    6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]);
 | 
					    6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  var k = new Int32Array([
 | 
					  var k = new Int32Array([
 | 
				
			||||||
    -680876936, -389564586, 606105819, -1044525330, -176418897, 1200080426,
 | 
					    -680876936, -389564586, 606105819, -1044525330, -176418897, 1200080426,
 | 
				
			||||||
    -1473231341, -45705983, 1770035416, -1958414417, -42063, -1990404162,
 | 
					    -1473231341, -45705983, 1770035416, -1958414417, -42063, -1990404162,
 | 
				
			||||||
    1804603682, -40341101, -1502002290, 1236535329, -165796510, -1069501632,
 | 
					    1804603682, -40341101, -1502002290, 1236535329, -165796510, -1069501632,
 | 
				
			||||||
    643717713, -373897302, -701558691, 38016083, -660478335, -405537848, 568446438,
 | 
					    643717713, -373897302, -701558691, 38016083, -660478335, -405537848,
 | 
				
			||||||
    -1019803690, -187363961, 1163531501, -1444681467, -51403784, 1735328473,
 | 
					    568446438, -1019803690, -187363961, 1163531501, -1444681467, -51403784,
 | 
				
			||||||
    -1926607734, -378558, -2022574463, 1839030562, -35309556, -1530992060,
 | 
					    1735328473, -1926607734, -378558, -2022574463, 1839030562, -35309556,
 | 
				
			||||||
    1272893353, -155497632, -1094730640, 681279174, -358537222, -722521979,
 | 
					    -1530992060, 1272893353, -155497632, -1094730640, 681279174, -358537222,
 | 
				
			||||||
    76029189, -640364487, -421815835, 530742520, -995338651, -198630844, 1126891415,
 | 
					    -722521979, 76029189, -640364487, -421815835, 530742520, -995338651,
 | 
				
			||||||
    -1416354905, -57434055, 1700485571, -1894986606, -1051523, -2054922799,
 | 
					    -198630844, 1126891415, -1416354905, -57434055, 1700485571, -1894986606,
 | 
				
			||||||
    1873313359, -30611744, -1560198380, 1309151649, -145523070, -1120210379,
 | 
					    -1051523, -2054922799, 1873313359, -30611744, -1560198380, 1309151649,
 | 
				
			||||||
    718787259, -343485551]);
 | 
					    -145523070, -1120210379, 718787259, -343485551]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function hash(data, offset, length) {
 | 
					  function hash(data, offset, length) {
 | 
				
			||||||
    var h0 = 1732584193, h1 = -271733879, h2 = -1732584194, h3 = 271733878;
 | 
					    var h0 = 1732584193, h1 = -271733879, h2 = -1732584194, h3 = 271733878;
 | 
				
			||||||
@ -76,10 +77,10 @@ var md5 = (function() {
 | 
				
			|||||||
    for (; i < n; ++i)
 | 
					    for (; i < n; ++i)
 | 
				
			||||||
      padded[i] = 0;
 | 
					      padded[i] = 0;
 | 
				
			||||||
    padded[i++] = (length << 3) & 0xFF;
 | 
					    padded[i++] = (length << 3) & 0xFF;
 | 
				
			||||||
    padded[i++] = (length >> 5)  & 0xFF;
 | 
					    padded[i++] = (length >> 5) & 0xFF;
 | 
				
			||||||
    padded[i++] = (length >> 13)  & 0xFF;
 | 
					    padded[i++] = (length >> 13) & 0xFF;
 | 
				
			||||||
    padded[i++] = (length >> 21)  & 0xFF;
 | 
					    padded[i++] = (length >> 21) & 0xFF;
 | 
				
			||||||
    padded[i++] = (length >>> 29)  & 0xFF;
 | 
					    padded[i++] = (length >>> 29) & 0xFF;
 | 
				
			||||||
    padded[i++] = 0;
 | 
					    padded[i++] = 0;
 | 
				
			||||||
    padded[i++] = 0;
 | 
					    padded[i++] = 0;
 | 
				
			||||||
    padded[i++] = 0;
 | 
					    padded[i++] = 0;
 | 
				
			||||||
@ -87,8 +88,10 @@ var md5 = (function() {
 | 
				
			|||||||
    // TODO ArrayBuffer ?
 | 
					    // TODO ArrayBuffer ?
 | 
				
			||||||
    var w = new Int32Array(16);
 | 
					    var w = new Int32Array(16);
 | 
				
			||||||
    for (i = 0; i < paddedLength;) {
 | 
					    for (i = 0; i < paddedLength;) {
 | 
				
			||||||
      for (j = 0; j < 16; ++j, i += 4)
 | 
					      for (j = 0; j < 16; ++j, i += 4) {
 | 
				
			||||||
        w[j] = padded[i] | (padded[i + 1] << 8) | (padded[i + 2] << 16) | (padded[i + 3] << 24);
 | 
					        w[j] = (padded[i] | (padded[i + 1] << 8) |
 | 
				
			||||||
 | 
					                (padded[i + 2] << 16) | (padded[i + 3] << 24));
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      var a = h0, b = h1, c = h2, d = h3, f, g;
 | 
					      var a = h0, b = h1, c = h2, d = h3, f, g;
 | 
				
			||||||
      for (j = 0; j < 64; ++j) {
 | 
					      for (j = 0; j < 64; ++j) {
 | 
				
			||||||
        if (j < 16) {
 | 
					        if (j < 16) {
 | 
				
			||||||
@ -131,7 +134,7 @@ var CipherTransform = (function() {
 | 
				
			|||||||
    this.streamCipherConstructor = streamCipherConstructor;
 | 
					    this.streamCipherConstructor = streamCipherConstructor;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  constructor.prototype = {
 | 
					  constructor.prototype = {
 | 
				
			||||||
    createStream: function (stream) {
 | 
					    createStream: function(stream) {
 | 
				
			||||||
      var cipher = new this.streamCipherConstructor();
 | 
					      var cipher = new this.streamCipherConstructor();
 | 
				
			||||||
      return new DecryptStream(stream, function(data) {
 | 
					      return new DecryptStream(stream, function(data) {
 | 
				
			||||||
        return cipher.encryptBlock(data);
 | 
					        return cipher.encryptBlock(data);
 | 
				
			||||||
@ -139,19 +142,22 @@ var CipherTransform = (function() {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    decryptString: function(s) {
 | 
					    decryptString: function(s) {
 | 
				
			||||||
      var cipher = new this.stringCipherConstructor();
 | 
					      var cipher = new this.stringCipherConstructor();
 | 
				
			||||||
      var data = string2bytes(s);
 | 
					      var data = stringToBytes(s);
 | 
				
			||||||
      data = cipher.encryptBlock(data);
 | 
					      data = cipher.encryptBlock(data);
 | 
				
			||||||
      return bytes2string(data);
 | 
					      return bytesToString(data);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  return constructor;
 | 
					  return constructor;
 | 
				
			||||||
})();
 | 
					})();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var CipherTransformFactory = (function() {
 | 
					var CipherTransformFactory = (function() {
 | 
				
			||||||
  function prepareKeyData(fileId, password, ownerPassword, userPassword, flags, revision, keyLength) {
 | 
					  function prepareKeyData(fileId, password, ownerPassword, userPassword,
 | 
				
			||||||
 | 
					                          flags, revision, keyLength) {
 | 
				
			||||||
    var defaultPasswordBytes = new Uint8Array([
 | 
					    var defaultPasswordBytes = new Uint8Array([
 | 
				
			||||||
      0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, 
 | 
					      0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41,
 | 
				
			||||||
      0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A]);
 | 
					      0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
 | 
				
			||||||
 | 
					      0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80,
 | 
				
			||||||
 | 
					      0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A]);
 | 
				
			||||||
    var hashData = new Uint8Array(88), i = 0, j, n;
 | 
					    var hashData = new Uint8Array(88), i = 0, j, n;
 | 
				
			||||||
    if (password) {
 | 
					    if (password) {
 | 
				
			||||||
      n = Math.min(32, password.length);
 | 
					      n = Math.min(32, password.length);
 | 
				
			||||||
@ -183,9 +189,10 @@ var CipherTransformFactory = (function() {
 | 
				
			|||||||
    var cipher, checkData;
 | 
					    var cipher, checkData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (revision >= 3) {
 | 
					    if (revision >= 3) {
 | 
				
			||||||
      // padded password in hashData, we can use this array for user password check
 | 
					      // padded password in hashData, we can use this array for user
 | 
				
			||||||
 | 
					      // password check
 | 
				
			||||||
      i = 32;
 | 
					      i = 32;
 | 
				
			||||||
      for(j = 0, n = fileId.length; j < n; ++j)
 | 
					      for (j = 0, n = fileId.length; j < n; ++j)
 | 
				
			||||||
        hashData[i++] = fileId[j];
 | 
					        hashData[i++] = fileId[j];
 | 
				
			||||||
      cipher = new ARCFourCipher(encryptionKey);
 | 
					      cipher = new ARCFourCipher(encryptionKey);
 | 
				
			||||||
      var checkData = cipher.encryptBlock(md5(hashData, 0, i));
 | 
					      var checkData = cipher.encryptBlock(md5(hashData, 0, i));
 | 
				
			||||||
@ -203,37 +210,38 @@ var CipherTransformFactory = (function() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    for (j = 0, n = checkData.length; j < n; ++j) {
 | 
					    for (j = 0, n = checkData.length; j < n; ++j) {
 | 
				
			||||||
      if (userPassword[j] != checkData[j])
 | 
					      if (userPassword[j] != checkData[j])
 | 
				
			||||||
        error("incorrect password");
 | 
					        error('incorrect password');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return encryptionKey;
 | 
					    return encryptionKey;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function constructor(dict, fileId, password) {
 | 
					  function constructor(dict, fileId, password) {
 | 
				
			||||||
    var filter = dict.get("Filter");
 | 
					    var filter = dict.get('Filter');
 | 
				
			||||||
    if (!IsName(filter) || filter.name != "Standard")
 | 
					    if (!IsName(filter) || filter.name != 'Standard')
 | 
				
			||||||
      error("unknown encryption method");
 | 
					      error('unknown encryption method');
 | 
				
			||||||
    this.dict = dict;
 | 
					    this.dict = dict;
 | 
				
			||||||
    var algorithm = dict.get("V");
 | 
					    var algorithm = dict.get('V');
 | 
				
			||||||
    if (!IsInt(algorithm) ||
 | 
					    if (!IsInt(algorithm) ||
 | 
				
			||||||
      (algorithm != 1 && algorithm != 2))
 | 
					      (algorithm != 1 && algorithm != 2))
 | 
				
			||||||
      error("unsupported encryption algorithm");
 | 
					      error('unsupported encryption algorithm');
 | 
				
			||||||
    // TODO support algorithm 4
 | 
					    // TODO support algorithm 4
 | 
				
			||||||
    var keyLength = dict.get("Length") || 40;
 | 
					    var keyLength = dict.get('Length') || 40;
 | 
				
			||||||
    if (!IsInt(keyLength) ||
 | 
					    if (!IsInt(keyLength) ||
 | 
				
			||||||
      keyLength < 40 || (keyLength % 8) != 0)
 | 
					      keyLength < 40 || (keyLength % 8) != 0)
 | 
				
			||||||
      error("invalid key length");
 | 
					      error('invalid key length');
 | 
				
			||||||
    // prepare keys
 | 
					    // prepare keys
 | 
				
			||||||
    var ownerPassword = stringToBytes(dict.get("O"));
 | 
					    var ownerPassword = stringToBytes(dict.get('O'));
 | 
				
			||||||
    var userPassword = stringToBytes(dict.get("U"));
 | 
					    var userPassword = stringToBytes(dict.get('U'));
 | 
				
			||||||
    var flags = dict.get("P");
 | 
					    var flags = dict.get('P');
 | 
				
			||||||
    var revision = dict.get("R");
 | 
					    var revision = dict.get('R');
 | 
				
			||||||
    var fileIdBytes = stringToBytes(fileId);
 | 
					    var fileIdBytes = stringToBytes(fileId);
 | 
				
			||||||
    var passwordBytes;
 | 
					    var passwordBytes;
 | 
				
			||||||
    if (password)
 | 
					    if (password)
 | 
				
			||||||
      passwordBytes = stringToBytes(password);
 | 
					      passwordBytes = stringToBytes(password);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.encryptionKey = prepareKeyData(fileIdBytes, passwordBytes,
 | 
					    this.encryptionKey = prepareKeyData(fileIdBytes, passwordBytes,
 | 
				
			||||||
                                        ownerPassword, userPassword, flags, revision, keyLength);
 | 
					                                        ownerPassword, userPassword,
 | 
				
			||||||
 | 
					                                        flags, revision, keyLength);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constructor.prototype = {
 | 
					  constructor.prototype = {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										12
									
								
								glyphlist.js
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								glyphlist.js
									
									
									
									
									
								
							@ -1,7 +1,7 @@
 | 
				
			|||||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 | 
					/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 | 
				
			||||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
					/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"use strict";
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var GlyphsUnicode = {
 | 
					var GlyphsUnicode = {
 | 
				
			||||||
  A: 0x0041,
 | 
					  A: 0x0041,
 | 
				
			||||||
@ -2474,8 +2474,8 @@ var GlyphsUnicode = {
 | 
				
			|||||||
  lameddageshhebrew: 0xFB3C,
 | 
					  lameddageshhebrew: 0xFB3C,
 | 
				
			||||||
  lamedhebrew: 0x05DC,
 | 
					  lamedhebrew: 0x05DC,
 | 
				
			||||||
  lamedholam: 0x05DC05B9,
 | 
					  lamedholam: 0x05DC05B9,
 | 
				
			||||||
  lamedholamdagesh: "05DC 05B9 05BC",
 | 
					  lamedholamdagesh: '05DC 05B9 05BC',
 | 
				
			||||||
  lamedholamdageshhebrew: "05DC 05B9 05BC",
 | 
					  lamedholamdageshhebrew: '05DC 05B9 05BC',
 | 
				
			||||||
  lamedholamhebrew: 0x05DC05B9,
 | 
					  lamedholamhebrew: 0x05DC05B9,
 | 
				
			||||||
  lamfinalarabic: 0xFEDE,
 | 
					  lamfinalarabic: 0xFEDE,
 | 
				
			||||||
  lamhahinitialarabic: 0xFCCA,
 | 
					  lamhahinitialarabic: 0xFCCA,
 | 
				
			||||||
@ -2486,8 +2486,8 @@ var GlyphsUnicode = {
 | 
				
			|||||||
  lammedialarabic: 0xFEE0,
 | 
					  lammedialarabic: 0xFEE0,
 | 
				
			||||||
  lammeemhahinitialarabic: 0xFD88,
 | 
					  lammeemhahinitialarabic: 0xFD88,
 | 
				
			||||||
  lammeeminitialarabic: 0xFCCC,
 | 
					  lammeeminitialarabic: 0xFCCC,
 | 
				
			||||||
  lammeemjeeminitialarabic: "FEDF FEE4 FEA0",
 | 
					  lammeemjeeminitialarabic: 'FEDF FEE4 FEA0',
 | 
				
			||||||
  lammeemkhahinitialarabic: "FEDF FEE4 FEA8",
 | 
					  lammeemkhahinitialarabic: 'FEDF FEE4 FEA8',
 | 
				
			||||||
  largecircle: 0x25EF,
 | 
					  largecircle: 0x25EF,
 | 
				
			||||||
  lbar: 0x019A,
 | 
					  lbar: 0x019A,
 | 
				
			||||||
  lbelt: 0x026C,
 | 
					  lbelt: 0x026C,
 | 
				
			||||||
@ -3250,7 +3250,7 @@ var GlyphsUnicode = {
 | 
				
			|||||||
  reharmenian: 0x0580,
 | 
					  reharmenian: 0x0580,
 | 
				
			||||||
  rehfinalarabic: 0xFEAE,
 | 
					  rehfinalarabic: 0xFEAE,
 | 
				
			||||||
  rehiragana: 0x308C,
 | 
					  rehiragana: 0x308C,
 | 
				
			||||||
  rehyehaleflamarabic: "0631 FEF3 FE8E 0644",
 | 
					  rehyehaleflamarabic: '0631 FEF3 FE8E 0644',
 | 
				
			||||||
  rekatakana: 0x30EC,
 | 
					  rekatakana: 0x30EC,
 | 
				
			||||||
  rekatakanahalfwidth: 0xFF9A,
 | 
					  rekatakanahalfwidth: 0xFF9A,
 | 
				
			||||||
  resh: 0x05E8,
 | 
					  resh: 0x05E8,
 | 
				
			||||||
 | 
				
			|||||||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 3.8 KiB  | 
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							@ -1,230 +0,0 @@
 | 
				
			|||||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 | 
					 | 
				
			||||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
body {
 | 
					 | 
				
			||||||
  background-color: #929292;
 | 
					 | 
				
			||||||
  font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;
 | 
					 | 
				
			||||||
  margin: 0px;
 | 
					 | 
				
			||||||
  padding: 0px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
canvas {
 | 
					 | 
				
			||||||
  box-shadow: 0px 4px 10px #000;
 | 
					 | 
				
			||||||
  -moz-box-shadow: 0px 4px 10px #000;
 | 
					 | 
				
			||||||
  -webkit-box-shadow: 0px 4px 10px #000;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
span {
 | 
					 | 
				
			||||||
  font-size: 0.8em;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.control {
 | 
					 | 
				
			||||||
  display: inline-block;
 | 
					 | 
				
			||||||
  float: left;
 | 
					 | 
				
			||||||
  margin: 0px 20px 0px 0px;
 | 
					 | 
				
			||||||
  padding: 0px 4px 0px 0px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.control > input {
 | 
					 | 
				
			||||||
  float: left;
 | 
					 | 
				
			||||||
  border: 1px solid #4d4d4d;
 | 
					 | 
				
			||||||
  height: 20px;
 | 
					 | 
				
			||||||
  padding: 0px;
 | 
					 | 
				
			||||||
  margin: 0px 2px 0px 0px;
 | 
					 | 
				
			||||||
  border-radius: 4px;
 | 
					 | 
				
			||||||
  -moz-border-radius: 4px;
 | 
					 | 
				
			||||||
  -webkit-border-radius: 4px;
 | 
					 | 
				
			||||||
  box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
 | 
					 | 
				
			||||||
  -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
 | 
					 | 
				
			||||||
  -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.control > select {
 | 
					 | 
				
			||||||
  float: left;
 | 
					 | 
				
			||||||
  border: 1px solid #4d4d4d;
 | 
					 | 
				
			||||||
  height: 22px;
 | 
					 | 
				
			||||||
  padding: 2px 0px 0px;
 | 
					 | 
				
			||||||
  margin: 0px 0px 1px;
 | 
					 | 
				
			||||||
  border-radius: 4px;
 | 
					 | 
				
			||||||
  -moz-border-radius: 4px;
 | 
					 | 
				
			||||||
  -webkit-border-radius: 4px;
 | 
					 | 
				
			||||||
  box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
 | 
					 | 
				
			||||||
  -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
 | 
					 | 
				
			||||||
  -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.control > span {
 | 
					 | 
				
			||||||
  cursor: default;
 | 
					 | 
				
			||||||
  float: left;
 | 
					 | 
				
			||||||
  height: 18px;
 | 
					 | 
				
			||||||
  margin: 5px 2px 0px;
 | 
					 | 
				
			||||||
  padding: 0px;
 | 
					 | 
				
			||||||
  user-select: none;
 | 
					 | 
				
			||||||
  -moz-user-select: none;
 | 
					 | 
				
			||||||
  -webkit-user-select: none;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.control .label {
 | 
					 | 
				
			||||||
  clear: both;
 | 
					 | 
				
			||||||
  float: left;
 | 
					 | 
				
			||||||
  font-size: 0.65em;
 | 
					 | 
				
			||||||
  margin: 2px 0px 0px;
 | 
					 | 
				
			||||||
  position: relative;
 | 
					 | 
				
			||||||
  text-align: center;
 | 
					 | 
				
			||||||
  width: 100%;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.thumbnailPageNumber {
 | 
					 | 
				
			||||||
  color: #fff;
 | 
					 | 
				
			||||||
  font-size: 0.55em;
 | 
					 | 
				
			||||||
  text-align: right;
 | 
					 | 
				
			||||||
  margin: -6px 2px 6px 0px;
 | 
					 | 
				
			||||||
  width: 102px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.thumbnail {
 | 
					 | 
				
			||||||
  width: 104px;
 | 
					 | 
				
			||||||
  height: 134px;
 | 
					 | 
				
			||||||
  margin: 0px auto 10px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.page {
 | 
					 | 
				
			||||||
  width: 816px;
 | 
					 | 
				
			||||||
  height: 1056px;
 | 
					 | 
				
			||||||
  margin: 10px auto;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#controls {
 | 
					 | 
				
			||||||
  background-color: #eee;
 | 
					 | 
				
			||||||
  border-bottom: 1px solid #666;
 | 
					 | 
				
			||||||
  padding: 4px 0px 0px 8px;
 | 
					 | 
				
			||||||
  position: fixed;
 | 
					 | 
				
			||||||
  left: 0px;
 | 
					 | 
				
			||||||
  top: 0px;
 | 
					 | 
				
			||||||
  height: 40px;
 | 
					 | 
				
			||||||
  width: 100%;
 | 
					 | 
				
			||||||
  box-shadow: 0px 2px 8px #000;
 | 
					 | 
				
			||||||
  -moz-box-shadow: 0px 2px 8px #000;
 | 
					 | 
				
			||||||
  -webkit-box-shadow: 0px 2px 8px #000;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#controls input {
 | 
					 | 
				
			||||||
  user-select: text;
 | 
					 | 
				
			||||||
  -moz-user-select: text;
 | 
					 | 
				
			||||||
  -webkit-user-select: text;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#previousPageButton {
 | 
					 | 
				
			||||||
  background: url('images/buttons.png') no-repeat 0px -23px;
 | 
					 | 
				
			||||||
  cursor: default;
 | 
					 | 
				
			||||||
  display: inline-block;
 | 
					 | 
				
			||||||
  float: left;
 | 
					 | 
				
			||||||
  margin: 0px;
 | 
					 | 
				
			||||||
  width: 28px;
 | 
					 | 
				
			||||||
  height: 23px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#previousPageButton.down {
 | 
					 | 
				
			||||||
  background: url('images/buttons.png') no-repeat 0px -46px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#previousPageButton.disabled {
 | 
					 | 
				
			||||||
  background: url('images/buttons.png') no-repeat 0px 0px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#nextPageButton {
 | 
					 | 
				
			||||||
  background: url('images/buttons.png') no-repeat -28px -23px;
 | 
					 | 
				
			||||||
  cursor: default;
 | 
					 | 
				
			||||||
  display: inline-block;
 | 
					 | 
				
			||||||
  float: left;
 | 
					 | 
				
			||||||
  margin: 0px;
 | 
					 | 
				
			||||||
  width: 28px;
 | 
					 | 
				
			||||||
  height: 23px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#nextPageButton.down {
 | 
					 | 
				
			||||||
  background: url('images/buttons.png') no-repeat -28px -46px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#nextPageButton.disabled {
 | 
					 | 
				
			||||||
  background: url('images/buttons.png') no-repeat -28px 0px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#openFileButton {
 | 
					 | 
				
			||||||
  background: url('images/buttons.png') no-repeat -56px -23px;
 | 
					 | 
				
			||||||
  cursor: default;
 | 
					 | 
				
			||||||
  display: inline-block;
 | 
					 | 
				
			||||||
  float: left;
 | 
					 | 
				
			||||||
  margin: 0px 0px 0px 3px;
 | 
					 | 
				
			||||||
  width: 29px;
 | 
					 | 
				
			||||||
  height: 23px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#openFileButton.down {
 | 
					 | 
				
			||||||
  background: url('images/buttons.png') no-repeat -56px -46px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#openFileButton.disabled {
 | 
					 | 
				
			||||||
  background: url('images/buttons.png') no-repeat -56px 0px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#fileInput {
 | 
					 | 
				
			||||||
  display: none;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pageNumber {
 | 
					 | 
				
			||||||
  text-align: right;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#sidebar {
 | 
					 | 
				
			||||||
  position: fixed;
 | 
					 | 
				
			||||||
  width: 200px;
 | 
					 | 
				
			||||||
  top: 62px;
 | 
					 | 
				
			||||||
  bottom: 18px;
 | 
					 | 
				
			||||||
  left: -140px;
 | 
					 | 
				
			||||||
  transition: left 0.25s ease-in-out 1s;
 | 
					 | 
				
			||||||
  -moz-transition: left 0.25s ease-in-out 1s;
 | 
					 | 
				
			||||||
  -webkit-transition: left 0.25s ease-in-out 1s;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#sidebar:hover {
 | 
					 | 
				
			||||||
  left: 0px;
 | 
					 | 
				
			||||||
  transition: left 0.25s ease-in-out 0s;
 | 
					 | 
				
			||||||
  -moz-transition: left 0.25s ease-in-out 0s;
 | 
					 | 
				
			||||||
  -webkit-transition: left 0.25s ease-in-out 0s;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#sidebarBox {
 | 
					 | 
				
			||||||
  background-color: rgba(0, 0, 0, 0.7);
 | 
					 | 
				
			||||||
  width: 150px;
 | 
					 | 
				
			||||||
  height: 100%;
 | 
					 | 
				
			||||||
  border-top-right-radius: 8px;
 | 
					 | 
				
			||||||
  border-bottom-right-radius: 8px;
 | 
					 | 
				
			||||||
  -moz-border-radius-topright: 8px;
 | 
					 | 
				
			||||||
  -moz-border-radius-bottomright: 8px;
 | 
					 | 
				
			||||||
  -webkit-border-top-right-radius: 8px;
 | 
					 | 
				
			||||||
  -webkit-border-bottom-right-radius: 8px;
 | 
					 | 
				
			||||||
  box-shadow: 0px 2px 8px #000;
 | 
					 | 
				
			||||||
  -moz-box-shadow: 0px 2px 8px #000;
 | 
					 | 
				
			||||||
  -webkit-box-shadow: 0px 2px 8px #000;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#sidebarScrollView {
 | 
					 | 
				
			||||||
  position: absolute;
 | 
					 | 
				
			||||||
  overflow: hidden;
 | 
					 | 
				
			||||||
  overflow-y: auto;
 | 
					 | 
				
			||||||
  top: 10px;
 | 
					 | 
				
			||||||
  bottom: 10px;
 | 
					 | 
				
			||||||
  left: 10px;
 | 
					 | 
				
			||||||
  width: 130px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#sidebarContentView {
 | 
					 | 
				
			||||||
  height: auto;
 | 
					 | 
				
			||||||
  width: 100px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#viewer {
 | 
					 | 
				
			||||||
  margin: 44px 0px 0px;
 | 
					 | 
				
			||||||
  padding: 8px 0px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										209
									
								
								test/driver.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										209
									
								
								test/driver.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,209 @@
 | 
				
			|||||||
 | 
					/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 | 
				
			||||||
 | 
					/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * A Test Driver for PDF.js
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var appPath, browser, canvas, currentTaskIdx, manifest, stdout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function queryParams() {
 | 
				
			||||||
 | 
					    var qs = window.location.search.substring(1);
 | 
				
			||||||
 | 
					    var kvs = qs.split("&");
 | 
				
			||||||
 | 
					    var params = { };
 | 
				
			||||||
 | 
					    for (var i = 0; i < kvs.length; ++i) {
 | 
				
			||||||
 | 
					        var kv = kvs[i].split("=");
 | 
				
			||||||
 | 
					        params[unescape(kv[0])] = unescape(kv[1]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return params;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function load() {
 | 
				
			||||||
 | 
					    var params = queryParams();
 | 
				
			||||||
 | 
					    browser = params.browser;
 | 
				
			||||||
 | 
					    manifestFile = params.manifestFile;
 | 
				
			||||||
 | 
					    appPath = params.path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    canvas = document.createElement("canvas");
 | 
				
			||||||
 | 
					    canvas.mozOpaque = true;
 | 
				
			||||||
 | 
					    stdout = document.getElementById("stdout");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    log("load...\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    log("Harness thinks this browser is '"+ browser + "' with path " + appPath + "\n");
 | 
				
			||||||
 | 
					    log("Fetching manifest "+ manifestFile +"...");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var r = new XMLHttpRequest();
 | 
				
			||||||
 | 
					    r.open("GET", manifestFile, false);
 | 
				
			||||||
 | 
					    r.onreadystatechange = function(e) {
 | 
				
			||||||
 | 
					        if (r.readyState == 4) {
 | 
				
			||||||
 | 
					            log("done\n");
 | 
				
			||||||
 | 
					            manifest = JSON.parse(r.responseText);
 | 
				
			||||||
 | 
					            currentTaskIdx = 0, nextTask();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    r.send(null);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					window.onload = load;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function nextTask() {
 | 
				
			||||||
 | 
					    if (currentTaskIdx == manifest.length) {
 | 
				
			||||||
 | 
					        return done();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    var task = manifest[currentTaskIdx];
 | 
				
			||||||
 | 
					    task.round = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    log("Loading file "+ task.file +"\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var r = new XMLHttpRequest();
 | 
				
			||||||
 | 
					    r.open("GET", task.file);
 | 
				
			||||||
 | 
					    r.mozResponseType = r.responseType = "arraybuffer";
 | 
				
			||||||
 | 
					    r.onreadystatechange = function() {
 | 
				
			||||||
 | 
					        var failure;
 | 
				
			||||||
 | 
					        if (r.readyState == 4) {
 | 
				
			||||||
 | 
					            var data = r.mozResponseArrayBuffer || r.mozResponse ||
 | 
				
			||||||
 | 
					                r.responseArrayBuffer || r.response;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                task.pdfDoc = new PDFDoc(new Stream(data));
 | 
				
			||||||
 | 
					            } catch(e) {
 | 
				
			||||||
 | 
					                failure = 'load PDF doc: '+ e.toString();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            task.pageNum = 1, nextPage(task, failure);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    r.send(null);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function isLastPage(task) {
 | 
				
			||||||
 | 
					    return (task.pdfDoc && (task.pageNum > task.pdfDoc.numPages));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function nextPage(task, loadError) {
 | 
				
			||||||
 | 
					    if (isLastPage(task)) {
 | 
				
			||||||
 | 
						      if (++task.round < task.rounds) {
 | 
				
			||||||
 | 
						          log("  Round "+ (1 + task.round) +"\n");
 | 
				
			||||||
 | 
						          task.pageNum = 1;
 | 
				
			||||||
 | 
						      } else {
 | 
				
			||||||
 | 
						          ++currentTaskIdx, nextTask();
 | 
				
			||||||
 | 
						          return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var failure = loadError || '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var ctx = null;
 | 
				
			||||||
 | 
					    var page = null;
 | 
				
			||||||
 | 
					    if (!failure) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            log("    loading page "+ task.pageNum +"... ");
 | 
				
			||||||
 | 
					            ctx = canvas.getContext("2d");
 | 
				
			||||||
 | 
					            page = task.pdfDoc.getPage(task.pageNum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var pdfToCssUnitsCoef = 96.0 / 72.0;
 | 
				
			||||||
 | 
					            // using mediaBox for the canvas size
 | 
				
			||||||
 | 
					            var pageWidth = (page.mediaBox[2] - page.mediaBox[0]);
 | 
				
			||||||
 | 
					            var pageHeight = (page.mediaBox[3] - page.mediaBox[1]);
 | 
				
			||||||
 | 
					            canvas.width = pageWidth * pdfToCssUnitsCoef;
 | 
				
			||||||
 | 
					            canvas.height = pageHeight * pdfToCssUnitsCoef;
 | 
				
			||||||
 | 
					            clear(ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            page.startRendering(
 | 
				
			||||||
 | 
					              ctx,
 | 
				
			||||||
 | 
					              function() { snapshotCurrentPage(page, task, failure); });
 | 
				
			||||||
 | 
					        } catch(e) {
 | 
				
			||||||
 | 
					            failure = 'page setup: '+ e.toString();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (failure) {
 | 
				
			||||||
 | 
					        // Skip right to snapshotting if there was a failure, since the
 | 
				
			||||||
 | 
					        // fonts might be in an inconsistent state.
 | 
				
			||||||
 | 
					        snapshotCurrentPage(page, task, failure);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function snapshotCurrentPage(page, task, failure) {
 | 
				
			||||||
 | 
					    log("done, snapshotting... ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sendTaskResult(canvas.toDataURL("image/png"), task, failure);
 | 
				
			||||||
 | 
					    log("done"+ (failure ? " (failed!: "+ failure +")" : "") +"\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Set up the next request
 | 
				
			||||||
 | 
					    backoff = (inFlightRequests > 0) ? inFlightRequests * 10 : 0;
 | 
				
			||||||
 | 
					    setTimeout(function() {
 | 
				
			||||||
 | 
					        ++task.pageNum, nextPage(task);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    backoff
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function sendQuitRequest() {
 | 
				
			||||||
 | 
					  var r = new XMLHttpRequest();
 | 
				
			||||||
 | 
					  r.open("POST", "/tellMeToQuit?path=" + escape(appPath), false);
 | 
				
			||||||
 | 
					  r.send("");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function quitApp() {
 | 
				
			||||||
 | 
					  log("Done!");
 | 
				
			||||||
 | 
					  document.body.innerHTML = "Tests are finished.  <h1>CLOSE ME!</h1>";
 | 
				
			||||||
 | 
					  if (window.SpecialPowers) {
 | 
				
			||||||
 | 
					    SpecialPowers.quitApplication();
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    sendQuitRequest();
 | 
				
			||||||
 | 
					    window.close();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function done() {
 | 
				
			||||||
 | 
					  if (inFlightRequests > 0) {
 | 
				
			||||||
 | 
					    document.getElementById("inFlightCount").innerHTML = inFlightRequests;
 | 
				
			||||||
 | 
					    setTimeout(done, 100);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    setTimeout(quitApp, 100);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var inFlightRequests = 0;
 | 
				
			||||||
 | 
					function sendTaskResult(snapshot, task, failure) {
 | 
				
			||||||
 | 
					  var result = { browser: browser,
 | 
				
			||||||
 | 
					                 id: task.id,
 | 
				
			||||||
 | 
					                 numPages: task.pdfDoc.numPages,
 | 
				
			||||||
 | 
					                 failure: failure,
 | 
				
			||||||
 | 
					                 file: task.file,
 | 
				
			||||||
 | 
					                 round: task.round,
 | 
				
			||||||
 | 
					                 page: task.pageNum,
 | 
				
			||||||
 | 
					                 snapshot: snapshot };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  var r = new XMLHttpRequest();
 | 
				
			||||||
 | 
					  // (The POST URI is ignored atm.)
 | 
				
			||||||
 | 
					  r.open("POST", "/submit_task_results", true);
 | 
				
			||||||
 | 
					  r.setRequestHeader("Content-Type", "application/json");
 | 
				
			||||||
 | 
					  r.onreadystatechange = function(e) {
 | 
				
			||||||
 | 
					    if (r.readyState == 4) {
 | 
				
			||||||
 | 
					      inFlightRequests--;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  document.getElementById("inFlightCount").innerHTML = inFlightRequests++;
 | 
				
			||||||
 | 
					  r.send(JSON.stringify(result));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function clear(ctx) {
 | 
				
			||||||
 | 
					  ctx.save();
 | 
				
			||||||
 | 
					  ctx.fillStyle = "rgb(255, 255, 255)";
 | 
				
			||||||
 | 
					  ctx.fillRect(0, 0, canvas.width, canvas.height);
 | 
				
			||||||
 | 
					  ctx.restore();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Auto-scroll if the scrollbar is near the bottom, otherwise do nothing. */
 | 
				
			||||||
 | 
					function checkScrolling() {
 | 
				
			||||||
 | 
					  if ((stdout.scrollHeight - stdout.scrollTop) <= stdout.offsetHeight) {
 | 
				
			||||||
 | 
					    stdout.scrollTop = stdout.scrollHeight;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function log(str) {
 | 
				
			||||||
 | 
					  stdout.innerHTML += str;
 | 
				
			||||||
 | 
					  checkScrolling();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								test/pdfs/DiwanProfile.pdf.link
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/pdfs/DiwanProfile.pdf.link
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					http://oannis.com/DiwanProfile.pdf
 | 
				
			||||||
							
								
								
									
										55
									
								
								test/pdfs/asciihexdecode.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								test/pdfs/asciihexdecode.pdf
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					%PDF-1.0
 | 
				
			||||||
 | 
					1 0 obj
 | 
				
			||||||
 | 
					<<
 | 
				
			||||||
 | 
						/Pages 2 0 R
 | 
				
			||||||
 | 
						/Type /Catalog
 | 
				
			||||||
 | 
					>>
 | 
				
			||||||
 | 
					endobj
 | 
				
			||||||
 | 
					2 0 obj
 | 
				
			||||||
 | 
					<<
 | 
				
			||||||
 | 
						/Count 1
 | 
				
			||||||
 | 
						/Kids [ 3 0 R ]
 | 
				
			||||||
 | 
						/Type /Pages
 | 
				
			||||||
 | 
					>>
 | 
				
			||||||
 | 
					endobj
 | 
				
			||||||
 | 
					3 0 obj
 | 
				
			||||||
 | 
					<<
 | 
				
			||||||
 | 
						/MediaBox [ 0 0 795 842 ]
 | 
				
			||||||
 | 
						/Parent 2 0 R
 | 
				
			||||||
 | 
						/Contents 4 0 R
 | 
				
			||||||
 | 
						/Resources <<
 | 
				
			||||||
 | 
							/Font <<
 | 
				
			||||||
 | 
								/F1 <<
 | 
				
			||||||
 | 
									/Name /F1
 | 
				
			||||||
 | 
									/BaseFont /Helvetica
 | 
				
			||||||
 | 
									/Subtype /Type1
 | 
				
			||||||
 | 
									/Type /Font
 | 
				
			||||||
 | 
								>>
 | 
				
			||||||
 | 
							>>
 | 
				
			||||||
 | 
						>>
 | 
				
			||||||
 | 
						/Type /Page
 | 
				
			||||||
 | 
					>>
 | 
				
			||||||
 | 
					endobj
 | 
				
			||||||
 | 
					4 0 obj
 | 
				
			||||||
 | 
					<<
 | 
				
			||||||
 | 
						/Filter /ASCIIHexDecode
 | 
				
			||||||
 | 
						/Length 111
 | 
				
			||||||
 | 
					>>stream
 | 
				
			||||||
 | 
					42540A2F46312033302054660A333530203735302054640A323020544C0A312054720A2848656C6C6F20776F726C642920546A0A45540A>
 | 
				
			||||||
 | 
					endstream
 | 
				
			||||||
 | 
					endobj
 | 
				
			||||||
 | 
					xref
 | 
				
			||||||
 | 
					0 5
 | 
				
			||||||
 | 
					0000000000 65535 f
 | 
				
			||||||
 | 
					0000000010 00000 n
 | 
				
			||||||
 | 
					0000000067 00000 n
 | 
				
			||||||
 | 
					0000000136 00000 n
 | 
				
			||||||
 | 
					0000000373 00000 n
 | 
				
			||||||
 | 
					trailer
 | 
				
			||||||
 | 
					<<
 | 
				
			||||||
 | 
						/Root 1 0 R
 | 
				
			||||||
 | 
						/Size 5
 | 
				
			||||||
 | 
					>>
 | 
				
			||||||
 | 
					startxref
 | 
				
			||||||
 | 
					568
 | 
				
			||||||
 | 
					%%EOF
 | 
				
			||||||
							
								
								
									
										1
									
								
								test/pdfs/shavian.pdf.link
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/pdfs/shavian.pdf.link
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					http://www.unicode.org/charts/PDF/U10450.pdf
 | 
				
			||||||
							
								
								
									
										44
									
								
								test/test.py
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								test/test.py
									
									
									
									
									
								
							@ -17,7 +17,6 @@ TMPDIR = 'tmp'
 | 
				
			|||||||
VERBOSE = False
 | 
					VERBOSE = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SERVER_HOST = "localhost"
 | 
					SERVER_HOST = "localhost"
 | 
				
			||||||
SERVER_PORT = 8080
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestOptions(OptionParser):
 | 
					class TestOptions(OptionParser):
 | 
				
			||||||
    def __init__(self, **kwargs):
 | 
					    def __init__(self, **kwargs):
 | 
				
			||||||
@ -34,6 +33,8 @@ class TestOptions(OptionParser):
 | 
				
			|||||||
        self.add_option("--reftest", action="store_true", dest="reftest",
 | 
					        self.add_option("--reftest", action="store_true", dest="reftest",
 | 
				
			||||||
                        help="Automatically start reftest showing comparison test failures, if there are any.",
 | 
					                        help="Automatically start reftest showing comparison test failures, if there are any.",
 | 
				
			||||||
                        default=False)
 | 
					                        default=False)
 | 
				
			||||||
 | 
					        self.add_option("--port", action="store", dest="port", type="int",
 | 
				
			||||||
 | 
					                        help="The port the HTTP server should listen on.", default=8080)
 | 
				
			||||||
        self.set_usage(USAGE_EXAMPLE)
 | 
					        self.set_usage(USAGE_EXAMPLE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def verifyOptions(self, options):
 | 
					    def verifyOptions(self, options):
 | 
				
			||||||
@ -44,7 +45,7 @@ class TestOptions(OptionParser):
 | 
				
			|||||||
        if options.browser and options.browserManifestFile:
 | 
					        if options.browser and options.browserManifestFile:
 | 
				
			||||||
            print "Warning: ignoring browser argument since manifest file was also supplied"
 | 
					            print "Warning: ignoring browser argument since manifest file was also supplied"
 | 
				
			||||||
        if not options.browser and not options.browserManifestFile:
 | 
					        if not options.browser and not options.browserManifestFile:
 | 
				
			||||||
            print "No browser arguments supplied, so just starting server on port %s." % SERVER_PORT
 | 
					            print "Starting server on port %s." % options.port
 | 
				
			||||||
        return options
 | 
					        return options
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
def prompt(question):
 | 
					def prompt(question):
 | 
				
			||||||
@ -70,7 +71,6 @@ class State:
 | 
				
			|||||||
    remaining = 0
 | 
					    remaining = 0
 | 
				
			||||||
    results = { }
 | 
					    results = { }
 | 
				
			||||||
    done = False
 | 
					    done = False
 | 
				
			||||||
    masterMode = False
 | 
					 | 
				
			||||||
    numErrors = 0
 | 
					    numErrors = 0
 | 
				
			||||||
    numEqFailures = 0
 | 
					    numEqFailures = 0
 | 
				
			||||||
    numEqNoSnapshot = 0
 | 
					    numEqNoSnapshot = 0
 | 
				
			||||||
@ -99,7 +99,7 @@ class PDFTestHandler(BaseHTTPRequestHandler):
 | 
				
			|||||||
        self.send_header("Content-Type", MIMEs[ext])
 | 
					        self.send_header("Content-Type", MIMEs[ext])
 | 
				
			||||||
        self.send_header("Content-Length", os.path.getsize(path))
 | 
					        self.send_header("Content-Length", os.path.getsize(path))
 | 
				
			||||||
        self.end_headers()
 | 
					        self.end_headers()
 | 
				
			||||||
        with open(path) as f:
 | 
					        with open(path, "rb") as f:
 | 
				
			||||||
            self.wfile.write(f.read())
 | 
					            self.wfile.write(f.read())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def do_GET(self):
 | 
					    def do_GET(self):
 | 
				
			||||||
@ -157,7 +157,8 @@ class PDFTestHandler(BaseHTTPRequestHandler):
 | 
				
			|||||||
            # sort the results since they sometimes come in out of order
 | 
					            # sort the results since they sometimes come in out of order
 | 
				
			||||||
            for results in taskResults:
 | 
					            for results in taskResults:
 | 
				
			||||||
                results.sort(key=lambda result: result.page)
 | 
					                results.sort(key=lambda result: result.page)
 | 
				
			||||||
            check(State.manifest[id], taskResults, browser)
 | 
					            check(State.manifest[id], taskResults, browser,
 | 
				
			||||||
 | 
					                  self.server.masterMode)
 | 
				
			||||||
            # Please oh please GC this ...
 | 
					            # Please oh please GC this ...
 | 
				
			||||||
            del State.taskResults[browser][id]
 | 
					            del State.taskResults[browser][id]
 | 
				
			||||||
            State.remaining -= 1
 | 
					            State.remaining -= 1
 | 
				
			||||||
@ -188,7 +189,7 @@ class BaseBrowserCommand(object):
 | 
				
			|||||||
            self._fixupMacPath()
 | 
					            self._fixupMacPath()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if not os.path.exists(self.path):
 | 
					        if not os.path.exists(self.path):
 | 
				
			||||||
            throw("Path to browser '%s' does not exist." % self.path)
 | 
					            raise Exception("Path to browser '%s' does not exist." % self.path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setup(self):
 | 
					    def setup(self):
 | 
				
			||||||
        self.tempDir = tempfile.mkdtemp()
 | 
					        self.tempDir = tempfile.mkdtemp()
 | 
				
			||||||
@ -275,7 +276,7 @@ def downloadLinkedPDFs(manifestList):
 | 
				
			|||||||
            sys.stdout.flush()
 | 
					            sys.stdout.flush()
 | 
				
			||||||
            response = urllib2.urlopen(link)
 | 
					            response = urllib2.urlopen(link)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            with open(f, 'w') as out:
 | 
					            with open(f, 'wb') as out:
 | 
				
			||||||
                out.write(response.read())
 | 
					                out.write(response.read())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            print 'done'
 | 
					            print 'done'
 | 
				
			||||||
@ -284,7 +285,6 @@ def setUp(options):
 | 
				
			|||||||
    # Only serve files from a pdf.js clone
 | 
					    # Only serve files from a pdf.js clone
 | 
				
			||||||
    assert not ANAL or os.path.isfile('../pdf.js') and os.path.isdir('../.git')
 | 
					    assert not ANAL or os.path.isfile('../pdf.js') and os.path.isdir('../.git')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    State.masterMode = options.masterMode
 | 
					 | 
				
			||||||
    if options.masterMode and os.path.isdir(TMPDIR):
 | 
					    if options.masterMode and os.path.isdir(TMPDIR):
 | 
				
			||||||
        print 'Temporary snapshot dir tmp/ is still around.'
 | 
					        print 'Temporary snapshot dir tmp/ is still around.'
 | 
				
			||||||
        print 'tmp/ can be removed if it has nothing you need.'
 | 
					        print 'tmp/ can be removed if it has nothing you need.'
 | 
				
			||||||
@ -325,7 +325,7 @@ def startBrowsers(browsers, options):
 | 
				
			|||||||
    for b in browsers:
 | 
					    for b in browsers:
 | 
				
			||||||
        b.setup()
 | 
					        b.setup()
 | 
				
			||||||
        print 'Launching', b.name
 | 
					        print 'Launching', b.name
 | 
				
			||||||
        host = 'http://%s:%s' % (SERVER_HOST, SERVER_PORT) 
 | 
					        host = 'http://%s:%s' % (SERVER_HOST, options.port) 
 | 
				
			||||||
        path = '/test/test_slave.html?'
 | 
					        path = '/test/test_slave.html?'
 | 
				
			||||||
        qs = 'browser='+ urllib.quote(b.name) +'&manifestFile='+ urllib.quote(options.manifestFile)
 | 
					        qs = 'browser='+ urllib.quote(b.name) +'&manifestFile='+ urllib.quote(options.manifestFile)
 | 
				
			||||||
        qs += '&path=' + b.path
 | 
					        qs += '&path=' + b.path
 | 
				
			||||||
@ -340,7 +340,7 @@ def teardownBrowsers(browsers):
 | 
				
			|||||||
            print "Temp dir was ", b.tempDir
 | 
					            print "Temp dir was ", b.tempDir
 | 
				
			||||||
            print "Error:", sys.exc_info()[0]
 | 
					            print "Error:", sys.exc_info()[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def check(task, results, browser):
 | 
					def check(task, results, browser, masterMode):
 | 
				
			||||||
    failed = False
 | 
					    failed = False
 | 
				
			||||||
    for r in xrange(len(results)):
 | 
					    for r in xrange(len(results)):
 | 
				
			||||||
        pageResults = results[r]
 | 
					        pageResults = results[r]
 | 
				
			||||||
@ -359,7 +359,7 @@ def check(task, results, browser):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    kind = task['type']
 | 
					    kind = task['type']
 | 
				
			||||||
    if 'eq' == kind:
 | 
					    if 'eq' == kind:
 | 
				
			||||||
        checkEq(task, results, browser)
 | 
					        checkEq(task, results, browser, masterMode)
 | 
				
			||||||
    elif 'fbf' == kind:
 | 
					    elif 'fbf' == kind:
 | 
				
			||||||
        checkFBF(task, results, browser)
 | 
					        checkFBF(task, results, browser)
 | 
				
			||||||
    elif 'load' == kind:
 | 
					    elif 'load' == kind:
 | 
				
			||||||
@ -368,7 +368,7 @@ def check(task, results, browser):
 | 
				
			|||||||
        assert 0 and 'Unknown test type'
 | 
					        assert 0 and 'Unknown test type'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def checkEq(task, results, browser):
 | 
					def checkEq(task, results, browser, masterMode):
 | 
				
			||||||
    pfx = os.path.join(REFDIR, sys.platform, browser, task['id'])
 | 
					    pfx = os.path.join(REFDIR, sys.platform, browser, task['id'])
 | 
				
			||||||
    results = results[0]
 | 
					    results = results[0]
 | 
				
			||||||
    taskId = task['id']
 | 
					    taskId = task['id']
 | 
				
			||||||
@ -406,12 +406,12 @@ def checkEq(task, results, browser):
 | 
				
			|||||||
                passed = False
 | 
					                passed = False
 | 
				
			||||||
                State.numEqFailures += 1
 | 
					                State.numEqFailures += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if State.masterMode and (ref is None or not eq):
 | 
					        if masterMode and (ref is None or not eq):
 | 
				
			||||||
            tmpTaskDir = os.path.join(TMPDIR, sys.platform, browser, task['id'])
 | 
					            tmpTaskDir = os.path.join(TMPDIR, sys.platform, browser, task['id'])
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                os.makedirs(tmpTaskDir)
 | 
					                os.makedirs(tmpTaskDir)
 | 
				
			||||||
            except OSError, e:
 | 
					            except OSError, e:
 | 
				
			||||||
                pass
 | 
					                print >>sys.stderr, 'Creating', tmpTaskDir, 'failed!'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            of = open(os.path.join(tmpTaskDir, str(page + 1)), 'w')
 | 
					            of = open(os.path.join(tmpTaskDir, str(page + 1)), 'w')
 | 
				
			||||||
            of.write(snapshot)
 | 
					            of.write(snapshot)
 | 
				
			||||||
@ -482,8 +482,8 @@ def maybeUpdateRefImages(options, browser):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                print 'done'
 | 
					                print 'done'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def startReftest(browser):
 | 
					def startReftest(browser, options):
 | 
				
			||||||
    url = "http://%s:%s" % (SERVER_HOST, SERVER_PORT)
 | 
					    url = "http://%s:%s" % (SERVER_HOST, options.port)
 | 
				
			||||||
    url += "/test/resources/reftest-analyzer.xhtml"
 | 
					    url += "/test/resources/reftest-analyzer.xhtml"
 | 
				
			||||||
    url += "#web=/test/eq.log"
 | 
					    url += "#web=/test/eq.log"
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
@ -511,7 +511,7 @@ def runTests(options, browsers):
 | 
				
			|||||||
        maybeUpdateRefImages(options, browsers[0])
 | 
					        maybeUpdateRefImages(options, browsers[0])
 | 
				
			||||||
    elif options.reftest and State.numEqFailures > 0:
 | 
					    elif options.reftest and State.numEqFailures > 0:
 | 
				
			||||||
        print "\nStarting reftest harness to examine %d eq test failures." % State.numEqFailures
 | 
					        print "\nStarting reftest harness to examine %d eq test failures." % State.numEqFailures
 | 
				
			||||||
        startReftest(browsers[0])
 | 
					        startReftest(browsers[0], options)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def main():
 | 
					def main():
 | 
				
			||||||
    optionParser = TestOptions()
 | 
					    optionParser = TestOptions()
 | 
				
			||||||
@ -520,7 +520,8 @@ def main():
 | 
				
			|||||||
    if options == None:
 | 
					    if options == None:
 | 
				
			||||||
        sys.exit(1)
 | 
					        sys.exit(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    httpd = TestServer((SERVER_HOST, SERVER_PORT), PDFTestHandler)
 | 
					    httpd = TestServer((SERVER_HOST, options.port), PDFTestHandler)
 | 
				
			||||||
 | 
					    httpd.masterMode = options.masterMode
 | 
				
			||||||
    httpd_thread = threading.Thread(target=httpd.serve_forever)
 | 
					    httpd_thread = threading.Thread(target=httpd.serve_forever)
 | 
				
			||||||
    httpd_thread.setDaemon(True)
 | 
					    httpd_thread.setDaemon(True)
 | 
				
			||||||
    httpd_thread.start()
 | 
					    httpd_thread.start()
 | 
				
			||||||
@ -531,8 +532,11 @@ def main():
 | 
				
			|||||||
    else:
 | 
					    else:
 | 
				
			||||||
        # just run the server
 | 
					        # just run the server
 | 
				
			||||||
        print "Running HTTP server. Press Ctrl-C to quit."
 | 
					        print "Running HTTP server. Press Ctrl-C to quit."
 | 
				
			||||||
        while True:
 | 
					        try:
 | 
				
			||||||
            time.sleep(1)
 | 
					            while True:
 | 
				
			||||||
 | 
					                time.sleep(1)
 | 
				
			||||||
 | 
					        except (KeyboardInterrupt):
 | 
				
			||||||
 | 
					            print "\nExiting."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
    main()
 | 
					    main()
 | 
				
			||||||
 | 
				
			|||||||
@ -26,6 +26,12 @@
 | 
				
			|||||||
       "rounds": 1,
 | 
					       "rounds": 1,
 | 
				
			||||||
       "type": "load"
 | 
					       "type": "load"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    {  "id": "shavian-load",
 | 
				
			||||||
 | 
					       "file": "pdfs/shavian.pdf",
 | 
				
			||||||
 | 
					       "link": true,
 | 
				
			||||||
 | 
					       "rounds": 1,
 | 
				
			||||||
 | 
					       "type": "load"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    {  "id": "sizes",
 | 
					    {  "id": "sizes",
 | 
				
			||||||
       "file": "pdfs/sizes.pdf",
 | 
					       "file": "pdfs/sizes.pdf",
 | 
				
			||||||
       "rounds": 1,
 | 
					       "rounds": 1,
 | 
				
			||||||
@ -36,5 +42,11 @@
 | 
				
			|||||||
       "link": true,
 | 
					       "link": true,
 | 
				
			||||||
       "rounds": 1,
 | 
					       "rounds": 1,
 | 
				
			||||||
       "type": "eq"
 | 
					       "type": "eq"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {  "id": "openoffice-pdf",
 | 
				
			||||||
 | 
					       "file": "pdfs/DiwanProfile.pdf",
 | 
				
			||||||
 | 
					       "link": true,
 | 
				
			||||||
 | 
					       "rounds": 1,
 | 
				
			||||||
 | 
					       "type": "load"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
				
			|||||||
@ -6,222 +6,7 @@
 | 
				
			|||||||
  <script type="text/javascript" src="/fonts.js"></script>
 | 
					  <script type="text/javascript" src="/fonts.js"></script>
 | 
				
			||||||
  <script type="text/javascript" src="/crypto.js"></script>
 | 
					  <script type="text/javascript" src="/crypto.js"></script>
 | 
				
			||||||
  <script type="text/javascript" src="/glyphlist.js"></script>
 | 
					  <script type="text/javascript" src="/glyphlist.js"></script>
 | 
				
			||||||
  <script type="application/javascript">
 | 
					  <script type="text/javascript" src="driver.js"></script>
 | 
				
			||||||
var appPath, browser, canvas, currentTask, currentTaskIdx, failure, manifest, numPages, pdfDoc, stdout;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function queryParams() {
 | 
					 | 
				
			||||||
    var qs = window.location.search.substring(1);
 | 
					 | 
				
			||||||
    var kvs = qs.split("&");
 | 
					 | 
				
			||||||
    var params = { };
 | 
					 | 
				
			||||||
    for (var i = 0; i < kvs.length; ++i) {
 | 
					 | 
				
			||||||
        var kv = kvs[i].split("=");
 | 
					 | 
				
			||||||
        params[unescape(kv[0])] = unescape(kv[1]);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return params;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function load() {
 | 
					 | 
				
			||||||
  var params = queryParams();
 | 
					 | 
				
			||||||
  browser = params.browser;
 | 
					 | 
				
			||||||
  manifestFile = params.manifestFile;
 | 
					 | 
				
			||||||
  appPath = params.path;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  canvas = document.createElement("canvas");
 | 
					 | 
				
			||||||
  canvas.mozOpaque = true;
 | 
					 | 
				
			||||||
  stdout = document.getElementById("stdout");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  log("Harness thinks this browser is '"+ browser + "' with path " + appPath + "\n");
 | 
					 | 
				
			||||||
  log("Fetching manifest "+ manifestFile +"...");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  var r = new XMLHttpRequest();
 | 
					 | 
				
			||||||
  r.open("GET", manifestFile, false);
 | 
					 | 
				
			||||||
  r.onreadystatechange = function(e) {
 | 
					 | 
				
			||||||
    if (r.readyState == 4) {
 | 
					 | 
				
			||||||
      log("done\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      manifest = JSON.parse(r.responseText);
 | 
					 | 
				
			||||||
      currentTaskIdx = 0, nextTask();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  r.send(null);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function nextTask() {
 | 
					 | 
				
			||||||
  if (currentTaskIdx == manifest.length) {
 | 
					 | 
				
			||||||
    return done();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  currentTask = manifest[currentTaskIdx];
 | 
					 | 
				
			||||||
  currentTask.round = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  log("Loading file "+ currentTask.file +"\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  var r = new XMLHttpRequest();
 | 
					 | 
				
			||||||
  r.open("GET", currentTask.file);
 | 
					 | 
				
			||||||
  r.mozResponseType = r.responseType = "arraybuffer";
 | 
					 | 
				
			||||||
  r.onreadystatechange = function() {
 | 
					 | 
				
			||||||
    if (r.readyState == 4) {
 | 
					 | 
				
			||||||
      var data = r.mozResponseArrayBuffer || r.mozResponse ||
 | 
					 | 
				
			||||||
                 r.responseArrayBuffer || r.response;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      try {
 | 
					 | 
				
			||||||
        pdfDoc = new PDFDoc(new Stream(data));
 | 
					 | 
				
			||||||
        numPages = pdfDoc.numPages;
 | 
					 | 
				
			||||||
      } catch(e) {
 | 
					 | 
				
			||||||
        numPages = 1;
 | 
					 | 
				
			||||||
        failure = 'load PDF doc: '+ e.toString();
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      currentTask.pageNum = 1, nextPage();
 | 
					 | 
				
			||||||
    }    
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  r.send(null);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function nextPage() {
 | 
					 | 
				
			||||||
  if (currentTask.pageNum > numPages) {
 | 
					 | 
				
			||||||
    if (++currentTask.round < currentTask.rounds) {
 | 
					 | 
				
			||||||
      log("  Round "+ (1 + currentTask.round) +"\n");
 | 
					 | 
				
			||||||
      currentTask.pageNum = 1;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      ++currentTaskIdx, nextTask();
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  failure = '';
 | 
					 | 
				
			||||||
  log("    loading page "+ currentTask.pageNum +"... ");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  var ctx = canvas.getContext("2d");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  var fonts = [];
 | 
					 | 
				
			||||||
  var gfx = null;
 | 
					 | 
				
			||||||
  try {
 | 
					 | 
				
			||||||
    gfx = new CanvasGraphics(ctx);
 | 
					 | 
				
			||||||
    currentPage = pdfDoc.getPage(currentTask.pageNum);
 | 
					 | 
				
			||||||
    currentPage.compile(gfx, fonts);
 | 
					 | 
				
			||||||
  } catch(e) {
 | 
					 | 
				
			||||||
    failure = 'compile: '+ e.toString();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  try {
 | 
					 | 
				
			||||||
    var pdfToCssUnitsCoef = 96.0 / 72.0;
 | 
					 | 
				
			||||||
    // using mediaBox for the canvas size
 | 
					 | 
				
			||||||
    var pageWidth = (currentPage.mediaBox[2] - currentPage.mediaBox[0]);
 | 
					 | 
				
			||||||
    var pageHeight = (currentPage.mediaBox[3] - currentPage.mediaBox[1]);
 | 
					 | 
				
			||||||
    canvas.width = pageWidth * pdfToCssUnitsCoef;
 | 
					 | 
				
			||||||
    canvas.height = pageHeight * pdfToCssUnitsCoef;
 | 
					 | 
				
			||||||
    clear(ctx);
 | 
					 | 
				
			||||||
  } catch(e) {
 | 
					 | 
				
			||||||
    failure = 'page setup: '+ e.toString();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!failure) {
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      FontLoader.bind(fonts, function() { snapshotCurrentPage(gfx); });
 | 
					 | 
				
			||||||
    } catch(e) {
 | 
					 | 
				
			||||||
      failure = 'fonts: '+ e.toString();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (failure) {
 | 
					 | 
				
			||||||
    // Skip right to snapshotting if there was a failure, since the
 | 
					 | 
				
			||||||
    // fonts might be in an inconsistent state.
 | 
					 | 
				
			||||||
    snapshotCurrentPage(gfx);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function snapshotCurrentPage(gfx) {
 | 
					 | 
				
			||||||
  log("done, snapshotting... ");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!failure) {
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      currentPage.display(gfx);
 | 
					 | 
				
			||||||
    } catch(e) {
 | 
					 | 
				
			||||||
      failure = 'render: '+ e.toString();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  sendTaskResult(canvas.toDataURL("image/png"));
 | 
					 | 
				
			||||||
  log("done"+ (failure ? " (failed!)" : "") +"\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Set up the next request
 | 
					 | 
				
			||||||
  backoff = (inFlightRequests > 0) ? inFlightRequests * 10 : 0;
 | 
					 | 
				
			||||||
  setTimeout(function() {
 | 
					 | 
				
			||||||
      ++currentTask.pageNum, nextPage();
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    backoff
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function sendQuitRequest() {
 | 
					 | 
				
			||||||
  var r = new XMLHttpRequest();
 | 
					 | 
				
			||||||
  r.open("POST", "/tellMeToQuit?path=" + escape(appPath), false);
 | 
					 | 
				
			||||||
  r.send("");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function quitApp() {
 | 
					 | 
				
			||||||
  log("Done!");
 | 
					 | 
				
			||||||
  document.body.innerHTML = "Tests are finished.  <h1>CLOSE ME!</h1>";
 | 
					 | 
				
			||||||
  if (window.SpecialPowers) {
 | 
					 | 
				
			||||||
    SpecialPowers.quitApplication();
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    sendQuitRequest();
 | 
					 | 
				
			||||||
    window.close();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function done() {
 | 
					 | 
				
			||||||
  if (inFlightRequests > 0) {
 | 
					 | 
				
			||||||
    document.getElementById("inFlightCount").innerHTML = inFlightRequests;
 | 
					 | 
				
			||||||
    setTimeout(done, 100);
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    setTimeout(quitApp, 100);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var inFlightRequests = 0;
 | 
					 | 
				
			||||||
function sendTaskResult(snapshot) {
 | 
					 | 
				
			||||||
  var result = { browser: browser,
 | 
					 | 
				
			||||||
                 id: currentTask.id,
 | 
					 | 
				
			||||||
                 numPages: numPages,
 | 
					 | 
				
			||||||
                 failure: failure,
 | 
					 | 
				
			||||||
                 file: currentTask.file,
 | 
					 | 
				
			||||||
                 round: currentTask.round,
 | 
					 | 
				
			||||||
                 page: currentTask.pageNum,
 | 
					 | 
				
			||||||
                 snapshot: snapshot };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  var r = new XMLHttpRequest();
 | 
					 | 
				
			||||||
  // (The POST URI is ignored atm.)
 | 
					 | 
				
			||||||
  r.open("POST", "/submit_task_results", true);
 | 
					 | 
				
			||||||
  r.setRequestHeader("Content-Type", "application/json");
 | 
					 | 
				
			||||||
  r.onreadystatechange = function(e) {
 | 
					 | 
				
			||||||
    if (r.readyState == 4) {
 | 
					 | 
				
			||||||
      inFlightRequests--;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  document.getElementById("inFlightCount").innerHTML = inFlightRequests++;
 | 
					 | 
				
			||||||
  r.send(JSON.stringify(result));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function clear(ctx) {
 | 
					 | 
				
			||||||
  ctx.save();
 | 
					 | 
				
			||||||
  ctx.fillStyle = "rgb(255, 255, 255)";
 | 
					 | 
				
			||||||
  ctx.fillRect(0, 0, canvas.width, canvas.height);
 | 
					 | 
				
			||||||
  ctx.restore();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Auto-scroll if the scrollbar is near the bottom, otherwise do nothing. */
 | 
					 | 
				
			||||||
function checkScrolling() {
 | 
					 | 
				
			||||||
  if ((stdout.scrollHeight - stdout.scrollTop) <= stdout.offsetHeight) {
 | 
					 | 
				
			||||||
    stdout.scrollTop = stdout.scrollHeight;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function log(str) {
 | 
					 | 
				
			||||||
  stdout.innerHTML += str;
 | 
					 | 
				
			||||||
  checkScrolling();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
  </script>
 | 
					 | 
				
			||||||
</head>
 | 
					</head>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<body onload="load();">
 | 
					<body onload="load();">
 | 
				
			||||||
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -1,7 +1,7 @@
 | 
				
			|||||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 | 
					/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 | 
				
			||||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
					/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"use strict";
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * The Type2 reader code below is only used for debugging purpose since Type2
 | 
					 * The Type2 reader code below is only used for debugging purpose since Type2
 | 
				
			||||||
@ -21,7 +21,7 @@ function readCharset(aStream, aCharstrings) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  var format = aStream.getByte();
 | 
					  var format = aStream.getByte();
 | 
				
			||||||
  if (format == 0) {
 | 
					  if (format == 0) {
 | 
				
			||||||
    charset[".notdef"] = readCharstringEncoding(aCharstrings[0]);
 | 
					    charset['.notdef'] = readCharstringEncoding(aCharstrings[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var count = aCharstrings.length - 1;
 | 
					    var count = aCharstrings.length - 1;
 | 
				
			||||||
    for (var i = 1; i < count + 1; i++) {
 | 
					    for (var i = 1; i < count + 1; i++) {
 | 
				
			||||||
@ -30,13 +30,13 @@ function readCharset(aStream, aCharstrings) {
 | 
				
			|||||||
      //log(CFFStrings[sid] + "::" + charset[CFFStrings[sid]]);
 | 
					      //log(CFFStrings[sid] + "::" + charset[CFFStrings[sid]]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  } else if (format == 1) {
 | 
					  } else if (format == 1) {
 | 
				
			||||||
    error("Charset Range are not supported");
 | 
					    error('Charset Range are not supported');
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    error("Invalid charset format");
 | 
					    error('Invalid charset format');
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return charset;
 | 
					  return charset;
 | 
				
			||||||
};
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Take a Type2 binary charstring as input and transform it to a human
 | 
					 * Take a Type2 binary charstring as input and transform it to a human
 | 
				
			||||||
@ -83,7 +83,7 @@ function readCharstringEncoding(aString) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return charstringTokens;
 | 
					  return charstringTokens;
 | 
				
			||||||
};
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -105,10 +105,10 @@ function readFontDictData(aString, aMap) {
 | 
				
			|||||||
    } else if (value == 29) {
 | 
					    } else if (value == 29) {
 | 
				
			||||||
      token = aString[i++] << 24 |
 | 
					      token = aString[i++] << 24 |
 | 
				
			||||||
              aString[i++] << 16 |
 | 
					              aString[i++] << 16 |
 | 
				
			||||||
              aString[i++] << 8  |
 | 
					              aString[i++] << 8 |
 | 
				
			||||||
              aString[i++];
 | 
					              aString[i++];
 | 
				
			||||||
    } else if (value == 30) {
 | 
					    } else if (value == 30) {
 | 
				
			||||||
      token = "";
 | 
					      token = '';
 | 
				
			||||||
      var parsed = false;
 | 
					      var parsed = false;
 | 
				
			||||||
      while (!parsed) {
 | 
					      while (!parsed) {
 | 
				
			||||||
        var byte = aString[i++];
 | 
					        var byte = aString[i++];
 | 
				
			||||||
@ -118,18 +118,18 @@ function readFontDictData(aString, aMap) {
 | 
				
			|||||||
          var nibble = nibbles[j];
 | 
					          var nibble = nibbles[j];
 | 
				
			||||||
          switch (nibble) {
 | 
					          switch (nibble) {
 | 
				
			||||||
            case 0xA:
 | 
					            case 0xA:
 | 
				
			||||||
              token += ".";
 | 
					              token += '.';
 | 
				
			||||||
              break;
 | 
					              break;
 | 
				
			||||||
            case 0xB:
 | 
					            case 0xB:
 | 
				
			||||||
              token += "E";
 | 
					              token += 'E';
 | 
				
			||||||
              break;
 | 
					              break;
 | 
				
			||||||
            case 0xC:
 | 
					            case 0xC:
 | 
				
			||||||
              token += "E-";
 | 
					              token += 'E-';
 | 
				
			||||||
              break;
 | 
					              break;
 | 
				
			||||||
            case 0xD:
 | 
					            case 0xD:
 | 
				
			||||||
              break;
 | 
					              break;
 | 
				
			||||||
            case 0xE:
 | 
					            case 0xE:
 | 
				
			||||||
              token += "-";
 | 
					              token += '-';
 | 
				
			||||||
              break;
 | 
					              break;
 | 
				
			||||||
            case 0xF:
 | 
					            case 0xF:
 | 
				
			||||||
              parsed = true;
 | 
					              parsed = true;
 | 
				
			||||||
@ -139,7 +139,7 @@ function readFontDictData(aString, aMap) {
 | 
				
			|||||||
              break;
 | 
					              break;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      };
 | 
					      }
 | 
				
			||||||
      token = parseFloat(token);
 | 
					      token = parseFloat(token);
 | 
				
			||||||
    } else if (value <= 31) {
 | 
					    } else if (value <= 31) {
 | 
				
			||||||
      token = aMap[value];
 | 
					      token = aMap[value];
 | 
				
			||||||
@ -150,14 +150,14 @@ function readFontDictData(aString, aMap) {
 | 
				
			|||||||
    } else if (value <= 254) {
 | 
					    } else if (value <= 254) {
 | 
				
			||||||
      token = -((value - 251) * 256) - aString[i++] - 108;
 | 
					      token = -((value - 251) * 256) - aString[i++] - 108;
 | 
				
			||||||
    } else if (value == 255) {
 | 
					    } else if (value == 255) {
 | 
				
			||||||
      error("255 is not a valid DICT command");
 | 
					      error('255 is not a valid DICT command');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fontDictDataTokens.push(token);
 | 
					    fontDictDataTokens.push(token);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return fontDictDataTokens;
 | 
					  return fontDictDataTokens;
 | 
				
			||||||
};
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -192,7 +192,7 @@ function readFontIndexData(aStream, aIsByte) {
 | 
				
			|||||||
      return aStream.getByte() << 24 | aStream.getByte() << 16 |
 | 
					      return aStream.getByte() << 24 | aStream.getByte() << 16 |
 | 
				
			||||||
             aStream.getByte() << 8 | aStream.getByte();
 | 
					             aStream.getByte() << 8 | aStream.getByte();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    error(offsize + " is not a valid offset size");
 | 
					    error(offsize + ' is not a valid offset size');
 | 
				
			||||||
    return null;
 | 
					    return null;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -200,7 +200,8 @@ function readFontIndexData(aStream, aIsByte) {
 | 
				
			|||||||
  for (var i = 0; i < count + 1; i++)
 | 
					  for (var i = 0; i < count + 1; i++)
 | 
				
			||||||
    offsets.push(getNextOffset());
 | 
					    offsets.push(getNextOffset());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  log("Found " + count + " objects at offsets :" + offsets + " (offsize: " + offsize + ")");
 | 
					  log('Found ' + count + ' objects at offsets :' +
 | 
				
			||||||
 | 
					      offsets + ' (offsize: ' + offsize + ')');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Now extract the objects
 | 
					  // Now extract the objects
 | 
				
			||||||
  var relativeOffset = aStream.pos;
 | 
					  var relativeOffset = aStream.pos;
 | 
				
			||||||
@ -217,15 +218,15 @@ function readFontIndexData(aStream, aIsByte) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return objects;
 | 
					  return objects;
 | 
				
			||||||
};
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var Type2Parser = function(aFilePath) {
 | 
					var Type2Parser = function(aFilePath) {
 | 
				
			||||||
  var font = new Dict();
 | 
					  var font = new Dict();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  var xhr = new XMLHttpRequest();
 | 
					  var xhr = new XMLHttpRequest();
 | 
				
			||||||
  xhr.open("GET", aFilePath, false);
 | 
					  xhr.open('GET', aFilePath, false);
 | 
				
			||||||
  xhr.mozResponseType = xhr.responseType = "arraybuffer";
 | 
					  xhr.mozResponseType = xhr.responseType = 'arraybuffer';
 | 
				
			||||||
  xhr.expected = (document.URL.indexOf("file:") == 0) ? 0 : 200;
 | 
					  xhr.expected = (document.URL.indexOf('file:') == 0) ? 0 : 200;
 | 
				
			||||||
  xhr.send(null);
 | 
					  xhr.send(null);
 | 
				
			||||||
  this.data = new Stream(xhr.mozResponseArrayBuffer || xhr.mozResponse ||
 | 
					  this.data = new Stream(xhr.mozResponseArrayBuffer || xhr.mozResponse ||
 | 
				
			||||||
                         xhr.responseArrayBuffer || xhr.response);
 | 
					                         xhr.responseArrayBuffer || xhr.response);
 | 
				
			||||||
@ -249,19 +250,19 @@ var Type2Parser = function(aFilePath) {
 | 
				
			|||||||
        stack.push(token);
 | 
					        stack.push(token);
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        switch (token.operand) {
 | 
					        switch (token.operand) {
 | 
				
			||||||
          case "SID":
 | 
					          case 'SID':
 | 
				
			||||||
            font.set(token.name, CFFStrings[stack.pop()]);
 | 
					            font.set(token.name, CFFStrings[stack.pop()]);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
          case "number number":
 | 
					          case 'number number':
 | 
				
			||||||
            font.set(token.name, {
 | 
					            font.set(token.name, {
 | 
				
			||||||
              offset: stack.pop(),
 | 
					              offset: stack.pop(),
 | 
				
			||||||
              size: stack.pop()
 | 
					              size: stack.pop()
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
          case "boolean":
 | 
					          case 'boolean':
 | 
				
			||||||
            font.set(token.name, stack.pop());
 | 
					            font.set(token.name, stack.pop());
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
          case "delta":
 | 
					          case 'delta':
 | 
				
			||||||
            font.set(token.name, stack.pop());
 | 
					            font.set(token.name, stack.pop());
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
          default:
 | 
					          default:
 | 
				
			||||||
@ -280,32 +281,32 @@ var Type2Parser = function(aFilePath) {
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  this.parse = function(aStream) {
 | 
					  this.parse = function(aStream) {
 | 
				
			||||||
    font.set("major", aStream.getByte());
 | 
					    font.set('major', aStream.getByte());
 | 
				
			||||||
    font.set("minor", aStream.getByte());
 | 
					    font.set('minor', aStream.getByte());
 | 
				
			||||||
    font.set("hdrSize", aStream.getByte());
 | 
					    font.set('hdrSize', aStream.getByte());
 | 
				
			||||||
    font.set("offsize", aStream.getByte());
 | 
					    font.set('offsize', aStream.getByte());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Move the cursor after the header
 | 
					    // Move the cursor after the header
 | 
				
			||||||
    aStream.skip(font.get("hdrSize") - aStream.pos);
 | 
					    aStream.skip(font.get('hdrSize') - aStream.pos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Read the NAME Index
 | 
					    // Read the NAME Index
 | 
				
			||||||
    dump("Reading Index: Names");
 | 
					    dump('Reading Index: Names');
 | 
				
			||||||
    font.set("Names", readFontIndexData(aStream));
 | 
					    font.set('Names', readFontIndexData(aStream));
 | 
				
			||||||
    log("Names: " + font.get("Names"));
 | 
					    log('Names: ' + font.get('Names'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Read the Top Dict Index
 | 
					    // Read the Top Dict Index
 | 
				
			||||||
    dump("Reading Index: TopDict");
 | 
					    dump('Reading Index: TopDict');
 | 
				
			||||||
    var topDict = readFontIndexData(aStream, true);
 | 
					    var topDict = readFontIndexData(aStream, true);
 | 
				
			||||||
    log("TopDict: " + topDict);
 | 
					    log('TopDict: ' + topDict);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Read the String Index
 | 
					    // Read the String Index
 | 
				
			||||||
    dump("Reading Index: Strings");
 | 
					    dump('Reading Index: Strings');
 | 
				
			||||||
    var strings = readFontIndexData(aStream);
 | 
					    var strings = readFontIndexData(aStream);
 | 
				
			||||||
    log("strings: " + strings);
 | 
					    log('strings: ' + strings);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Fill up the Strings dictionary with the new unique strings
 | 
					    // Fill up the Strings dictionary with the new unique strings
 | 
				
			||||||
    for (var i = 0; i < strings.length; i++)
 | 
					    for (var i = 0; i < strings.length; i++)
 | 
				
			||||||
      CFFStrings.push(strings[i].join(""));
 | 
					      CFFStrings.push(strings[i].join(''));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Parse the TopDict operator
 | 
					    // Parse the TopDict operator
 | 
				
			||||||
    var objects = [];
 | 
					    var objects = [];
 | 
				
			||||||
@ -315,39 +316,40 @@ var Type2Parser = function(aFilePath) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Read the Global Subr Index that comes just after the Strings Index
 | 
					    // Read the Global Subr Index that comes just after the Strings Index
 | 
				
			||||||
    // (cf. "The Compact Font Format Specification" Chapter 16)
 | 
					    // (cf. "The Compact Font Format Specification" Chapter 16)
 | 
				
			||||||
    dump("Reading Global Subr Index");
 | 
					    dump('Reading Global Subr Index');
 | 
				
			||||||
    var subrs = readFontIndexData(aStream, true);
 | 
					    var subrs = readFontIndexData(aStream, true);
 | 
				
			||||||
    dump(subrs);
 | 
					    dump(subrs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Reading Private Dict
 | 
					    // Reading Private Dict
 | 
				
			||||||
    var priv = font.get("Private");
 | 
					    var priv = font.get('Private');
 | 
				
			||||||
    log("Reading Private Dict (offset: " + priv.offset + " size: " + priv.size + ")");
 | 
					    log('Reading Private Dict (offset: ' + priv.offset +
 | 
				
			||||||
 | 
					        ' size: ' + priv.size + ')');
 | 
				
			||||||
    aStream.pos = priv.offset;
 | 
					    aStream.pos = priv.offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var privateDict = [];
 | 
					    var privateDict = [];
 | 
				
			||||||
    for (var i = 0; i < priv.size; i++)
 | 
					    for (var i = 0; i < priv.size; i++)
 | 
				
			||||||
      privateDict.push(aStream.getByte());
 | 
					      privateDict.push(aStream.getByte());
 | 
				
			||||||
    dump("private:" + privateDict);
 | 
					    dump('private:' + privateDict);
 | 
				
			||||||
    parseAsToken(privateDict, CFFDictPrivateDataMap);
 | 
					    parseAsToken(privateDict, CFFDictPrivateDataMap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (var p in font.map)
 | 
					    for (var p in font.map)
 | 
				
			||||||
      dump(p + "::" + font.get(p));
 | 
					      dump(p + '::' + font.get(p));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Read CharStrings Index
 | 
					    // Read CharStrings Index
 | 
				
			||||||
    var charStringsOffset = font.get("CharStrings");
 | 
					    var charStringsOffset = font.get('CharStrings');
 | 
				
			||||||
    dump("Read CharStrings Index (offset: " + charStringsOffset + ")");
 | 
					    dump('Read CharStrings Index (offset: ' + charStringsOffset + ')');
 | 
				
			||||||
    aStream.pos = charStringsOffset;
 | 
					    aStream.pos = charStringsOffset;
 | 
				
			||||||
    var charStrings = readFontIndexData(aStream, true);
 | 
					    var charStrings = readFontIndexData(aStream, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Read Charset
 | 
					    // Read Charset
 | 
				
			||||||
    dump("Read Charset for " + charStrings.length + " glyphs");
 | 
					    dump('Read Charset for ' + charStrings.length + ' glyphs');
 | 
				
			||||||
    var charsetEntry = font.get("charset");
 | 
					    var charsetEntry = font.get('charset');
 | 
				
			||||||
    if (charsetEntry == 0) {
 | 
					    if (charsetEntry == 0) {
 | 
				
			||||||
      error("Need to support CFFISOAdobeCharset");
 | 
					      error('Need to support CFFISOAdobeCharset');
 | 
				
			||||||
    } else if (charsetEntry == 1) {
 | 
					    } else if (charsetEntry == 1) {
 | 
				
			||||||
      error("Need to support CFFExpert");
 | 
					      error('Need to support CFFExpert');
 | 
				
			||||||
    } else if (charsetEntry == 2) {
 | 
					    } else if (charsetEntry == 2) {
 | 
				
			||||||
      error("Need to support CFFExpertSubsetCharset");
 | 
					      error('Need to support CFFExpertSubsetCharset');
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      aStream.pos = charsetEntry;
 | 
					      aStream.pos = charsetEntry;
 | 
				
			||||||
      var charset = readCharset(aStream, charStrings);
 | 
					      var charset = readCharset(aStream, charStrings);
 | 
				
			||||||
@ -378,23 +380,23 @@ var Type2Parser = function(aFilePath) {
 | 
				
			|||||||
 * writeToFile(fontData, "/tmp/pdf.js." + fontCount + ".cff");
 | 
					 * writeToFile(fontData, "/tmp/pdf.js." + fontCount + ".cff");
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function writeToFile(aBytes, aFilePath) {
 | 
					function writeToFile(aBytes, aFilePath) {
 | 
				
			||||||
  if (!("netscape" in window))
 | 
					  if (!('netscape' in window))
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 | 
					  netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
 | 
				
			||||||
  var Cc = Components.classes,
 | 
					  var Cc = Components.classes,
 | 
				
			||||||
      Ci = Components.interfaces;
 | 
					      Ci = Components.interfaces;
 | 
				
			||||||
  var file  = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsILocalFile);
 | 
					  var file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsILocalFile);
 | 
				
			||||||
  file.initWithPath(aFilePath);
 | 
					  file.initWithPath(aFilePath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  var stream = Cc["@mozilla.org/network/file-output-stream;1"]
 | 
					  var stream = Cc['@mozilla.org/network/file-output-stream;1']
 | 
				
			||||||
                 .createInstance(Ci.nsIFileOutputStream);
 | 
					                 .createInstance(Ci.nsIFileOutputStream);
 | 
				
			||||||
  stream.init(file, 0x04 | 0x08 | 0x20, 0x180, 0);
 | 
					  stream.init(file, 0x04 | 0x08 | 0x20, 0x180, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  var bos = Cc["@mozilla.org/binaryoutputstream;1"]
 | 
					  var bos = Cc['@mozilla.org/binaryoutputstream;1']
 | 
				
			||||||
              .createInstance(Ci.nsIBinaryOutputStream);
 | 
					              .createInstance(Ci.nsIBinaryOutputStream);
 | 
				
			||||||
  bos.setOutputStream(stream);
 | 
					  bos.setOutputStream(stream);
 | 
				
			||||||
  bos.writeByteArray(aBytes, aBytes.length);
 | 
					  bos.writeByteArray(aBytes, aBytes.length);
 | 
				
			||||||
  stream.close();
 | 
					  stream.close();
 | 
				
			||||||
};
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										111
									
								
								viewer.js
									
									
									
									
									
								
							
							
						
						
									
										111
									
								
								viewer.js
									
									
									
									
									
								
							@ -1,111 +0,0 @@
 | 
				
			|||||||
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- /
 | 
					 | 
				
			||||||
/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
"use strict";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var pdfDocument, canvas, pageScale, pageDisplay, pageNum, numPages;
 | 
					 | 
				
			||||||
function load(userInput) {
 | 
					 | 
				
			||||||
    canvas = document.getElementById("canvas");
 | 
					 | 
				
			||||||
    canvas.mozOpaque = true;
 | 
					 | 
				
			||||||
    pageNum = ("page" in queryParams()) ? parseInt(queryParams().page) : 1;
 | 
					 | 
				
			||||||
    pageScale = ("scale" in queryParams()) ? parseInt(queryParams().scale) : 1.5;
 | 
					 | 
				
			||||||
    var fileName = userInput;
 | 
					 | 
				
			||||||
    if (!userInput) {
 | 
					 | 
				
			||||||
      fileName = queryParams().file || "compressed.tracemonkey-pldi-09.pdf";
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    open(fileName);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function queryParams() {
 | 
					 | 
				
			||||||
    var qs = window.location.search.substring(1);
 | 
					 | 
				
			||||||
    var kvs = qs.split("&");
 | 
					 | 
				
			||||||
    var params = { };
 | 
					 | 
				
			||||||
    for (var i = 0; i < kvs.length; ++i) {
 | 
					 | 
				
			||||||
        var kv = kvs[i].split("=");
 | 
					 | 
				
			||||||
        params[unescape(kv[0])] = unescape(kv[1]);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return params;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function open(url) {
 | 
					 | 
				
			||||||
    document.title = url;
 | 
					 | 
				
			||||||
    var req = new XMLHttpRequest();
 | 
					 | 
				
			||||||
    req.open("GET", url);
 | 
					 | 
				
			||||||
    req.mozResponseType = req.responseType = "arraybuffer";
 | 
					 | 
				
			||||||
    req.expected = (document.URL.indexOf("file:") == 0) ? 0 : 200;
 | 
					 | 
				
			||||||
    req.onreadystatechange = function() {
 | 
					 | 
				
			||||||
      if (req.readyState == 4 && req.status == req.expected) {
 | 
					 | 
				
			||||||
        var data = req.mozResponseArrayBuffer || req.mozResponse ||
 | 
					 | 
				
			||||||
                   req.responseArrayBuffer || req.response;
 | 
					 | 
				
			||||||
        pdfDocument = new PDFDoc(new Stream(data));
 | 
					 | 
				
			||||||
        numPages = pdfDocument.numPages;
 | 
					 | 
				
			||||||
        document.getElementById("numPages").innerHTML = numPages.toString();
 | 
					 | 
				
			||||||
        goToPage(pageNum);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    req.send(null);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function gotoPage(num) {
 | 
					 | 
				
			||||||
    if (0 <= num && num <= numPages)
 | 
					 | 
				
			||||||
        pageNum = num;
 | 
					 | 
				
			||||||
    displayPage(pageNum);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function displayPage(num) {
 | 
					 | 
				
			||||||
    document.getElementById("pageNumber").value = num;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    var t0 = Date.now();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    var page = pdfDocument.getPage(pageNum = num);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    var pdfToCssUnitsCoef = 96.0 / 72.0;
 | 
					 | 
				
			||||||
    var pageWidth = (page.mediaBox[2] - page.mediaBox[0]);
 | 
					 | 
				
			||||||
    var pageHeight = (page.mediaBox[3] - page.mediaBox[1]);
 | 
					 | 
				
			||||||
    canvas.width = pageScale * pageWidth * pdfToCssUnitsCoef;
 | 
					 | 
				
			||||||
    canvas.height = pageScale * pageHeight * pdfToCssUnitsCoef;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    var t1 = Date.now();
 | 
					 | 
				
			||||||
    var ctx = canvas.getContext("2d");
 | 
					 | 
				
			||||||
    ctx.save();
 | 
					 | 
				
			||||||
    ctx.fillStyle = "rgb(255, 255, 255)";
 | 
					 | 
				
			||||||
    ctx.fillRect(0, 0, canvas.width, canvas.height);
 | 
					 | 
				
			||||||
    ctx.restore();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    var gfx = new CanvasGraphics(ctx);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // page.compile will collect all fonts for us, once we have loaded them
 | 
					 | 
				
			||||||
    // we can trigger the actual page rendering with page.display
 | 
					 | 
				
			||||||
    var fonts = [];
 | 
					 | 
				
			||||||
    page.compile(gfx, fonts);
 | 
					 | 
				
			||||||
    var t2 = Date.now();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function displayPage() {
 | 
					 | 
				
			||||||
        var t3 = Date.now();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        page.display(gfx);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        var t4 = Date.now();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        var infoDisplay = document.getElementById("info");
 | 
					 | 
				
			||||||
        infoDisplay.innerHTML = "Time to load/compile/fonts/render: "+ (t1 - t0) + "/" + (t2 - t1) + "/" + (t3 - t2) + "/" + (t4 - t3) + " ms";
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    FontLoader.bind(fonts, displayPage);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function nextPage() {
 | 
					 | 
				
			||||||
    if (pageNum < pdfDocument.numPages)
 | 
					 | 
				
			||||||
      displayPage(++pageNum);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function prevPage() {
 | 
					 | 
				
			||||||
    if (pageNum > 1)
 | 
					 | 
				
			||||||
      displayPage(--pageNum);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function goToPage(num) {
 | 
					 | 
				
			||||||
  if (0 <= num && num <= numPages)
 | 
					 | 
				
			||||||
    displayPage(pageNum = num);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
							
								
								
									
										156
									
								
								web/compatibility.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								web/compatibility.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,156 @@
 | 
				
			|||||||
 | 
					/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 | 
				
			||||||
 | 
					/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Checking if the typed arrays are supported
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  if (typeof Uint8Array !== 'undefined')
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function subarray(start, end) {
 | 
				
			||||||
 | 
					    return this.slice(start, end);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function set_(array, offset) {
 | 
				
			||||||
 | 
					    if (arguments.length < 2) offset = 0;
 | 
				
			||||||
 | 
					    for (var i = 0, n = array.length; i < n; ++i, ++offset)
 | 
				
			||||||
 | 
					      this[offset] = array[i] & 0xFF;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function TypedArray(arg1) {
 | 
				
			||||||
 | 
					    var result;
 | 
				
			||||||
 | 
					    if (typeof arg1 === 'number') {
 | 
				
			||||||
 | 
					       result = new Array(arg1);
 | 
				
			||||||
 | 
					       for (var i = 0; i < arg1; ++i)
 | 
				
			||||||
 | 
					         result[i] = 0;
 | 
				
			||||||
 | 
					    } else
 | 
				
			||||||
 | 
					       result = arg1.slice(0);
 | 
				
			||||||
 | 
					    result.subarray = subarray;
 | 
				
			||||||
 | 
					    result.buffer = result;
 | 
				
			||||||
 | 
					    result.byteLength = result.length;
 | 
				
			||||||
 | 
					    result.set = set_;
 | 
				
			||||||
 | 
					    if (typeof arg1 === 'object' && arg1.buffer)
 | 
				
			||||||
 | 
					      result.buffer = arg1.buffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  window.Uint8Array = TypedArray;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // we don't need support for set, byteLength for 32-bit array
 | 
				
			||||||
 | 
					  // so we can use the TypedArray as well
 | 
				
			||||||
 | 
					  window.Uint32Array = TypedArray;
 | 
				
			||||||
 | 
					  window.Int32Array = TypedArray;
 | 
				
			||||||
 | 
					})();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Object.create() ?
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  if (typeof Object.create !== 'undefined')
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Object.create = function(proto) {
 | 
				
			||||||
 | 
					    var constructor = function() {};
 | 
				
			||||||
 | 
					    constructor.prototype = proto;
 | 
				
			||||||
 | 
					    return new constructor();
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					})();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Object.defineProperty() ?
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  if (typeof Object.defineProperty !== 'undefined')
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Object.defineProperty = function(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() {
 | 
				
			||||||
 | 
					          return value;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        return value;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      obj[name] = def.value;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					})();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// No XMLHttpRequest.response ?
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  var xhrPrototype = XMLHttpRequest.prototype;
 | 
				
			||||||
 | 
					  if ('response' in xhrPrototype ||
 | 
				
			||||||
 | 
					      'mozResponseArrayBuffer' in xhrPrototype ||
 | 
				
			||||||
 | 
					      'mozResponse' in xhrPrototype ||
 | 
				
			||||||
 | 
					      'responseArrayBuffer' in xhrPrototype)
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  // IE ?
 | 
				
			||||||
 | 
					  if (typeof VBArray !== 'undefined') {
 | 
				
			||||||
 | 
					    Object.defineProperty(xhrPrototype, 'response', {
 | 
				
			||||||
 | 
					      get: function() {
 | 
				
			||||||
 | 
					        return new Uint8Array(new VBArray(this.responseBody).toArray());
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // other browsers
 | 
				
			||||||
 | 
					  function responseTypeSetter() {
 | 
				
			||||||
 | 
					    // will be only called to set "arraybuffer"
 | 
				
			||||||
 | 
					    this.overrideMimeType('text/plain; charset=x-user-defined');
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (typeof xhrPrototype.overrideMimeType === 'function') {
 | 
				
			||||||
 | 
					    Object.defineProperty(xhrPrototype, 'responseType',
 | 
				
			||||||
 | 
					                          { set: responseTypeSetter });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  function responseGetter() {
 | 
				
			||||||
 | 
					    var text = this.responseText;
 | 
				
			||||||
 | 
					    var i, n = text.length;
 | 
				
			||||||
 | 
					    var result = new Uint8Array(n);
 | 
				
			||||||
 | 
					    for (i = 0; i < n; ++i)
 | 
				
			||||||
 | 
					      result[i] = text.charCodeAt(i) & 0xFF;
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  Object.defineProperty(xhrPrototype, 'response', { get: responseGetter });
 | 
				
			||||||
 | 
					})();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// window.btoa (base64 encode function) ?
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  if ('btoa' in window)
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  var digits =
 | 
				
			||||||
 | 
					    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  window.btoa = function(chars) {
 | 
				
			||||||
 | 
					    var buffer = '';
 | 
				
			||||||
 | 
					    var i, n;
 | 
				
			||||||
 | 
					    for (i = 0, n = chars.length; i < n; i += 3) {
 | 
				
			||||||
 | 
					      var b1 = chars.charCodeAt(i) & 0xFF;
 | 
				
			||||||
 | 
					      var b2 = chars.charCodeAt(i + 1) & 0xFF;
 | 
				
			||||||
 | 
					      var b3 = chars.charCodeAt(i + 2) & 0xFF;
 | 
				
			||||||
 | 
					      var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4);
 | 
				
			||||||
 | 
					      var d3 = i + 1 < n ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64;
 | 
				
			||||||
 | 
					      var d4 = i + 2 < n ? (b3 & 0x3F) : 64;
 | 
				
			||||||
 | 
					      buffer += (digits.charAt(d1) + digits.charAt(d2) +
 | 
				
			||||||
 | 
					                 digits.charAt(d3) + digits.charAt(d4));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return buffer;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					})();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Function.prototype.bind ?
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  if (typeof Function.prototype.bind !== 'undefined')
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Function.prototype.bind = function(obj) {
 | 
				
			||||||
 | 
					    var fn = this, headArgs = Array.prototype.slice.call(arguments, 1);
 | 
				
			||||||
 | 
					    var binded = function(tailArgs) {
 | 
				
			||||||
 | 
					      var args = headArgs.concat(tailArgs);
 | 
				
			||||||
 | 
					      return fn.apply(obj, args);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    return binded;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					})();
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								web/images/buttons.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								web/images/buttons.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 1.9 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								web/images/source/Buttons.psd.zip
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								web/images/source/Buttons.psd.zip
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										88
									
								
								web/index.html.template
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								web/index.html.template
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,88 @@
 | 
				
			|||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html>
 | 
				
			||||||
 | 
					<head>
 | 
				
			||||||
 | 
					  <meta charset='utf-8'>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <title>andreasgal/pdf.js @ GitHub</title>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <style type="text/css">
 | 
				
			||||||
 | 
					    body {
 | 
				
			||||||
 | 
					      margin-top: 1.0em;
 | 
				
			||||||
 | 
					      background-color: #482a30;
 | 
				
			||||||
 | 
					      font-family: Helvetica, Arial, FreeSans, san-serif;
 | 
				
			||||||
 | 
					      color: #ffffff;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #container {
 | 
				
			||||||
 | 
					      margin: 0 auto;
 | 
				
			||||||
 | 
					      width: 700px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    h1 { font-size: 3.8em; color: #b7d5cf; margin-bottom: 3px; }
 | 
				
			||||||
 | 
					    h1 .small { font-size: 0.4em; }
 | 
				
			||||||
 | 
					    h1 a { text-decoration: none }
 | 
				
			||||||
 | 
					    h2 { font-size: 1.5em; color: #b7d5cf; }
 | 
				
			||||||
 | 
					    h3 { text-align: center; color: #b7d5cf; }
 | 
				
			||||||
 | 
					    a { color: #b7d5cf; }
 | 
				
			||||||
 | 
					    .description { font-size: 1.2em; margin-bottom: 30px; margin-top: 30px; font-style: italic;}
 | 
				
			||||||
 | 
					    .download { float: right; }
 | 
				
			||||||
 | 
					    pre { background: #000; color: #fff; padding: 15px;}
 | 
				
			||||||
 | 
					    hr { border: 0; width: 80%; border-bottom: 1px solid #aaa}
 | 
				
			||||||
 | 
					    .footer { text-align:center; padding-top:30px; font-style: italic; }
 | 
				
			||||||
 | 
					  </style>
 | 
				
			||||||
 | 
					</head>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<body>
 | 
				
			||||||
 | 
					  <a href="http://github.com/andreasgal/pdf.js"><img style="position: absolute; top: 0; right: 0; border: 0;" src="http://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub" /></a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <div id="container">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="download">
 | 
				
			||||||
 | 
					      <a href="http://github.com/andreasgal/pdf.js/zipball/master">
 | 
				
			||||||
 | 
					        <img border="0" width="90" src="http://github.com/images/modules/download/zip.png"></a>
 | 
				
			||||||
 | 
					      <a href="http://github.com/andreasgal/pdf.js/tarball/master">
 | 
				
			||||||
 | 
					        <img border="0" width="90" src="http://github.com/images/modules/download/tar.png"></a>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <h1><a href="http://github.com/andreasgal/pdf.js">pdf.js</a>
 | 
				
			||||||
 | 
					      <span class="small">by <a href="http://github.com/andreasgal">andreasgal</a></span></h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="description">
 | 
				
			||||||
 | 
					      PDF Reader in JavaScript
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <h2>Try it out!</h2>
 | 
				
			||||||
 | 
					    <p>Live <a href="web/multi_page_viewer.html">demo</a> lives here.</p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <h2>Authors</h2>
 | 
				
			||||||
 | 
					<p>Vivien Nicolas (21@vingtetun.org)
 | 
				
			||||||
 | 
					<br/>Andreas Gal (andreas.gal@gmail.com)
 | 
				
			||||||
 | 
					<br/>Soumya Deb (debloper@gmail.com)
 | 
				
			||||||
 | 
					<br/>Chris Jones (jones.chris.g@gmail.com)
 | 
				
			||||||
 | 
					<br/>Justin D'Arcangelo (justindarc@gmail.com)
 | 
				
			||||||
 | 
					<br/>sbarman (sbarman@eecs.berkeley.edu)
 | 
				
			||||||
 | 
					<br/>
 | 
				
			||||||
 | 
					<br/> </p>
 | 
				
			||||||
 | 
					<h2>Contact</h2>
 | 
				
			||||||
 | 
					<p> (andreas.gal@gmail.com)
 | 
				
			||||||
 | 
					<br/> </p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <h2>Download</h2>
 | 
				
			||||||
 | 
					    <p>
 | 
				
			||||||
 | 
					      You can download this project in either
 | 
				
			||||||
 | 
					      <a href="http://github.com/andreasgal/pdf.js/zipball/master">zip</a> or
 | 
				
			||||||
 | 
					      <a href="http://github.com/andreasgal/pdf.js/tarball/master">tar</a> formats.
 | 
				
			||||||
 | 
					    </p>
 | 
				
			||||||
 | 
					    <p>You can also clone the project with <a href="http://git-scm.com">Git</a>
 | 
				
			||||||
 | 
					      by running:
 | 
				
			||||||
 | 
					      <pre>$ git clone git://github.com/andreasgal/pdf.js</pre>
 | 
				
			||||||
 | 
					    </p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="footer">
 | 
				
			||||||
 | 
					      get the source code on GitHub : <a href="http://github.com/andreasgal/pdf.js">andreasgal/pdf.js</a>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										296
									
								
								web/multi_page_viewer.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										296
									
								
								web/multi_page_viewer.css
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,296 @@
 | 
				
			|||||||
 | 
					/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 | 
				
			||||||
 | 
					/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					body {
 | 
				
			||||||
 | 
					  background-color: #929292;
 | 
				
			||||||
 | 
					  font-family: 'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;
 | 
				
			||||||
 | 
					  margin: 0px;
 | 
				
			||||||
 | 
					  padding: 0px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					canvas {
 | 
				
			||||||
 | 
					  box-shadow: 0px 4px 10px #000;
 | 
				
			||||||
 | 
					  -moz-box-shadow: 0px 4px 10px #000;
 | 
				
			||||||
 | 
					  -webkit-box-shadow: 0px 4px 10px #000;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					span {
 | 
				
			||||||
 | 
					  font-size: 0.8em;
 | 
				
			||||||
 | 
					  text-shadow: 0px 1px 0px #fff;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.control {
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  float: left;
 | 
				
			||||||
 | 
					  margin: 0px 20px 0px 0px;
 | 
				
			||||||
 | 
					  padding: 0px 4px 0px 0px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.control > input {
 | 
				
			||||||
 | 
					  float: left;
 | 
				
			||||||
 | 
					  border: 1px solid #4d4d4d;
 | 
				
			||||||
 | 
					  height: 20px;
 | 
				
			||||||
 | 
					  padding: 0px;
 | 
				
			||||||
 | 
					  margin: 0px 2px 0px 0px;
 | 
				
			||||||
 | 
					  border-radius: 3px;
 | 
				
			||||||
 | 
					  -moz-border-radius: 3px;
 | 
				
			||||||
 | 
					  -webkit-border-radius: 3px;
 | 
				
			||||||
 | 
					  box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.3);
 | 
				
			||||||
 | 
					  -moz-box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.3);
 | 
				
			||||||
 | 
					  -webkit-box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.3);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.control > select {
 | 
				
			||||||
 | 
					  float: left;
 | 
				
			||||||
 | 
					  border: 1px solid #4d4d4d;
 | 
				
			||||||
 | 
					  height: 22px;
 | 
				
			||||||
 | 
					  padding: 2px 0px 0px;
 | 
				
			||||||
 | 
					  margin: 0px 0px 1px;
 | 
				
			||||||
 | 
					  border-radius: 3px;
 | 
				
			||||||
 | 
					  -moz-border-radius: 3px;
 | 
				
			||||||
 | 
					  -webkit-border-radius: 3px;
 | 
				
			||||||
 | 
					  box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.3);
 | 
				
			||||||
 | 
					  -moz-box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.3);
 | 
				
			||||||
 | 
					  -webkit-box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.3);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.control > span {
 | 
				
			||||||
 | 
					  cursor: default;
 | 
				
			||||||
 | 
					  float: left;
 | 
				
			||||||
 | 
					  height: 18px;
 | 
				
			||||||
 | 
					  margin: 5px 2px 0px;
 | 
				
			||||||
 | 
					  padding: 0px;
 | 
				
			||||||
 | 
					  user-select: none;
 | 
				
			||||||
 | 
					  -moz-user-select: none;
 | 
				
			||||||
 | 
					  -webkit-user-select: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.control .label {
 | 
				
			||||||
 | 
					  clear: both;
 | 
				
			||||||
 | 
					  float: left;
 | 
				
			||||||
 | 
					  font-size: 0.65em;
 | 
				
			||||||
 | 
					  margin: 2px 0px 0px;
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.thumbnailPageNumber {
 | 
				
			||||||
 | 
					  color: #fff;
 | 
				
			||||||
 | 
					  font-size: 0.55em;
 | 
				
			||||||
 | 
					  text-align: right;
 | 
				
			||||||
 | 
					  margin: -6px 2px 6px 0px;
 | 
				
			||||||
 | 
					  width: 102px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.thumbnail {
 | 
				
			||||||
 | 
					  width: 104px;
 | 
				
			||||||
 | 
					  height: 134px;
 | 
				
			||||||
 | 
					  margin: 0px auto 10px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.page {
 | 
				
			||||||
 | 
					  width: 816px;
 | 
				
			||||||
 | 
					  height: 1056px;
 | 
				
			||||||
 | 
					  margin: 10px auto;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#controls {
 | 
				
			||||||
 | 
					  background-color: #eee;
 | 
				
			||||||
 | 
					  background: -moz-linear-gradient(center bottom, #ddd 0%, #fff 100%);
 | 
				
			||||||
 | 
					  background: -webkit-gradient(linear, left bottom, left top, color-stop(0.0, #ddd), color-stop(1.0, #fff));
 | 
				
			||||||
 | 
					  border-bottom: 1px solid #666;
 | 
				
			||||||
 | 
					  padding: 4px 0px 0px 8px;
 | 
				
			||||||
 | 
					  position: fixed;
 | 
				
			||||||
 | 
					  left: 0px;
 | 
				
			||||||
 | 
					  top: 0px;
 | 
				
			||||||
 | 
					  height: 40px;
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  box-shadow: 0px 2px 8px #000;
 | 
				
			||||||
 | 
					  -moz-box-shadow: 0px 2px 8px #000;
 | 
				
			||||||
 | 
					  -webkit-box-shadow: 0px 2px 8px #000;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#controls input {
 | 
				
			||||||
 | 
					  user-select: text;
 | 
				
			||||||
 | 
					  -moz-user-select: text;
 | 
				
			||||||
 | 
					  -webkit-user-select: text;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					button {
 | 
				
			||||||
 | 
					  background-color: #ddd;
 | 
				
			||||||
 | 
					  background: -moz-linear-gradient(center bottom, #c3c3c3 0%, #f3f3f3 100%);
 | 
				
			||||||
 | 
					  background: -webkit-gradient(linear, left bottom, left top, color-stop(0.0, #c3c3c3), color-stop(1.0, #f3f3f3));
 | 
				
			||||||
 | 
					  border: 1px solid #4d4d4d;
 | 
				
			||||||
 | 
					  cursor: default;
 | 
				
			||||||
 | 
					  float: left;
 | 
				
			||||||
 | 
					  margin: 0px 0px 1px;
 | 
				
			||||||
 | 
					  width: 29px;
 | 
				
			||||||
 | 
					  height: 22px;
 | 
				
			||||||
 | 
						border-radius: 3px;
 | 
				
			||||||
 | 
						-moz-border-radius: 3px;
 | 
				
			||||||
 | 
						-webkit-border-radius: 3px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					button:disabled {
 | 
				
			||||||
 | 
					  background-color: #eee;
 | 
				
			||||||
 | 
					  background: -moz-linear-gradient(center bottom, #ddd 0%, #fff 100%);
 | 
				
			||||||
 | 
					  background: -webkit-gradient(linear, left bottom, left top, color-stop(0.0, #ddd), color-stop(1.0, #fff));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					button:disabled > span {
 | 
				
			||||||
 | 
					  opacity: 0.3;
 | 
				
			||||||
 | 
					  -moz-opacity: 0.3;
 | 
				
			||||||
 | 
					  -webkit-opacity: 0.3;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					button.down {
 | 
				
			||||||
 | 
					  background-color: #777;
 | 
				
			||||||
 | 
					  background: -moz-linear-gradient(center bottom, #888 0%, #555 100%);
 | 
				
			||||||
 | 
					  background: -webkit-gradient(linear, left bottom, left top, color-stop(0.0, #888), color-stop(1.0, #555));
 | 
				
			||||||
 | 
					  box-shadow: inset 0px 0px 2px rgba(0, 0, 0, 0.8);
 | 
				
			||||||
 | 
					  -moz-box-shadow: inset 0px 0px 2px rgba(0, 0, 0, 0.8);
 | 
				
			||||||
 | 
					  -webkit-box-shadow: inset 0px 0px 2px rgba(0, 0, 0, 0.8);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#previousPageButton {
 | 
				
			||||||
 | 
					  width: 28px;
 | 
				
			||||||
 | 
					  border-right: 0px;
 | 
				
			||||||
 | 
					  border-top-right-radius: 0px;
 | 
				
			||||||
 | 
					  border-bottom-right-radius: 0px;
 | 
				
			||||||
 | 
					  -moz-border-radius-topright: 0px;
 | 
				
			||||||
 | 
					  -moz-border-radius-bottomright: 0px;
 | 
				
			||||||
 | 
					  -webkit-border-top-right-radius: 0px;
 | 
				
			||||||
 | 
					  -webkit-border-bottom-right-radius: 0px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#previousPageButton > span {
 | 
				
			||||||
 | 
					  background: url('images/buttons.png') no-repeat 0px 0px;
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  width: 19px;
 | 
				
			||||||
 | 
					  height: 19px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#nextPageButton {
 | 
				
			||||||
 | 
					  width: 28px;
 | 
				
			||||||
 | 
					  border-top-left-radius: 0px;
 | 
				
			||||||
 | 
					  border-bottom-left-radius: 0px;
 | 
				
			||||||
 | 
					  -moz-border-radius-topleft: 0px;
 | 
				
			||||||
 | 
					  -moz-border-radius-bottomleft: 0px;
 | 
				
			||||||
 | 
					  -webkit-border-top-left-radius: 0px;
 | 
				
			||||||
 | 
					  -webkit-border-bottom-left-radius: 0px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#nextPageButton > span {
 | 
				
			||||||
 | 
					  background: url('images/buttons.png') no-repeat -19px 0px;
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  width: 19px;
 | 
				
			||||||
 | 
					  height: 19px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#singleLayoutButton {
 | 
				
			||||||
 | 
					  width: 28px;
 | 
				
			||||||
 | 
					  border-right: 0px;
 | 
				
			||||||
 | 
					  border-top-right-radius: 0px;
 | 
				
			||||||
 | 
					  border-bottom-right-radius: 0px;
 | 
				
			||||||
 | 
					  -moz-border-radius-topright: 0px;
 | 
				
			||||||
 | 
					  -moz-border-radius-bottomright: 0px;
 | 
				
			||||||
 | 
					  -webkit-border-top-right-radius: 0px;
 | 
				
			||||||
 | 
					  -webkit-border-bottom-right-radius: 0px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#singleLayoutButton > span {
 | 
				
			||||||
 | 
					  background: url('images/buttons.png') no-repeat -57px 0px;
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  width: 19px;
 | 
				
			||||||
 | 
					  height: 19px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#splitLayoutButton {
 | 
				
			||||||
 | 
					  width: 28px;
 | 
				
			||||||
 | 
					  border-top-left-radius: 0px;
 | 
				
			||||||
 | 
					  border-bottom-left-radius: 0px;
 | 
				
			||||||
 | 
					  -moz-border-radius-topleft: 0px;
 | 
				
			||||||
 | 
					  -moz-border-radius-bottomleft: 0px;
 | 
				
			||||||
 | 
					  -webkit-border-top-left-radius: 0px;
 | 
				
			||||||
 | 
					  -webkit-border-bottom-left-radius: 0px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#splitLayoutButton > span {
 | 
				
			||||||
 | 
					  background: url('images/buttons.png') no-repeat -76px 0px;
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  width: 19px;
 | 
				
			||||||
 | 
					  height: 19px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#openFileButton {
 | 
				
			||||||
 | 
					  margin-left: 3px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#openFileButton > span {
 | 
				
			||||||
 | 
					  background: url('images/buttons.png') no-repeat -38px 0px;
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  width: 19px;
 | 
				
			||||||
 | 
					  height: 19px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#fileInput {
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pageNumber {
 | 
				
			||||||
 | 
					  text-align: right;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#sidebar {
 | 
				
			||||||
 | 
					  position: fixed;
 | 
				
			||||||
 | 
					  width: 200px;
 | 
				
			||||||
 | 
					  top: 62px;
 | 
				
			||||||
 | 
					  bottom: 18px;
 | 
				
			||||||
 | 
					  left: -140px;
 | 
				
			||||||
 | 
					  transition: left 0.25s ease-in-out 1s;
 | 
				
			||||||
 | 
					  -moz-transition: left 0.25s ease-in-out 1s;
 | 
				
			||||||
 | 
					  -webkit-transition: left 0.25s ease-in-out 1s;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#sidebar:hover {
 | 
				
			||||||
 | 
					  left: 0px;
 | 
				
			||||||
 | 
					  transition: left 0.25s ease-in-out 0s;
 | 
				
			||||||
 | 
					  -moz-transition: left 0.25s ease-in-out 0s;
 | 
				
			||||||
 | 
					  -webkit-transition: left 0.25s ease-in-out 0s;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#sidebarBox {
 | 
				
			||||||
 | 
					  background-color: rgba(0, 0, 0, 0.7);
 | 
				
			||||||
 | 
					  width: 150px;
 | 
				
			||||||
 | 
					  height: 100%;
 | 
				
			||||||
 | 
					  border-top-right-radius: 8px;
 | 
				
			||||||
 | 
					  border-bottom-right-radius: 8px;
 | 
				
			||||||
 | 
					  -moz-border-radius-topright: 8px;
 | 
				
			||||||
 | 
					  -moz-border-radius-bottomright: 8px;
 | 
				
			||||||
 | 
					  -webkit-border-top-right-radius: 8px;
 | 
				
			||||||
 | 
					  -webkit-border-bottom-right-radius: 8px;
 | 
				
			||||||
 | 
					  box-shadow: 0px 2px 8px #000;
 | 
				
			||||||
 | 
					  -moz-box-shadow: 0px 2px 8px #000;
 | 
				
			||||||
 | 
					  -webkit-box-shadow: 0px 2px 8px #000;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#sidebarScrollView {
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					  overflow-y: auto;
 | 
				
			||||||
 | 
					  top: 10px;
 | 
				
			||||||
 | 
					  bottom: 10px;
 | 
				
			||||||
 | 
					  left: 10px;
 | 
				
			||||||
 | 
					  width: 130px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#sidebarContentView {
 | 
				
			||||||
 | 
					  height: auto;
 | 
				
			||||||
 | 
					  width: 100px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#viewer {
 | 
				
			||||||
 | 
					  margin: 44px 0px 0px;
 | 
				
			||||||
 | 
					  padding: 8px 0px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -4,17 +4,18 @@
 | 
				
			|||||||
<title>pdf.js Multi-Page Viewer</title>
 | 
					<title>pdf.js Multi-Page Viewer</title>
 | 
				
			||||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8"/>
 | 
					<meta http-equiv="Content-type" content="text/html;charset=UTF-8"/>
 | 
				
			||||||
<link rel="stylesheet" href="multi_page_viewer.css" type="text/css" media="screen"/>
 | 
					<link rel="stylesheet" href="multi_page_viewer.css" type="text/css" media="screen"/>
 | 
				
			||||||
<script type="text/javascript" src="pdf.js"></script>
 | 
					<script type="text/javascript" src="compatibility.js"></script>
 | 
				
			||||||
<script type="text/javascript" src="fonts.js"></script>
 | 
					<script type="text/javascript" src="../pdf.js"></script>
 | 
				
			||||||
<script type="text/javascript" src="crypto.js"></script>
 | 
					<script type="text/javascript" src="../fonts.js"></script>
 | 
				
			||||||
<script type="text/javascript" src="glyphlist.js"></script>
 | 
					<script type="text/javascript" src="../crypto.js"></script>
 | 
				
			||||||
 | 
					<script type="text/javascript" src="../glyphlist.js"></script>
 | 
				
			||||||
<script type="text/javascript" src="multi_page_viewer.js"></script>
 | 
					<script type="text/javascript" src="multi_page_viewer.js"></script>
 | 
				
			||||||
</head>
 | 
					</head>
 | 
				
			||||||
<body>
 | 
					<body>
 | 
				
			||||||
  <div id="controls">
 | 
					  <div id="controls">
 | 
				
			||||||
    <span class="control">
 | 
					    <span class="control">
 | 
				
			||||||
      <span id="previousPageButton" class="disabled"></span>
 | 
					      <button id="previousPageButton" disabled="disabled"><span></span></button>
 | 
				
			||||||
      <span id="nextPageButton" class="disabled"></span>
 | 
					      <button id="nextPageButton" disabled="disabled"><span></span></button>
 | 
				
			||||||
      <span class="label">Previous/Next</span>
 | 
					      <span class="label">Previous/Next</span>
 | 
				
			||||||
    </span>
 | 
					    </span>
 | 
				
			||||||
    <span class="control">
 | 
					    <span class="control">
 | 
				
			||||||
@ -34,8 +35,18 @@
 | 
				
			|||||||
      </select>
 | 
					      </select>
 | 
				
			||||||
      <span class="label">Zoom</span>
 | 
					      <span class="label">Zoom</span>
 | 
				
			||||||
    </span>
 | 
					    </span>
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    <!-- WIP: Leave commented out until implemented -->
 | 
				
			||||||
 | 
					    <!--
 | 
				
			||||||
    <span class="control">
 | 
					    <span class="control">
 | 
				
			||||||
      <span id="openFileButton"></span>
 | 
					      <button id="singleLayoutButton" class="selected"><span></span></button>
 | 
				
			||||||
 | 
					      <button id="splitLayoutButton"><span></span></button>
 | 
				
			||||||
 | 
					      <span class="label">Page Layout</span>
 | 
				
			||||||
 | 
					    </span>
 | 
				
			||||||
 | 
					    -->
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    <span class="control" id="fileWrapper">
 | 
				
			||||||
 | 
					      <button id="openFileButton"><span></span></button>
 | 
				
			||||||
      <input type="file" id="fileInput"/>
 | 
					      <input type="file" id="fileInput"/>
 | 
				
			||||||
      <span class="label">Open File</span>
 | 
					      <span class="label">Open File</span>
 | 
				
			||||||
    </span>
 | 
					    </span>
 | 
				
			||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 | 
					/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 | 
				
			||||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
					/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"use strict";
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var pageTimeout;
 | 
					var pageTimeout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -43,7 +43,7 @@ var PDFViewer = {
 | 
				
			|||||||
  lastPagesDrawn: [],
 | 
					  lastPagesDrawn: [],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  visiblePages: function() {
 | 
					  visiblePages: function() {
 | 
				
			||||||
    const pageBottomMargin = 10;
 | 
					    var pageBottomMargin = 10;
 | 
				
			||||||
    var windowTop = window.pageYOffset;
 | 
					    var windowTop = window.pageYOffset;
 | 
				
			||||||
    var windowBottom = window.pageYOffset + window.innerHeight;
 | 
					    var windowBottom = window.pageYOffset + window.innerHeight;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -123,14 +123,7 @@ var PDFViewer = {
 | 
				
			|||||||
      ctx.fillRect(0, 0, canvas.width, canvas.height);
 | 
					      ctx.fillRect(0, 0, canvas.width, canvas.height);
 | 
				
			||||||
      ctx.restore();
 | 
					      ctx.restore();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      var gfx = new CanvasGraphics(ctx);
 | 
					      page.startRendering(ctx, function() { });
 | 
				
			||||||
 | 
					 | 
				
			||||||
      // page.compile will collect all fonts for us, once we have loaded them
 | 
					 | 
				
			||||||
      // we can trigger the actual page rendering with page.display
 | 
					 | 
				
			||||||
      var fonts = [];
 | 
					 | 
				
			||||||
      page.compile(gfx, fonts);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      FontLoader.bind(fonts, function() { page.display(gfx); });
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -183,14 +176,7 @@ var PDFViewer = {
 | 
				
			|||||||
      ctx.fillRect(0, 0, canvas.width, canvas.height);
 | 
					      ctx.fillRect(0, 0, canvas.width, canvas.height);
 | 
				
			||||||
      ctx.restore();
 | 
					      ctx.restore();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      var gfx = new CanvasGraphics(ctx);
 | 
					      page.startRendering(ctx, function() { });
 | 
				
			||||||
 | 
					 | 
				
			||||||
      // page.compile will collect all fonts for us, once we have loaded them
 | 
					 | 
				
			||||||
      // we can trigger the actual page rendering with page.display
 | 
					 | 
				
			||||||
      var fonts = [];
 | 
					 | 
				
			||||||
      page.compile(gfx, fonts);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      FontLoader.bind(fonts, function() { page.display(gfx); });
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -243,8 +229,8 @@ var PDFViewer = {
 | 
				
			|||||||
        setTimeout(window.onscroll, 0);
 | 
					        setTimeout(window.onscroll, 0);
 | 
				
			||||||
      document.location.hash = PDFViewer.pageNumber;
 | 
					      document.location.hash = PDFViewer.pageNumber;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : '';
 | 
					      PDFViewer.previousPageButton.disabled = (PDFViewer.pageNumber === 1);
 | 
				
			||||||
      PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : '';
 | 
					      PDFViewer.nextPageButton.disabled = (PDFViewer.pageNumber === PDFViewer.numberOfPages);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -277,7 +263,8 @@ var PDFViewer = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    req.onreadystatechange = function() {
 | 
					    req.onreadystatechange = function() {
 | 
				
			||||||
      if (req.readyState === 4 && req.status === req.expected) {
 | 
					      if (req.readyState === 4 && req.status === req.expected) {
 | 
				
			||||||
        var data = req.mozResponseArrayBuffer || req.mozResponse || req.responseArrayBuffer || req.response;
 | 
					        var data = (req.mozResponseArrayBuffer || req.mozResponse ||
 | 
				
			||||||
 | 
					                    req.responseArrayBuffer || req.response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        PDFViewer.readPDF(data);
 | 
					        PDFViewer.readPDF(data);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -294,12 +281,15 @@ var PDFViewer = {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (PDFViewer.sidebarContentView.hasChildNodes()) {
 | 
					    while (PDFViewer.sidebarContentView.hasChildNodes()) {
 | 
				
			||||||
      PDFViewer.sidebarContentView.removeChild(PDFViewer.sidebarContentView.firstChild);
 | 
					      PDFViewer.sidebarContentView.removeChild(
 | 
				
			||||||
 | 
					        PDFViewer.sidebarContentView.firstChild
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    PDFViewer.pdf = new PDFDoc(new Stream(data));
 | 
					    PDFViewer.pdf = new PDFDoc(new Stream(data));
 | 
				
			||||||
    PDFViewer.numberOfPages = PDFViewer.pdf.numPages;
 | 
					    PDFViewer.numberOfPages = PDFViewer.pdf.numPages;
 | 
				
			||||||
    document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString();
 | 
					    document.getElementById('numPages').innerHTML =
 | 
				
			||||||
 | 
					      PDFViewer.numberOfPages.toString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (var i = 1; i <= PDFViewer.numberOfPages; i++) {
 | 
					    for (var i = 1; i <= PDFViewer.numberOfPages; i++) {
 | 
				
			||||||
      PDFViewer.createPage(i);
 | 
					      PDFViewer.createPage(i);
 | 
				
			||||||
@ -327,8 +317,8 @@ var PDFViewer = {
 | 
				
			|||||||
      }).bind(this), 500);
 | 
					      }).bind(this), 500);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : '';
 | 
					    PDFViewer.previousPageButton.disabled = (PDFViewer.pageNumber === 1);
 | 
				
			||||||
    PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : '';
 | 
					    PDFViewer.nextPageButton.disabled = (PDFViewer.pageNumber === PDFViewer.numberOfPages);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -396,38 +386,30 @@ window.onload = function() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  PDFViewer.previousPageButton = document.getElementById('previousPageButton');
 | 
					  PDFViewer.previousPageButton = document.getElementById('previousPageButton');
 | 
				
			||||||
  PDFViewer.previousPageButton.onclick = function(evt) {
 | 
					  PDFViewer.previousPageButton.onclick = function(evt) {
 | 
				
			||||||
    if (this.className.indexOf('disabled') === -1) {
 | 
					    PDFViewer.goToPreviousPage();
 | 
				
			||||||
      PDFViewer.goToPreviousPage();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  PDFViewer.previousPageButton.onmousedown = function(evt) {
 | 
					  PDFViewer.previousPageButton.onmousedown = function(evt) {
 | 
				
			||||||
    if (this.className.indexOf('disabled') === -1) {
 | 
					    this.className = 'down';
 | 
				
			||||||
      this.className = 'down';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  PDFViewer.previousPageButton.onmouseup = function(evt) {
 | 
					  PDFViewer.previousPageButton.onmouseup = function(evt) {
 | 
				
			||||||
    this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : '';
 | 
					    this.className = '';
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  PDFViewer.previousPageButton.onmouseout = function(evt) {
 | 
					  PDFViewer.previousPageButton.onmouseout = function(evt) {
 | 
				
			||||||
    this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : '';
 | 
					    this.className = '';
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  PDFViewer.nextPageButton = document.getElementById('nextPageButton');
 | 
					  PDFViewer.nextPageButton = document.getElementById('nextPageButton');
 | 
				
			||||||
  PDFViewer.nextPageButton.onclick = function(evt) {
 | 
					  PDFViewer.nextPageButton.onclick = function(evt) {
 | 
				
			||||||
    if (this.className.indexOf('disabled') === -1) {
 | 
					    PDFViewer.goToNextPage();
 | 
				
			||||||
      PDFViewer.goToNextPage();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  PDFViewer.nextPageButton.onmousedown = function(evt) {
 | 
					  PDFViewer.nextPageButton.onmousedown = function(evt) {
 | 
				
			||||||
    if (this.className.indexOf('disabled') === -1) {
 | 
					    this.className = 'down';
 | 
				
			||||||
      this.className = 'down';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  PDFViewer.nextPageButton.onmouseup = function(evt) {
 | 
					  PDFViewer.nextPageButton.onmouseup = function(evt) {
 | 
				
			||||||
    this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : '';
 | 
					    this.className = '';
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  PDFViewer.nextPageButton.onmouseout = function(evt) {
 | 
					  PDFViewer.nextPageButton.onmouseout = function(evt) {
 | 
				
			||||||
    this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : '';
 | 
					    this.className = '';
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  PDFViewer.scaleSelect = document.getElementById('scaleSelect');
 | 
					  PDFViewer.scaleSelect = document.getElementById('scaleSelect');
 | 
				
			||||||
@ -438,20 +420,16 @@ window.onload = function() {
 | 
				
			|||||||
  if (window.File && window.FileReader && window.FileList && window.Blob) {
 | 
					  if (window.File && window.FileReader && window.FileList && window.Blob) {
 | 
				
			||||||
    var openFileButton = document.getElementById('openFileButton');
 | 
					    var openFileButton = document.getElementById('openFileButton');
 | 
				
			||||||
    openFileButton.onclick = function(evt) {
 | 
					    openFileButton.onclick = function(evt) {
 | 
				
			||||||
      if (this.className.indexOf('disabled') === -1) {
 | 
					      PDFViewer.fileInput.click();
 | 
				
			||||||
        PDFViewer.fileInput.click();
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    openFileButton.onmousedown = function(evt) {
 | 
					    openFileButton.onmousedown = function(evt) {
 | 
				
			||||||
      if (this.className.indexOf('disabled') === -1) {
 | 
					      this.className = 'down';
 | 
				
			||||||
        this.className = 'down';
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    openFileButton.onmouseup = function(evt) {
 | 
					    openFileButton.onmouseup = function(evt) {
 | 
				
			||||||
      this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : '';
 | 
					      this.className = '';
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    openFileButton.onmouseout = function(evt) {
 | 
					    openFileButton.onmouseout = function(evt) {
 | 
				
			||||||
      this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : '';
 | 
					      this.className = '';
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    PDFViewer.fileInput = document.getElementById('fileInput');
 | 
					    PDFViewer.fileInput = document.getElementById('fileInput');
 | 
				
			||||||
@ -487,7 +465,8 @@ window.onload = function() {
 | 
				
			|||||||
    document.getElementById('fileWrapper').style.display = 'none';
 | 
					    document.getElementById('fileWrapper').style.display = 'none';
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber;
 | 
					  PDFViewer.pageNumber =
 | 
				
			||||||
 | 
					    parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber;
 | 
				
			||||||
  PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0;
 | 
					  PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  PDFViewer.openURL(PDFViewer.queryParams.file || PDFViewer.url);
 | 
					  PDFViewer.openURL(PDFViewer.queryParams.file || PDFViewer.url);
 | 
				
			||||||
@ -525,8 +504,8 @@ window.onload = function() {
 | 
				
			|||||||
    // Update the page number input with the current page number.
 | 
					    // Update the page number input with the current page number.
 | 
				
			||||||
    if (!PDFViewer.willJumpToPage && visiblePages.length > 0) {
 | 
					    if (!PDFViewer.willJumpToPage && visiblePages.length > 0) {
 | 
				
			||||||
      PDFViewer.pageNumber = PDFViewer.pageNumberInput.value = visiblePages[0];
 | 
					      PDFViewer.pageNumber = PDFViewer.pageNumberInput.value = visiblePages[0];
 | 
				
			||||||
      PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ? 'disabled' : '';
 | 
					      PDFViewer.previousPageButton.disabled = (PDFViewer.pageNumber === 1);
 | 
				
			||||||
      PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ? 'disabled' : '';
 | 
					      PDFViewer.nextPageButton.disabled = (PDFViewer.pageNumber === PDFViewer.numberOfPages);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      PDFViewer.willJumpToPage = false;
 | 
					      PDFViewer.willJumpToPage = false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -1,14 +1,15 @@
 | 
				
			|||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
<html>
 | 
					<html>
 | 
				
			||||||
    <head>
 | 
					    <head>
 | 
				
			||||||
        <title>Simple pdf.js page viewer</title>
 | 
					        <title>Simple pdf.js page viewer</title>
 | 
				
			||||||
        <link rel="stylesheet" href="viewer.css"></link>
 | 
					        <link rel="stylesheet" href="viewer.css"></link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <script type="text/javascript" src="compatibility.js"></script>
 | 
				
			||||||
        <script type="text/javascript" src="viewer.js"></script>
 | 
					        <script type="text/javascript" src="viewer.js"></script>
 | 
				
			||||||
        <script type="text/javascript" src="pdf.js"></script>
 | 
					        <script type="text/javascript" src="../pdf.js"></script>
 | 
				
			||||||
        <script type="text/javascript" src="utils/fonts_utils.js"></script>
 | 
					        <script type="text/javascript" src="../fonts.js"></script>
 | 
				
			||||||
        <script type="text/javascript" src="fonts.js"></script>
 | 
					        <script type="text/javascript" src="../crypto.js"></script>
 | 
				
			||||||
        <script type="text/javascript" src="crypto.js"></script>
 | 
					        <script type="text/javascript" src="../glyphlist.js"></script>
 | 
				
			||||||
        <script type="text/javascript" src="glyphlist.js"></script>
 | 
					 | 
				
			||||||
  </head>
 | 
					  </head>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <body onload="load();">
 | 
					  <body onload="load();">
 | 
				
			||||||
							
								
								
									
										99
									
								
								web/viewer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								web/viewer.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,99 @@
 | 
				
			|||||||
 | 
					/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 | 
				
			||||||
 | 
					/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var pdfDocument, canvas, pageScale, pageDisplay, pageNum, numPages;
 | 
				
			||||||
 | 
					function load(userInput) {
 | 
				
			||||||
 | 
					  canvas = document.getElementById('canvas');
 | 
				
			||||||
 | 
					  canvas.mozOpaque = true;
 | 
				
			||||||
 | 
					  pageNum = ('page' in queryParams()) ? parseInt(queryParams().page) : 1;
 | 
				
			||||||
 | 
					  pageScale = ('scale' in queryParams()) ? parseInt(queryParams().scale) : 1.5;
 | 
				
			||||||
 | 
					  var fileName = userInput;
 | 
				
			||||||
 | 
					  if (!userInput) {
 | 
				
			||||||
 | 
					    fileName = queryParams().file || 'compressed.tracemonkey-pldi-09.pdf';
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  open(fileName);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function queryParams() {
 | 
				
			||||||
 | 
					  var qs = window.location.search.substring(1);
 | 
				
			||||||
 | 
					  var kvs = qs.split('&');
 | 
				
			||||||
 | 
					  var params = { };
 | 
				
			||||||
 | 
					  for (var i = 0; i < kvs.length; ++i) {
 | 
				
			||||||
 | 
					    var kv = kvs[i].split('=');
 | 
				
			||||||
 | 
					    params[unescape(kv[0])] = unescape(kv[1]);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return params;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function open(url) {
 | 
				
			||||||
 | 
					  document.title = url;
 | 
				
			||||||
 | 
					  var req = new XMLHttpRequest();
 | 
				
			||||||
 | 
					  req.open('GET', url);
 | 
				
			||||||
 | 
					  req.mozResponseType = req.responseType = 'arraybuffer';
 | 
				
			||||||
 | 
					  req.expected = (document.URL.indexOf('file:') == 0) ? 0 : 200;
 | 
				
			||||||
 | 
					  req.onreadystatechange = function() {
 | 
				
			||||||
 | 
					    if (req.readyState == 4 && req.status == req.expected) {
 | 
				
			||||||
 | 
					      var data = (req.mozResponseArrayBuffer || req.mozResponse ||
 | 
				
			||||||
 | 
					                  req.responseArrayBuffer || req.response);
 | 
				
			||||||
 | 
					      pdfDocument = new PDFDoc(new Stream(data));
 | 
				
			||||||
 | 
					      numPages = pdfDocument.numPages;
 | 
				
			||||||
 | 
					      document.getElementById('numPages').innerHTML = numPages.toString();
 | 
				
			||||||
 | 
					      goToPage(pageNum);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  req.send(null);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function gotoPage(num) {
 | 
				
			||||||
 | 
					  if (0 <= num && num <= numPages)
 | 
				
			||||||
 | 
					    pageNum = num;
 | 
				
			||||||
 | 
					  displayPage(pageNum);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function displayPage(num) {
 | 
				
			||||||
 | 
					  document.getElementById('pageNumber').value = num;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  var t0 = Date.now();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  var page = pdfDocument.getPage(pageNum = num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  var pdfToCssUnitsCoef = 96.0 / 72.0;
 | 
				
			||||||
 | 
					  var pageWidth = (page.mediaBox[2] - page.mediaBox[0]);
 | 
				
			||||||
 | 
					  var pageHeight = (page.mediaBox[3] - page.mediaBox[1]);
 | 
				
			||||||
 | 
					  canvas.width = pageScale * pageWidth * pdfToCssUnitsCoef;
 | 
				
			||||||
 | 
					  canvas.height = pageScale * pageHeight * pdfToCssUnitsCoef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  var t1 = Date.now();
 | 
				
			||||||
 | 
					  var ctx = canvas.getContext('2d');
 | 
				
			||||||
 | 
					  ctx.save();
 | 
				
			||||||
 | 
					  ctx.fillStyle = 'rgb(255, 255, 255)';
 | 
				
			||||||
 | 
					  ctx.fillRect(0, 0, canvas.width, canvas.height);
 | 
				
			||||||
 | 
					  ctx.restore();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  page.startRendering(
 | 
				
			||||||
 | 
					    ctx,
 | 
				
			||||||
 | 
					    function() {
 | 
				
			||||||
 | 
					      var infoDisplay = document.getElementById('info');
 | 
				
			||||||
 | 
					      var stats = page.stats;
 | 
				
			||||||
 | 
					      var t2 = stats.compile, t3 = stats.fonts, t4 = stats.render;
 | 
				
			||||||
 | 
					      infoDisplay.innerHTML = 'Time to load/compile/fonts/render: ' +
 | 
				
			||||||
 | 
					        (t1 - t0) + '/' + (t2 - t1) + '/' + (t3 - t2) + '/' + (t4 - t3) + ' ms';
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function nextPage() {
 | 
				
			||||||
 | 
					  if (pageNum < pdfDocument.numPages)
 | 
				
			||||||
 | 
					    displayPage(++pageNum);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function prevPage() {
 | 
				
			||||||
 | 
					  if (pageNum > 1)
 | 
				
			||||||
 | 
					    displayPage(--pageNum);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function goToPage(num) {
 | 
				
			||||||
 | 
					  if (0 <= num && num <= numPages)
 | 
				
			||||||
 | 
					    displayPage(pageNum = num);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,10 +1,10 @@
 | 
				
			|||||||
<html>
 | 
					<html>
 | 
				
			||||||
    <head>
 | 
					    <head>
 | 
				
			||||||
        <title>Simple pdf.js page worker viewer</title>
 | 
					        <title>Simple pdf.js page worker viewer</title>
 | 
				
			||||||
        <script type="text/javascript" src="fonts.js"></script>
 | 
					        <script type="text/javascript" src="../fonts.js"></script>
 | 
				
			||||||
        <script type="text/javascript" src="glyphlist.js"></script>
 | 
					        <script type="text/javascript" src="../glyphlist.js"></script>
 | 
				
			||||||
        <script type="text/javascript" src="pdf.js"></script>
 | 
					        <script type="text/javascript" src="../pdf.js"></script>
 | 
				
			||||||
        <script type="text/javascript" src="worker/client.js"></script>
 | 
					        <script type="text/javascript" src="../worker/client.js"></script>
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										169
									
								
								worker/canvas.js
									
									
									
									
									
								
							
							
						
						
									
										169
									
								
								worker/canvas.js
									
									
									
									
									
								
							@ -1,7 +1,7 @@
 | 
				
			|||||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 | 
					/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 | 
				
			||||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
					/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"use strict";
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var JpegStreamProxyCounter = 0;
 | 
					var JpegStreamProxyCounter = 0;
 | 
				
			||||||
// WebWorker Proxy for JpegStream.
 | 
					// WebWorker Proxy for JpegStream.
 | 
				
			||||||
@ -12,7 +12,7 @@ var JpegStreamProxy = (function() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Tell the main thread to create an image.
 | 
					    // Tell the main thread to create an image.
 | 
				
			||||||
    postMessage({
 | 
					    postMessage({
 | 
				
			||||||
      action: "jpeg_stream",
 | 
					      action: 'jpeg_stream',
 | 
				
			||||||
      data: {
 | 
					      data: {
 | 
				
			||||||
        id: this.id,
 | 
					        id: this.id,
 | 
				
			||||||
        raw: bytesToString(bytes)
 | 
					        raw: bytesToString(bytes)
 | 
				
			||||||
@ -25,7 +25,7 @@ var JpegStreamProxy = (function() {
 | 
				
			|||||||
      return this;
 | 
					      return this;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    getChar: function() {
 | 
					    getChar: function() {
 | 
				
			||||||
      error("internal error: getChar is not valid on JpegStream");
 | 
					      error('internal error: getChar is not valid on JpegStream');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -36,9 +36,9 @@ var JpegStreamProxy = (function() {
 | 
				
			|||||||
// the time, meaning you can't create a gradient, create a second one and then
 | 
					// the time, meaning you can't create a gradient, create a second one and then
 | 
				
			||||||
// use the first one again. As this isn't used in pdf.js right now, it's okay.
 | 
					// use the first one again. As this isn't used in pdf.js right now, it's okay.
 | 
				
			||||||
function GradientProxy(cmdQueue, x0, y0, x1, y1) {
 | 
					function GradientProxy(cmdQueue, x0, y0, x1, y1) {
 | 
				
			||||||
  cmdQueue.push(["$createLinearGradient", [x0, y0, x1, y1]]);
 | 
					  cmdQueue.push(['$createLinearGradient', [x0, y0, x1, y1]]);
 | 
				
			||||||
  this.addColorStop = function(i, rgba) {
 | 
					  this.addColorStop = function(i, rgba) {
 | 
				
			||||||
    cmdQueue.push(["$addColorStop", [i, rgba]]);
 | 
					    cmdQueue.push(['$addColorStop', [i, rgba]]);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -47,15 +47,15 @@ var patternProxyCounter = 0;
 | 
				
			|||||||
function PatternProxy(cmdQueue, object, kind) {
 | 
					function PatternProxy(cmdQueue, object, kind) {
 | 
				
			||||||
  this.id = patternProxyCounter++;
 | 
					  this.id = patternProxyCounter++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!(object instanceof CanvasProxy) ) {
 | 
					  if (!(object instanceof CanvasProxy)) {
 | 
				
			||||||
    throw "unkown type to createPattern";
 | 
					    throw 'unkown type to createPattern';
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Flush the object here to ensure it's available on the main thread.
 | 
					  // Flush the object here to ensure it's available on the main thread.
 | 
				
			||||||
  // TODO: Make some kind of dependency management, such that the object
 | 
					  // TODO: Make some kind of dependency management, such that the object
 | 
				
			||||||
  // gets flushed only if needed.
 | 
					  // gets flushed only if needed.
 | 
				
			||||||
  object.flush();
 | 
					  object.flush();
 | 
				
			||||||
  cmdQueue.push(["$createPatternFromCanvas", [this.id, object.id, kind]]);
 | 
					  cmdQueue.push(['$createPatternFromCanvas', [this.id, object.id, kind]]);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var canvasProxyCounter = 0;
 | 
					var canvasProxyCounter = 0;
 | 
				
			||||||
@ -68,8 +68,8 @@ function CanvasProxy(width, height) {
 | 
				
			|||||||
  // Dummy context that gets exposed.
 | 
					  // Dummy context that gets exposed.
 | 
				
			||||||
  var ctx = {};
 | 
					  var ctx = {};
 | 
				
			||||||
  this.getContext = function(type) {
 | 
					  this.getContext = function(type) {
 | 
				
			||||||
    if (type != "2d") {
 | 
					    if (type != '2d') {
 | 
				
			||||||
      throw "CanvasProxy can only provide a 2d context.";
 | 
					      throw 'CanvasProxy can only provide a 2d context.';
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return ctx;
 | 
					    return ctx;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -82,45 +82,45 @@ function CanvasProxy(width, height) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // Setup function calls to `ctx`.
 | 
					  // Setup function calls to `ctx`.
 | 
				
			||||||
  var ctxFunc = [
 | 
					  var ctxFunc = [
 | 
				
			||||||
  "createRadialGradient",
 | 
					  'createRadialGradient',
 | 
				
			||||||
  "arcTo",
 | 
					  'arcTo',
 | 
				
			||||||
  "arc",
 | 
					  'arc',
 | 
				
			||||||
  "fillText",
 | 
					  'fillText',
 | 
				
			||||||
  "strokeText",
 | 
					  'strokeText',
 | 
				
			||||||
  "createImageData",
 | 
					  'createImageData',
 | 
				
			||||||
  "drawWindow",
 | 
					  'drawWindow',
 | 
				
			||||||
  "save",
 | 
					  'save',
 | 
				
			||||||
  "restore",
 | 
					  'restore',
 | 
				
			||||||
  "scale",
 | 
					  'scale',
 | 
				
			||||||
  "rotate",
 | 
					  'rotate',
 | 
				
			||||||
  "translate",
 | 
					  'translate',
 | 
				
			||||||
  "transform",
 | 
					  'transform',
 | 
				
			||||||
  "setTransform",
 | 
					  'setTransform',
 | 
				
			||||||
  "clearRect",
 | 
					  'clearRect',
 | 
				
			||||||
  "fillRect",
 | 
					  'fillRect',
 | 
				
			||||||
  "strokeRect",
 | 
					  'strokeRect',
 | 
				
			||||||
  "beginPath",
 | 
					  'beginPath',
 | 
				
			||||||
  "closePath",
 | 
					  'closePath',
 | 
				
			||||||
  "moveTo",
 | 
					  'moveTo',
 | 
				
			||||||
  "lineTo",
 | 
					  'lineTo',
 | 
				
			||||||
  "quadraticCurveTo",
 | 
					  'quadraticCurveTo',
 | 
				
			||||||
  "bezierCurveTo",
 | 
					  'bezierCurveTo',
 | 
				
			||||||
  "rect",
 | 
					  'rect',
 | 
				
			||||||
  "fill",
 | 
					  'fill',
 | 
				
			||||||
  "stroke",
 | 
					  'stroke',
 | 
				
			||||||
  "clip",
 | 
					  'clip',
 | 
				
			||||||
  "measureText",
 | 
					  'measureText',
 | 
				
			||||||
  "isPointInPath",
 | 
					  'isPointInPath',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // These functions are necessary to track the rendering currentX state.
 | 
					  // These functions are necessary to track the rendering currentX state.
 | 
				
			||||||
  // The exact values can be computed on the main thread only, as the
 | 
					  // The exact values can be computed on the main thread only, as the
 | 
				
			||||||
  // worker has no idea about text width.
 | 
					  // worker has no idea about text width.
 | 
				
			||||||
  "$setCurrentX",
 | 
					  '$setCurrentX',
 | 
				
			||||||
  "$addCurrentX",
 | 
					  '$addCurrentX',
 | 
				
			||||||
  "$saveCurrentX",
 | 
					  '$saveCurrentX',
 | 
				
			||||||
  "$restoreCurrentX",
 | 
					  '$restoreCurrentX',
 | 
				
			||||||
  "$showText",
 | 
					  '$showText',
 | 
				
			||||||
  "$setFont"
 | 
					  '$setFont'
 | 
				
			||||||
  ];
 | 
					  ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function buildFuncCall(name) {
 | 
					  function buildFuncCall(name) {
 | 
				
			||||||
@ -154,53 +154,54 @@ function CanvasProxy(width, height) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ctx.putImageData = function(data, x, y, width, height) {
 | 
					  ctx.putImageData = function(data, x, y, width, height) {
 | 
				
			||||||
    cmdQueue.push(["$putImageData", [data, x, y, width, height]]);
 | 
					    cmdQueue.push(['$putImageData', [data, x, y, width, height]]);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ctx.drawImage = function(image, x, y, width, height, sx, sy, swidth, sheight) {
 | 
					  ctx.drawImage = function(image, x, y, width, height,
 | 
				
			||||||
 | 
					                           sx, sy, swidth, sheight) {
 | 
				
			||||||
    if (image instanceof CanvasProxy) {
 | 
					    if (image instanceof CanvasProxy) {
 | 
				
			||||||
      // Send the image/CanvasProxy to the main thread.
 | 
					      // Send the image/CanvasProxy to the main thread.
 | 
				
			||||||
      image.flush();
 | 
					      image.flush();
 | 
				
			||||||
      cmdQueue.push(["$drawCanvas", [image.id, x, y, sx, sy, swidth, sheight]]);
 | 
					      cmdQueue.push(['$drawCanvas', [image.id, x, y, sx, sy, swidth, sheight]]);
 | 
				
			||||||
    } else if(image instanceof JpegStreamProxy) {
 | 
					    } else if (image instanceof JpegStreamProxy) {
 | 
				
			||||||
      cmdQueue.push(["$drawImage", [image.id, x, y, sx, sy, swidth, sheight]])
 | 
					      cmdQueue.push(['$drawImage', [image.id, x, y, sx, sy, swidth, sheight]]);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      throw "unkown type to drawImage";
 | 
					      throw 'unkown type to drawImage';
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Setup property access to `ctx`.
 | 
					  // Setup property access to `ctx`.
 | 
				
			||||||
  var ctxProp = {
 | 
					  var ctxProp = {
 | 
				
			||||||
    // "canvas"
 | 
					    // "canvas"
 | 
				
			||||||
    "globalAlpha": "1",
 | 
					    'globalAlpha': '1',
 | 
				
			||||||
    "globalCompositeOperation": "source-over",
 | 
					    'globalCompositeOperation': 'source-over',
 | 
				
			||||||
    "strokeStyle": "#000000",
 | 
					    'strokeStyle': '#000000',
 | 
				
			||||||
    "fillStyle": "#000000",
 | 
					    'fillStyle': '#000000',
 | 
				
			||||||
    "lineWidth": "1",
 | 
					    'lineWidth': '1',
 | 
				
			||||||
    "lineCap": "butt",
 | 
					    'lineCap': 'butt',
 | 
				
			||||||
    "lineJoin": "miter",
 | 
					    'lineJoin': 'miter',
 | 
				
			||||||
    "miterLimit": "10",
 | 
					    'miterLimit': '10',
 | 
				
			||||||
    "shadowOffsetX": "0",
 | 
					    'shadowOffsetX': '0',
 | 
				
			||||||
    "shadowOffsetY": "0",
 | 
					    'shadowOffsetY': '0',
 | 
				
			||||||
    "shadowBlur": "0",
 | 
					    'shadowBlur': '0',
 | 
				
			||||||
    "shadowColor": "rgba(0, 0, 0, 0)",
 | 
					    'shadowColor': 'rgba(0, 0, 0, 0)',
 | 
				
			||||||
    "font": "10px sans-serif",
 | 
					    'font': '10px sans-serif',
 | 
				
			||||||
    "textAlign": "start",
 | 
					    'textAlign': 'start',
 | 
				
			||||||
    "textBaseline": "alphabetic",
 | 
					    'textBaseline': 'alphabetic',
 | 
				
			||||||
    "mozTextStyle": "10px sans-serif",
 | 
					    'mozTextStyle': '10px sans-serif',
 | 
				
			||||||
    "mozImageSmoothingEnabled": "true"
 | 
					    'mozImageSmoothingEnabled': 'true'
 | 
				
			||||||
  }
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function buildGetter(name) {
 | 
					  function buildGetter(name) {
 | 
				
			||||||
    return function() {
 | 
					    return function() {
 | 
				
			||||||
      return ctx["$" + name];
 | 
					      return ctx['$' + name];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function buildSetter(name) {
 | 
					  function buildSetter(name) {
 | 
				
			||||||
    return function(value) {
 | 
					    return function(value) {
 | 
				
			||||||
      cmdQueue.push(["$", name, value]);
 | 
					      cmdQueue.push(['$', name, value]);
 | 
				
			||||||
      return ctx["$" + name] = value;
 | 
					      return ctx['$' + name] = value;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -209,23 +210,23 @@ function CanvasProxy(width, height) {
 | 
				
			|||||||
  function buildSetterStyle(name) {
 | 
					  function buildSetterStyle(name) {
 | 
				
			||||||
    return function(value) {
 | 
					    return function(value) {
 | 
				
			||||||
      if (value instanceof GradientProxy) {
 | 
					      if (value instanceof GradientProxy) {
 | 
				
			||||||
        cmdQueue.push(["$" + name + "Gradient"]);
 | 
					        cmdQueue.push(['$' + name + 'Gradient']);
 | 
				
			||||||
      } else if (value instanceof PatternProxy) {
 | 
					      } else if (value instanceof PatternProxy) {
 | 
				
			||||||
        cmdQueue.push(["$" + name + "Pattern", [value.id]]);
 | 
					        cmdQueue.push(['$' + name + 'Pattern', [value.id]]);
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        cmdQueue.push(["$", name, value]);
 | 
					        cmdQueue.push(['$', name, value]);
 | 
				
			||||||
        return ctx["$" + name] = value;
 | 
					        return ctx['$' + name] = value;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (var name in ctxProp) {
 | 
					  for (var name in ctxProp) {
 | 
				
			||||||
    ctx["$" + name] = ctxProp[name];
 | 
					    ctx['$' + name] = ctxProp[name];
 | 
				
			||||||
    ctx.__defineGetter__(name, buildGetter(name));
 | 
					    ctx.__defineGetter__(name, buildGetter(name));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Special treatment for `fillStyle` and `strokeStyle`: The passed style
 | 
					    // Special treatment for `fillStyle` and `strokeStyle`: The passed style
 | 
				
			||||||
    // might be a gradient. Need to check for that.
 | 
					    // might be a gradient. Need to check for that.
 | 
				
			||||||
    if (name == "fillStyle" || name == "strokeStyle") {
 | 
					    if (name == 'fillStyle' || name == 'strokeStyle') {
 | 
				
			||||||
      ctx.__defineSetter__(name, buildSetterStyle(name));
 | 
					      ctx.__defineSetter__(name, buildSetterStyle(name));
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      ctx.__defineSetter__(name, buildSetter(name));
 | 
					      ctx.__defineSetter__(name, buildSetter(name));
 | 
				
			||||||
@ -239,13 +240,13 @@ function CanvasProxy(width, height) {
 | 
				
			|||||||
*/
 | 
					*/
 | 
				
			||||||
CanvasProxy.prototype.flush = function() {
 | 
					CanvasProxy.prototype.flush = function() {
 | 
				
			||||||
  postMessage({
 | 
					  postMessage({
 | 
				
			||||||
    action: "canvas_proxy_cmd_queue",
 | 
					    action: 'canvas_proxy_cmd_queue',
 | 
				
			||||||
    data: {
 | 
					    data: {
 | 
				
			||||||
      id:         this.id,
 | 
					      id: this.id,
 | 
				
			||||||
      cmdQueue:   this.cmdQueue,
 | 
					      cmdQueue: this.cmdQueue,
 | 
				
			||||||
      width:      this.width,
 | 
					      width: this.width,
 | 
				
			||||||
      height:     this.height
 | 
					      height: this.height
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  this.cmdQueue.length = 0;
 | 
					  this.cmdQueue.length = 0;
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										154
									
								
								worker/client.js
									
									
									
									
									
								
							
							
						
						
									
										154
									
								
								worker/client.js
									
									
									
									
									
								
							@ -1,9 +1,9 @@
 | 
				
			|||||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 | 
					/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 | 
				
			||||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
					/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"use strict";
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (typeof console.time == "undefined") {
 | 
					if (typeof console.time == 'undefined') {
 | 
				
			||||||
  var consoleTimer = {};
 | 
					  var consoleTimer = {};
 | 
				
			||||||
  console.time = function(name) {
 | 
					  console.time = function(name) {
 | 
				
			||||||
    consoleTimer[name] = Date.now();
 | 
					    consoleTimer[name] = Date.now();
 | 
				
			||||||
@ -12,25 +12,25 @@ if (typeof console.time == "undefined") {
 | 
				
			|||||||
  console.timeEnd = function(name) {
 | 
					  console.timeEnd = function(name) {
 | 
				
			||||||
    var time = consoleTimer[name];
 | 
					    var time = consoleTimer[name];
 | 
				
			||||||
    if (time == null) {
 | 
					    if (time == null) {
 | 
				
			||||||
      throw "Unkown timer name " + name;
 | 
					      throw 'Unkown timer name ' + name;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    this.log("Timer:", name, Date.now() - time);
 | 
					    this.log('Timer:', name, Date.now() - time);
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function FontWorker() {
 | 
					function FontWorker() {
 | 
				
			||||||
  this.worker = new Worker("worker/font.js");
 | 
					  this.worker = new Worker('worker/font.js');
 | 
				
			||||||
  this.fontsWaiting = 0;
 | 
					  this.fontsWaiting = 0;
 | 
				
			||||||
  this.fontsWaitingCallbacks = [];
 | 
					  this.fontsWaitingCallbacks = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Listen to the WebWorker for data and call actionHandler on it.
 | 
					  // Listen to the WebWorker for data and call actionHandler on it.
 | 
				
			||||||
  this.worker.onmessage = function(event) {
 | 
					  this.worker.onmessage = function(event) {
 | 
				
			||||||
    var data = event.data;
 | 
					    var data = event.data;
 | 
				
			||||||
    var actionHandler = this.actionHandler
 | 
					    var actionHandler = this.actionHandler;
 | 
				
			||||||
    if (data.action in actionHandler) {
 | 
					    if (data.action in actionHandler) {
 | 
				
			||||||
      actionHandler[data.action].call(this, data.data);
 | 
					      actionHandler[data.action].call(this, data.data);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      throw "Unkown action from worker: " + data.action;
 | 
					      throw 'Unkown action from worker: ' + data.action;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }.bind(this);
 | 
					  }.bind(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -52,20 +52,21 @@ FontWorker.prototype = {
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  actionHandler: {
 | 
					  actionHandler: {
 | 
				
			||||||
    "log": function(data) {
 | 
					    'log': function(data) {
 | 
				
			||||||
      console.log.apply(console, data);
 | 
					      console.log.apply(console, data);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "fonts": function(data) {
 | 
					    'fonts': function(data) {
 | 
				
			||||||
      // console.log("got processed fonts from worker", Object.keys(data));
 | 
					      // console.log("got processed fonts from worker", Object.keys(data));
 | 
				
			||||||
      for (name in data) {
 | 
					      for (name in data) {
 | 
				
			||||||
        // Update the encoding property.
 | 
					        // Update the encoding property.
 | 
				
			||||||
        var font = Fonts.lookup(name);
 | 
					        var font = Fonts.lookup(name);
 | 
				
			||||||
        font.properties = {
 | 
					        font.properties = {
 | 
				
			||||||
          encoding: data[name].encoding
 | 
					          encoding: data[name].encoding
 | 
				
			||||||
        }
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Call `Font.prototype.bindDOM` to make the font get loaded on the page.
 | 
					        // Call `Font.prototype.bindDOM` to make the font get loaded
 | 
				
			||||||
 | 
					        // on the page.
 | 
				
			||||||
        Font.prototype.bindDOM.call(
 | 
					        Font.prototype.bindDOM.call(
 | 
				
			||||||
          font,
 | 
					          font,
 | 
				
			||||||
          data[name].str,
 | 
					          data[name].str,
 | 
				
			||||||
@ -95,15 +96,15 @@ FontWorker.prototype = {
 | 
				
			|||||||
      this.fontsWaiting++;
 | 
					      this.fontsWaiting++;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    console.time("ensureFonts");
 | 
					    console.time('ensureFonts');
 | 
				
			||||||
    // If there are fonts, that need to get loaded, tell the FontWorker to get
 | 
					    // If there are fonts, that need to get loaded, tell the FontWorker to get
 | 
				
			||||||
    // started and push the callback on the waiting-callback-stack.
 | 
					    // started and push the callback on the waiting-callback-stack.
 | 
				
			||||||
    if (notLoaded.length != 0) {
 | 
					    if (notLoaded.length != 0) {
 | 
				
			||||||
      console.log("fonts -> FontWorker");
 | 
					      console.log('fonts -> FontWorker');
 | 
				
			||||||
      // Send the worker the fonts to work on.
 | 
					      // Send the worker the fonts to work on.
 | 
				
			||||||
      this.worker.postMessage({
 | 
					      this.worker.postMessage({
 | 
				
			||||||
        action: "fonts",
 | 
					        action: 'fonts',
 | 
				
			||||||
        data:   notLoaded
 | 
					        data: notLoaded
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
      if (callback) {
 | 
					      if (callback) {
 | 
				
			||||||
        this.fontsWaitingCallbacks.push(callback);
 | 
					        this.fontsWaitingCallbacks.push(callback);
 | 
				
			||||||
@ -115,13 +116,13 @@ FontWorker.prototype = {
 | 
				
			|||||||
        callback();
 | 
					        callback();
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  }
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function WorkerPDFDoc(canvas) {
 | 
					function WorkerPDFDoc(canvas) {
 | 
				
			||||||
  var timer = null
 | 
					  var timer = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  this.ctx = canvas.getContext("2d");
 | 
					  this.ctx = canvas.getContext('2d');
 | 
				
			||||||
  this.canvas = canvas;
 | 
					  this.canvas = canvas;
 | 
				
			||||||
  this.worker = new Worker('worker/pdf.js');
 | 
					  this.worker = new Worker('worker/pdf.js');
 | 
				
			||||||
  this.fontWorker = new FontWorker();
 | 
					  this.fontWorker = new FontWorker();
 | 
				
			||||||
@ -142,30 +143,30 @@ function WorkerPDFDoc(canvas) {
 | 
				
			|||||||
  var currentXStack = [];
 | 
					  var currentXStack = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  var ctxSpecial = {
 | 
					  var ctxSpecial = {
 | 
				
			||||||
    "$setCurrentX": function(value) {
 | 
					    '$setCurrentX': function(value) {
 | 
				
			||||||
      currentX = value;
 | 
					      currentX = value;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "$addCurrentX": function(value) {
 | 
					    '$addCurrentX': function(value) {
 | 
				
			||||||
      currentX += value;
 | 
					      currentX += value;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "$saveCurrentX": function() {
 | 
					    '$saveCurrentX': function() {
 | 
				
			||||||
      currentXStack.push(currentX);
 | 
					      currentXStack.push(currentX);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "$restoreCurrentX": function() {
 | 
					    '$restoreCurrentX': function() {
 | 
				
			||||||
      currentX = currentXStack.pop();
 | 
					      currentX = currentXStack.pop();
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "$showText": function(y, text) {
 | 
					    '$showText': function(y, text) {
 | 
				
			||||||
      text = Fonts.charsToUnicode(text);
 | 
					      text = Fonts.charsToUnicode(text);
 | 
				
			||||||
      this.translate(currentX, -1 * y);
 | 
					      this.translate(currentX, -1 * y);
 | 
				
			||||||
      this.fillText(text, 0, 0);
 | 
					      this.fillText(text, 0, 0);
 | 
				
			||||||
      currentX += this.measureText(text).width;
 | 
					      currentX += this.measureText(text).width;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "$putImageData": function(imageData, x, y) {
 | 
					    '$putImageData': function(imageData, x, y) {
 | 
				
			||||||
      var imgData = this.getImageData(0, 0, imageData.width, imageData.height);
 | 
					      var imgData = this.getImageData(0, 0, imageData.width, imageData.height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Store the .data property to avaid property lookups.
 | 
					      // Store the .data property to avaid property lookups.
 | 
				
			||||||
@ -175,24 +176,24 @@ function WorkerPDFDoc(canvas) {
 | 
				
			|||||||
      // Copy over the imageData.
 | 
					      // Copy over the imageData.
 | 
				
			||||||
      var len = imageRealData.length;
 | 
					      var len = imageRealData.length;
 | 
				
			||||||
      while (len--)
 | 
					      while (len--)
 | 
				
			||||||
      imgRealData[len] = imageRealData[len]
 | 
					      imgRealData[len] = imageRealData[len];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      this.putImageData(imgData, x, y);
 | 
					      this.putImageData(imgData, x, y);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "$drawImage": function(id, x, y, sx, sy, swidth, sheight) {
 | 
					    '$drawImage': function(id, x, y, sx, sy, swidth, sheight) {
 | 
				
			||||||
      var image = imagesList[id];
 | 
					      var image = imagesList[id];
 | 
				
			||||||
      if (!image) {
 | 
					      if (!image) {
 | 
				
			||||||
        throw "Image not found: " + id;
 | 
					        throw 'Image not found: ' + id;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      this.drawImage(image, x, y, image.width, image.height,
 | 
					      this.drawImage(image, x, y, image.width, image.height,
 | 
				
			||||||
        sx, sy, swidth, sheight);
 | 
					        sx, sy, swidth, sheight);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "$drawCanvas": function(id, x, y, sx, sy, swidth, sheight) {
 | 
					    '$drawCanvas': function(id, x, y, sx, sy, swidth, sheight) {
 | 
				
			||||||
      var canvas = canvasList[id];
 | 
					      var canvas = canvasList[id];
 | 
				
			||||||
      if (!canvas) {
 | 
					      if (!canvas) {
 | 
				
			||||||
        throw "Canvas not found";
 | 
					        throw 'Canvas not found';
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (sheight != null) {
 | 
					      if (sheight != null) {
 | 
				
			||||||
        this.drawImage(canvas, x, y, canvas.width, canvas.height,
 | 
					        this.drawImage(canvas, x, y, canvas.width, canvas.height,
 | 
				
			||||||
@ -202,58 +203,58 @@ function WorkerPDFDoc(canvas) {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "$createLinearGradient": function(x0, y0, x1, y1) {
 | 
					    '$createLinearGradient': function(x0, y0, x1, y1) {
 | 
				
			||||||
      gradient = this.createLinearGradient(x0, y0, x1, y1);
 | 
					      gradient = this.createLinearGradient(x0, y0, x1, y1);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "$createPatternFromCanvas": function(patternId, canvasId, kind) {
 | 
					    '$createPatternFromCanvas': function(patternId, canvasId, kind) {
 | 
				
			||||||
      var canvas = canvasList[canvasId];
 | 
					      var canvas = canvasList[canvasId];
 | 
				
			||||||
      if (!canvas) {
 | 
					      if (!canvas) {
 | 
				
			||||||
        throw "Canvas not found";
 | 
					        throw 'Canvas not found';
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      patternList[patternId] = this.createPattern(canvas, kind);
 | 
					      patternList[patternId] = this.createPattern(canvas, kind);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "$addColorStop": function(i, rgba) {
 | 
					    '$addColorStop': function(i, rgba) {
 | 
				
			||||||
      gradient.addColorStop(i, rgba);
 | 
					      gradient.addColorStop(i, rgba);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "$fillStyleGradient": function() {
 | 
					    '$fillStyleGradient': function() {
 | 
				
			||||||
      this.fillStyle = gradient;
 | 
					      this.fillStyle = gradient;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "$fillStylePattern": function(id) {
 | 
					    '$fillStylePattern': function(id) {
 | 
				
			||||||
      var pattern = patternList[id];
 | 
					      var pattern = patternList[id];
 | 
				
			||||||
      if (!pattern) {
 | 
					      if (!pattern) {
 | 
				
			||||||
        throw "Pattern not found";
 | 
					        throw 'Pattern not found';
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      this.fillStyle = pattern;
 | 
					      this.fillStyle = pattern;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "$strokeStyleGradient": function() {
 | 
					    '$strokeStyleGradient': function() {
 | 
				
			||||||
      this.strokeStyle = gradient;
 | 
					      this.strokeStyle = gradient;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "$strokeStylePattern": function(id) {
 | 
					    '$strokeStylePattern': function(id) {
 | 
				
			||||||
      var pattern = patternList[id];
 | 
					      var pattern = patternList[id];
 | 
				
			||||||
      if (!pattern) {
 | 
					      if (!pattern) {
 | 
				
			||||||
        throw "Pattern not found";
 | 
					        throw 'Pattern not found';
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      this.strokeStyle = pattern;
 | 
					      this.strokeStyle = pattern;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "$setFont": function(name, size) {
 | 
					    '$setFont': function(name, size) {
 | 
				
			||||||
      this.font = size + 'px "' + name + '"';
 | 
					      this.font = size + 'px "' + name + '"';
 | 
				
			||||||
      Fonts.setActive(name, size);
 | 
					      Fonts.setActive(name, size);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function renderProxyCanvas(canvas, cmdQueue) {
 | 
					  function renderProxyCanvas(canvas, cmdQueue) {
 | 
				
			||||||
    var ctx = canvas.getContext("2d");
 | 
					    var ctx = canvas.getContext('2d');
 | 
				
			||||||
    var cmdQueueLength = cmdQueue.length;
 | 
					    var cmdQueueLength = cmdQueue.length;
 | 
				
			||||||
    for (var i = 0; i < cmdQueueLength; i++) {
 | 
					    for (var i = 0; i < cmdQueueLength; i++) {
 | 
				
			||||||
      var opp = cmdQueue[i];
 | 
					      var opp = cmdQueue[i];
 | 
				
			||||||
      if (opp[0] == "$") {
 | 
					      if (opp[0] == '$') {
 | 
				
			||||||
        ctx[opp[1]] = opp[2];
 | 
					        ctx[opp[1]] = opp[2];
 | 
				
			||||||
      } else if (opp[0] in ctxSpecial) {
 | 
					      } else if (opp[0] in ctxSpecial) {
 | 
				
			||||||
        ctxSpecial[opp[0]].apply(ctx, opp[1]);
 | 
					        ctxSpecial[opp[0]].apply(ctx, opp[1]);
 | 
				
			||||||
@ -267,44 +268,45 @@ function WorkerPDFDoc(canvas) {
 | 
				
			|||||||
  * Functions to handle data sent by the WebWorker.
 | 
					  * Functions to handle data sent by the WebWorker.
 | 
				
			||||||
  */
 | 
					  */
 | 
				
			||||||
  var actionHandler = {
 | 
					  var actionHandler = {
 | 
				
			||||||
    "log": function(data) {
 | 
					    'log': function(data) {
 | 
				
			||||||
      console.log.apply(console, data);
 | 
					      console.log.apply(console, data);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "pdf_num_pages": function(data) {
 | 
					    'pdf_num_pages': function(data) {
 | 
				
			||||||
      this.numPages = parseInt(data);
 | 
					      this.numPages = parseInt(data);
 | 
				
			||||||
      if (this.loadCallback) {
 | 
					      if (this.loadCallback) {
 | 
				
			||||||
        this.loadCallback();
 | 
					        this.loadCallback();
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "font": function(data) {
 | 
					    'font': function(data) {
 | 
				
			||||||
      var base64 = window.btoa(data.raw);
 | 
					      var base64 = window.btoa(data.raw);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Add the @font-face rule to the document
 | 
					      // Add the @font-face rule to the document
 | 
				
			||||||
      var url = "url(data:" + data.mimetype + ";base64," + base64 + ");";
 | 
					      var url = 'url(data:' + data.mimetype + ';base64,' + base64 + ');';
 | 
				
			||||||
      var rule = "@font-face { font-family:'" + data.fontName + "';src:" + url + "}";
 | 
					      var rule = ("@font-face { font-family:'" + data.fontName +
 | 
				
			||||||
 | 
					                  "';src:" + url + '}');
 | 
				
			||||||
      var styleSheet = document.styleSheets[0];
 | 
					      var styleSheet = document.styleSheets[0];
 | 
				
			||||||
      styleSheet.insertRule(rule, styleSheet.length);
 | 
					      styleSheet.insertRule(rule, styleSheet.cssRules.length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Just adding the font-face to the DOM doesn't make it load. It
 | 
					      // Just adding the font-face to the DOM doesn't make it load. It
 | 
				
			||||||
      // seems it's loaded once Gecko notices it's used. Therefore,
 | 
					      // seems it's loaded once Gecko notices it's used. Therefore,
 | 
				
			||||||
      // add a div on the page using the loaded font.
 | 
					      // add a div on the page using the loaded font.
 | 
				
			||||||
      var div = document.createElement("div");
 | 
					      var div = document.createElement('div');
 | 
				
			||||||
      var style = 'font-family:"' + data.fontName +
 | 
					      var style = 'font-family:"' + data.fontName +
 | 
				
			||||||
        '";position: absolute;top:-99999;left:-99999;z-index:-99999';
 | 
					        '";position: absolute;top:-99999;left:-99999;z-index:-99999';
 | 
				
			||||||
      div.setAttribute("style", style);
 | 
					      div.setAttribute('style', style);
 | 
				
			||||||
      document.body.appendChild(div);
 | 
					      document.body.appendChild(div);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "setup_page": function(data) {
 | 
					    'setup_page': function(data) {
 | 
				
			||||||
      var size = data.split(",");
 | 
					      var size = data.split(',');
 | 
				
			||||||
      var canvas = this.canvas, ctx = this.ctx;
 | 
					      var canvas = this.canvas, ctx = this.ctx;
 | 
				
			||||||
      canvas.width = parseInt(size[0]);
 | 
					      canvas.width = parseInt(size[0]);
 | 
				
			||||||
      canvas.height = parseInt(size[1]);
 | 
					      canvas.height = parseInt(size[1]);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "fonts": function(data) {
 | 
					    'fonts': function(data) {
 | 
				
			||||||
      this.waitingForFonts = true;
 | 
					      this.waitingForFonts = true;
 | 
				
			||||||
      this.fontWorker.ensureFonts(data, function() {
 | 
					      this.fontWorker.ensureFonts(data, function() {
 | 
				
			||||||
        this.waitingForFonts = false;
 | 
					        this.waitingForFonts = false;
 | 
				
			||||||
@ -316,20 +318,20 @@ function WorkerPDFDoc(canvas) {
 | 
				
			|||||||
      }.bind(this));
 | 
					      }.bind(this));
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "jpeg_stream": function(data) {
 | 
					    'jpeg_stream': function(data) {
 | 
				
			||||||
      var img = new Image();
 | 
					      var img = new Image();
 | 
				
			||||||
      img.src = "data:image/jpeg;base64," + window.btoa(data.raw);
 | 
					      img.src = 'data:image/jpeg;base64,' + window.btoa(data.raw);
 | 
				
			||||||
      imagesList[data.id] = img;
 | 
					      imagesList[data.id] = img;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "canvas_proxy_cmd_queue": function(data) {
 | 
					    'canvas_proxy_cmd_queue': function(data) {
 | 
				
			||||||
        var id = data.id;
 | 
					        var id = data.id;
 | 
				
			||||||
        var cmdQueue = data.cmdQueue;
 | 
					        var cmdQueue = data.cmdQueue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Check if there is already a canvas with the given id. If not,
 | 
					        // Check if there is already a canvas with the given id. If not,
 | 
				
			||||||
        // create a new canvas.
 | 
					        // create a new canvas.
 | 
				
			||||||
        if (!canvasList[id]) {
 | 
					        if (!canvasList[id]) {
 | 
				
			||||||
          var newCanvas = document.createElement("canvas");
 | 
					          var newCanvas = document.createElement('canvas');
 | 
				
			||||||
          newCanvas.width = data.width;
 | 
					          newCanvas.width = data.width;
 | 
				
			||||||
          newCanvas.height = data.height;
 | 
					          newCanvas.height = data.height;
 | 
				
			||||||
          canvasList[id] = newCanvas;
 | 
					          canvasList[id] = newCanvas;
 | 
				
			||||||
@ -337,23 +339,23 @@ function WorkerPDFDoc(canvas) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        var renderData = function() {
 | 
					        var renderData = function() {
 | 
				
			||||||
          if (id == 0) {
 | 
					          if (id == 0) {
 | 
				
			||||||
            console.time("main canvas rendering");
 | 
					            console.time('main canvas rendering');
 | 
				
			||||||
            var ctx = this.ctx;
 | 
					            var ctx = this.ctx;
 | 
				
			||||||
            ctx.save();
 | 
					            ctx.save();
 | 
				
			||||||
            ctx.fillStyle = "rgb(255, 255, 255)";
 | 
					            ctx.fillStyle = 'rgb(255, 255, 255)';
 | 
				
			||||||
            ctx.fillRect(0, 0, canvas.width, canvas.height);
 | 
					            ctx.fillRect(0, 0, canvas.width, canvas.height);
 | 
				
			||||||
            ctx.restore();
 | 
					            ctx.restore();
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          renderProxyCanvas(canvasList[id], cmdQueue);
 | 
					          renderProxyCanvas(canvasList[id], cmdQueue);
 | 
				
			||||||
          if (id == 0) {
 | 
					          if (id == 0) {
 | 
				
			||||||
            console.timeEnd("main canvas rendering");
 | 
					            console.timeEnd('main canvas rendering');
 | 
				
			||||||
            console.timeEnd(">>> total page display time:");
 | 
					            console.timeEnd('>>> total page display time:');
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }.bind(this);
 | 
					        }.bind(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (this.waitingForFonts) {
 | 
					        if (this.waitingForFonts) {
 | 
				
			||||||
          if (id == 0) {
 | 
					          if (id == 0) {
 | 
				
			||||||
            console.log("want to render, but not all fonts are there", id);
 | 
					            console.log('want to render, but not all fonts are there', id);
 | 
				
			||||||
            this.waitingForFontsCallback.push(renderData);
 | 
					            this.waitingForFontsCallback.push(renderData);
 | 
				
			||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
            // console.log("assume canvas doesn't have fonts", id);
 | 
					            // console.log("assume canvas doesn't have fonts", id);
 | 
				
			||||||
@ -363,7 +365,7 @@ function WorkerPDFDoc(canvas) {
 | 
				
			|||||||
          renderData();
 | 
					          renderData();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Listen to the WebWorker for data and call actionHandler on it.
 | 
					  // Listen to the WebWorker for data and call actionHandler on it.
 | 
				
			||||||
  this.worker.onmessage = function(event) {
 | 
					  this.worker.onmessage = function(event) {
 | 
				
			||||||
@ -371,16 +373,16 @@ function WorkerPDFDoc(canvas) {
 | 
				
			|||||||
    if (data.action in actionHandler) {
 | 
					    if (data.action in actionHandler) {
 | 
				
			||||||
      actionHandler[data.action].call(this, data.data);
 | 
					      actionHandler[data.action].call(this, data.data);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      throw "Unkown action from worker: " + data.action;
 | 
					      throw 'Unkown action from worker: ' + data.action;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }.bind(this)
 | 
					  }.bind(this);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
WorkerPDFDoc.prototype.open = function(url, callback) {
 | 
					WorkerPDFDoc.prototype.open = function(url, callback) {
 | 
				
			||||||
  var req = new XMLHttpRequest();
 | 
					  var req = new XMLHttpRequest();
 | 
				
			||||||
  req.open("GET", url);
 | 
					  req.open('GET', url);
 | 
				
			||||||
  req.mozResponseType = req.responseType = "arraybuffer";
 | 
					  req.mozResponseType = req.responseType = 'arraybuffer';
 | 
				
			||||||
  req.expected = (document.URL.indexOf("file:") == 0) ? 0 : 200;
 | 
					  req.expected = (document.URL.indexOf('file:') == 0) ? 0 : 200;
 | 
				
			||||||
  req.onreadystatechange = function() {
 | 
					  req.onreadystatechange = function() {
 | 
				
			||||||
    if (req.readyState == 4 && req.status == req.expected) {
 | 
					    if (req.readyState == 4 && req.status == req.expected) {
 | 
				
			||||||
      var data = req.mozResponseArrayBuffer || req.mozResponse ||
 | 
					      var data = req.mozResponseArrayBuffer || req.mozResponse ||
 | 
				
			||||||
@ -392,24 +394,24 @@ WorkerPDFDoc.prototype.open = function(url, callback) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }.bind(this);
 | 
					  }.bind(this);
 | 
				
			||||||
  req.send(null);
 | 
					  req.send(null);
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
WorkerPDFDoc.prototype.showPage = function(numPage) {
 | 
					WorkerPDFDoc.prototype.showPage = function(numPage) {
 | 
				
			||||||
  this.numPage = parseInt(numPage);
 | 
					  this.numPage = parseInt(numPage);
 | 
				
			||||||
  console.log("=== start rendering page " + numPage + " ===");
 | 
					  console.log('=== start rendering page ' + numPage + ' ===');
 | 
				
			||||||
  console.time(">>> total page display time:");
 | 
					  console.time('>>> total page display time:');
 | 
				
			||||||
  this.worker.postMessage(numPage);
 | 
					  this.worker.postMessage(numPage);
 | 
				
			||||||
  if (this.onChangePage) {
 | 
					  if (this.onChangePage) {
 | 
				
			||||||
    this.onChangePage(numPage);
 | 
					    this.onChangePage(numPage);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
WorkerPDFDoc.prototype.nextPage = function() {
 | 
					WorkerPDFDoc.prototype.nextPage = function() {
 | 
				
			||||||
  if (this.numPage == this.numPages) return;
 | 
					  if (this.numPage == this.numPages) return;
 | 
				
			||||||
  this.showPage(++this.numPage);
 | 
					  this.showPage(++this.numPage);
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
WorkerPDFDoc.prototype.prevPage = function() {
 | 
					WorkerPDFDoc.prototype.prevPage = function() {
 | 
				
			||||||
  if (this.numPage == 1) return;
 | 
					  if (this.numPage == 1) return;
 | 
				
			||||||
  this.showPage(--this.numPage);
 | 
					  this.showPage(--this.numPage);
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -1,14 +1,14 @@
 | 
				
			|||||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 | 
					/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 | 
				
			||||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
					/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"use strict";
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var consoleTimer = {};
 | 
					var consoleTimer = {};
 | 
				
			||||||
var console = {
 | 
					var console = {
 | 
				
			||||||
  log: function log() {
 | 
					  log: function log() {
 | 
				
			||||||
    var args = Array.prototype.slice.call(arguments);
 | 
					    var args = Array.prototype.slice.call(arguments);
 | 
				
			||||||
    postMessage({
 | 
					    postMessage({
 | 
				
			||||||
      action: "log",
 | 
					      action: 'log',
 | 
				
			||||||
      data: args
 | 
					      data: args
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
@ -20,8 +20,8 @@ var console = {
 | 
				
			|||||||
  timeEnd: function(name) {
 | 
					  timeEnd: function(name) {
 | 
				
			||||||
    var time = consoleTimer[name];
 | 
					    var time = consoleTimer[name];
 | 
				
			||||||
    if (time == null) {
 | 
					    if (time == null) {
 | 
				
			||||||
      throw "Unkown timer name " + name;
 | 
					      throw 'Unkown timer name ' + name;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    this.log("Timer:", name, Date.now() - time);
 | 
					    this.log('Timer:', name, Date.now() - time);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -1,13 +1,13 @@
 | 
				
			|||||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 | 
					/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 | 
				
			||||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
					/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"use strict";
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
importScripts("console.js");
 | 
					importScripts('console.js');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
importScripts("../pdf.js");
 | 
					importScripts('../pdf.js');
 | 
				
			||||||
importScripts("../fonts.js");
 | 
					importScripts('../fonts.js');
 | 
				
			||||||
importScripts("../glyphlist.js")
 | 
					importScripts('../glyphlist.js');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function fontDataToString(font) {
 | 
					function fontDataToString(font) {
 | 
				
			||||||
  // Doing postMessage on objects make them lose their "shape". This adds the
 | 
					  // Doing postMessage on objects make them lose their "shape". This adds the
 | 
				
			||||||
@ -16,30 +16,31 @@ function fontDataToString(font) {
 | 
				
			|||||||
  var fontFileDict = new Dict();
 | 
					  var fontFileDict = new Dict();
 | 
				
			||||||
  fontFileDict.map = font.file.dict.map;
 | 
					  fontFileDict.map = font.file.dict.map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  var fontFile = new Stream(font.file.bytes, font.file.start, font.file.end - font.file.start, fontFileDict);
 | 
					  var fontFile = new Stream(font.file.bytes, font.file.start,
 | 
				
			||||||
 | 
					                            font.file.end - font.file.start, fontFileDict);
 | 
				
			||||||
  font.file = new FlateStream(fontFile);
 | 
					  font.file = new FlateStream(fontFile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // This will encode the font.
 | 
					  // This will encode the font.
 | 
				
			||||||
  var fontObj = new Font(font.name, font.file, font.properties);
 | 
					  var fontObj = new Font(font.name, font.file, font.properties);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Create string that is used for css later.
 | 
					  // Create string that is used for css later.
 | 
				
			||||||
  var str = "";
 | 
					  var str = '';
 | 
				
			||||||
  var data = fontObj.data;
 | 
					  var data = fontObj.data;
 | 
				
			||||||
  var length = data.length;
 | 
					  var length = data.length;
 | 
				
			||||||
  for (var j = 0; j < length; j++)
 | 
					  for (var j = 0; j < length; j++)
 | 
				
			||||||
    str += String.fromCharCode(data[j]);
 | 
					    str += String.fromCharCode(data[j]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
    str:      str,
 | 
					    str: str,
 | 
				
			||||||
    encoding: font.properties.encoding
 | 
					    encoding: font.properties.encoding
 | 
				
			||||||
  }
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
* Functions to handle data sent by the MainThread.
 | 
					* Functions to handle data sent by the MainThread.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
var actionHandler = {
 | 
					var actionHandler = {
 | 
				
			||||||
  "fonts": function(data) {
 | 
					  'fonts': function(data) {
 | 
				
			||||||
    var fontData;
 | 
					    var fontData;
 | 
				
			||||||
    var result = {};
 | 
					    var result = {};
 | 
				
			||||||
    for (var i = 0; i < data.length; i++) {
 | 
					    for (var i = 0; i < data.length; i++) {
 | 
				
			||||||
@ -48,11 +49,11 @@ var actionHandler = {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    postMessage({
 | 
					    postMessage({
 | 
				
			||||||
      action: "fonts",
 | 
					      action: 'fonts',
 | 
				
			||||||
      data:   result
 | 
					      data: result
 | 
				
			||||||
    })
 | 
					    });
 | 
				
			||||||
  },
 | 
					  }
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Listen to the MainThread for data and call actionHandler on it.
 | 
					// Listen to the MainThread for data and call actionHandler on it.
 | 
				
			||||||
this.onmessage = function(event) {
 | 
					this.onmessage = function(event) {
 | 
				
			||||||
@ -60,6 +61,6 @@ this.onmessage = function(event) {
 | 
				
			|||||||
  if (data.action in actionHandler) {
 | 
					  if (data.action in actionHandler) {
 | 
				
			||||||
    actionHandler[data.action].call(this, data.data);
 | 
					    actionHandler[data.action].call(this, data.data);
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    throw "Unkown action from worker: " + data.action;
 | 
					    throw 'Unkown action from worker: ' + data.action;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -1,14 +1,14 @@
 | 
				
			|||||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 | 
					/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 | 
				
			||||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
					/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"use strict";
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var consoleTimer = {};
 | 
					var consoleTimer = {};
 | 
				
			||||||
var console = {
 | 
					var console = {
 | 
				
			||||||
  log: function log() {
 | 
					  log: function log() {
 | 
				
			||||||
    var args = Array.prototype.slice.call(arguments);
 | 
					    var args = Array.prototype.slice.call(arguments);
 | 
				
			||||||
    postMessage({
 | 
					    postMessage({
 | 
				
			||||||
      action: "log",
 | 
					      action: 'log',
 | 
				
			||||||
      data: args
 | 
					      data: args
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
@ -20,19 +20,19 @@ var console = {
 | 
				
			|||||||
  timeEnd: function(name) {
 | 
					  timeEnd: function(name) {
 | 
				
			||||||
    var time = consoleTimer[name];
 | 
					    var time = consoleTimer[name];
 | 
				
			||||||
    if (time == null) {
 | 
					    if (time == null) {
 | 
				
			||||||
      throw "Unkown timer name " + name;
 | 
					      throw 'Unkown timer name ' + name;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    this.log("Timer:", name, Date.now() - time);
 | 
					    this.log('Timer:', name, Date.now() - time);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
importScripts("console.js")
 | 
					importScripts('console.js');
 | 
				
			||||||
importScripts("canvas.js");
 | 
					importScripts('canvas.js');
 | 
				
			||||||
importScripts("../pdf.js");
 | 
					importScripts('../pdf.js');
 | 
				
			||||||
importScripts("../fonts.js");
 | 
					importScripts('../fonts.js');
 | 
				
			||||||
importScripts("../crypto.js");
 | 
					importScripts('../crypto.js');
 | 
				
			||||||
importScripts("../glyphlist.js")
 | 
					importScripts('../glyphlist.js');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Use the JpegStreamProxy proxy.
 | 
					// Use the JpegStreamProxy proxy.
 | 
				
			||||||
JpegStream = JpegStreamProxy;
 | 
					JpegStream = JpegStreamProxy;
 | 
				
			||||||
@ -48,14 +48,14 @@ onmessage = function(event) {
 | 
				
			|||||||
  if (!pdfDocument) {
 | 
					  if (!pdfDocument) {
 | 
				
			||||||
    pdfDocument = new PDFDoc(new Stream(data));
 | 
					    pdfDocument = new PDFDoc(new Stream(data));
 | 
				
			||||||
    postMessage({
 | 
					    postMessage({
 | 
				
			||||||
      action: "pdf_num_pages",
 | 
					      action: 'pdf_num_pages',
 | 
				
			||||||
      data: pdfDocument.numPages
 | 
					      data: pdfDocument.numPages
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  // User requested to render a certain page.
 | 
					  // User requested to render a certain page.
 | 
				
			||||||
  else {
 | 
					  else {
 | 
				
			||||||
    console.time("compile");
 | 
					    console.time('compile');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Let's try to render the first page...
 | 
					    // Let's try to render the first page...
 | 
				
			||||||
    var page = pdfDocument.getPage(parseInt(data));
 | 
					    var page = pdfDocument.getPage(parseInt(data));
 | 
				
			||||||
@ -64,8 +64,8 @@ onmessage = function(event) {
 | 
				
			|||||||
    var pageWidth = (page.mediaBox[2] - page.mediaBox[0]) * pdfToCssUnitsCoef;
 | 
					    var pageWidth = (page.mediaBox[2] - page.mediaBox[0]) * pdfToCssUnitsCoef;
 | 
				
			||||||
    var pageHeight = (page.mediaBox[3] - page.mediaBox[1]) * pdfToCssUnitsCoef;
 | 
					    var pageHeight = (page.mediaBox[3] - page.mediaBox[1]) * pdfToCssUnitsCoef;
 | 
				
			||||||
    postMessage({
 | 
					    postMessage({
 | 
				
			||||||
      action: "setup_page",
 | 
					      action: 'setup_page',
 | 
				
			||||||
      data: pageWidth + "," + pageHeight
 | 
					      data: pageWidth + ',' + pageHeight
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Set canvas size.
 | 
					    // Set canvas size.
 | 
				
			||||||
@ -75,21 +75,21 @@ onmessage = function(event) {
 | 
				
			|||||||
    // page.compile will collect all fonts for us, once we have loaded them
 | 
					    // page.compile will collect all fonts for us, once we have loaded them
 | 
				
			||||||
    // we can trigger the actual page rendering with page.display
 | 
					    // we can trigger the actual page rendering with page.display
 | 
				
			||||||
    var fonts = [];
 | 
					    var fonts = [];
 | 
				
			||||||
    var gfx = new CanvasGraphics(canvas.getContext("2d"), CanvasProxy);
 | 
					    var gfx = new CanvasGraphics(canvas.getContext('2d'), CanvasProxy);
 | 
				
			||||||
    page.compile(gfx, fonts);
 | 
					    page.compile(gfx, fonts);
 | 
				
			||||||
    console.timeEnd("compile");
 | 
					    console.timeEnd('compile');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Send fonts to the main thread.
 | 
					    // Send fonts to the main thread.
 | 
				
			||||||
    console.time("fonts");
 | 
					    console.time('fonts');
 | 
				
			||||||
    postMessage({
 | 
					    postMessage({
 | 
				
			||||||
      action: "fonts",
 | 
					      action: 'fonts',
 | 
				
			||||||
      data:   fonts
 | 
					      data: fonts
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    console.timeEnd("fonts");
 | 
					    console.timeEnd('fonts');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    console.time("display");
 | 
					    console.time('display');
 | 
				
			||||||
    page.display(gfx);
 | 
					    page.display(gfx);
 | 
				
			||||||
    canvas.flush();
 | 
					    canvas.flush();
 | 
				
			||||||
    console.timeEnd("display");
 | 
					    console.timeEnd('display');
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user