diff --git a/09/miniwebsite/ViewerJS/compatibility.js b/09/miniwebsite/ViewerJS/compatibility.js
new file mode 100644
index 0000000..06f54bf
--- /dev/null
+++ b/09/miniwebsite/ViewerJS/compatibility.js
@@ -0,0 +1,577 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+/* Copyright 2012 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* globals VBArray, PDFJS */
+
+'use strict';
+
+// Initializing PDFJS global object here, it case if we need to change/disable
+// some PDF.js features, e.g. range requests
+if (typeof PDFJS === 'undefined') {
+ (typeof window !== 'undefined' ? window : this).PDFJS = {};
+}
+
+// Checking if the typed arrays are supported
+// Support: iOS<6.0 (subarray), IE<10, Android<4.0
+(function checkTypedArrayCompatibility() {
+ if (typeof Uint8Array !== 'undefined') {
+ // Support: iOS<6.0
+ if (typeof Uint8Array.prototype.subarray === 'undefined') {
+ Uint8Array.prototype.subarray = function subarray(start, end) {
+ return new Uint8Array(this.slice(start, end));
+ };
+ Float32Array.prototype.subarray = function subarray(start, end) {
+ return new Float32Array(this.slice(start, end));
+ };
+ }
+
+ // Support: Android<4.1
+ if (typeof Float64Array === 'undefined') {
+ window.Float64Array = Float32Array;
+ }
+ return;
+ }
+
+ function subarray(start, end) {
+ return new TypedArray(this.slice(start, end));
+ }
+
+ function setArrayOffset(array, offset) {
+ if (arguments.length < 2) {
+ offset = 0;
+ }
+ for (var i = 0, n = array.length; i < n; ++i, ++offset) {
+ this[offset] = array[i] & 0xFF;
+ }
+ }
+
+ function TypedArray(arg1) {
+ var result, i, n;
+ if (typeof arg1 === 'number') {
+ result = [];
+ for (i = 0; i < arg1; ++i) {
+ result[i] = 0;
+ }
+ } else if ('slice' in arg1) {
+ result = arg1.slice(0);
+ } else {
+ result = [];
+ for (i = 0, n = arg1.length; i < n; ++i) {
+ result[i] = arg1[i];
+ }
+ }
+
+ result.subarray = subarray;
+ result.buffer = result;
+ result.byteLength = result.length;
+ result.set = setArrayOffset;
+
+ if (typeof arg1 === 'object' && arg1.buffer) {
+ result.buffer = arg1.buffer;
+ }
+ return result;
+ }
+
+ window.Uint8Array = TypedArray;
+ window.Int8Array = 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;
+ window.Uint16Array = TypedArray;
+ window.Float32Array = TypedArray;
+ window.Float64Array = TypedArray;
+})();
+
+// URL = URL || webkitURL
+// Support: Safari<7, Android 4.2+
+(function normalizeURLObject() {
+ if (!window.URL) {
+ window.URL = window.webkitURL;
+ }
+})();
+
+// Object.defineProperty()?
+// Support: Android<4.0, Safari<5.1
+(function checkObjectDefinePropertyCompatibility() {
+ if (typeof Object.defineProperty !== 'undefined') {
+ var definePropertyPossible = true;
+ try {
+ // some browsers (e.g. safari) cannot use defineProperty() on DOM objects
+ // and thus the native version is not sufficient
+ Object.defineProperty(new Image(), 'id', { value: 'test' });
+ // ... another test for android gb browser for non-DOM objects
+ var Test = function Test() {};
+ Test.prototype = { get id() { } };
+ Object.defineProperty(new Test(), 'id',
+ { value: '', configurable: true, enumerable: true, writable: false });
+ } catch (e) {
+ definePropertyPossible = false;
+ }
+ if (definePropertyPossible) {
+ return;
+ }
+ }
+
+ Object.defineProperty = function objectDefineProperty(obj, name, def) {
+ delete obj[name];
+ if ('get' in def) {
+ obj.__defineGetter__(name, def['get']);
+ }
+ if ('set' in def) {
+ obj.__defineSetter__(name, def['set']);
+ }
+ if ('value' in def) {
+ obj.__defineSetter__(name, function objectDefinePropertySetter(value) {
+ this.__defineGetter__(name, function objectDefinePropertyGetter() {
+ return value;
+ });
+ return value;
+ });
+ obj[name] = def.value;
+ }
+ };
+})();
+
+
+// No XMLHttpRequest#response?
+// Support: IE<11, Android <4.0
+(function checkXMLHttpRequestResponseCompatibility() {
+ var xhrPrototype = XMLHttpRequest.prototype;
+ var xhr = new XMLHttpRequest();
+ if (!('overrideMimeType' in xhr)) {
+ // IE10 might have response, but not overrideMimeType
+ // Support: IE10
+ Object.defineProperty(xhrPrototype, 'overrideMimeType', {
+ value: function xmlHttpRequestOverrideMimeType(mimeType) {}
+ });
+ }
+ if ('responseType' in xhr) {
+ return;
+ }
+
+ // The worker will be using XHR, so we can save time and disable worker.
+ PDFJS.disableWorker = true;
+
+ Object.defineProperty(xhrPrototype, 'responseType', {
+ get: function xmlHttpRequestGetResponseType() {
+ return this._responseType || 'text';
+ },
+ set: function xmlHttpRequestSetResponseType(value) {
+ if (value === 'text' || value === 'arraybuffer') {
+ this._responseType = value;
+ if (value === 'arraybuffer' &&
+ typeof this.overrideMimeType === 'function') {
+ this.overrideMimeType('text/plain; charset=x-user-defined');
+ }
+ }
+ }
+ });
+
+ // Support: IE9
+ if (typeof VBArray !== 'undefined') {
+ Object.defineProperty(xhrPrototype, 'response', {
+ get: function xmlHttpRequestResponseGet() {
+ if (this.responseType === 'arraybuffer') {
+ return new Uint8Array(new VBArray(this.responseBody).toArray());
+ } else {
+ return this.responseText;
+ }
+ }
+ });
+ return;
+ }
+
+ Object.defineProperty(xhrPrototype, 'response', {
+ get: function xmlHttpRequestResponseGet() {
+ if (this.responseType !== 'arraybuffer') {
+ return this.responseText;
+ }
+ 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.buffer;
+ }
+ });
+})();
+
+// window.btoa (base64 encode function) ?
+// Support: IE<10
+(function checkWindowBtoaCompatibility() {
+ if ('btoa' in window) {
+ return;
+ }
+
+ var digits =
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
+
+ window.btoa = function windowBtoa(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;
+ };
+})();
+
+// window.atob (base64 encode function)?
+// Support: IE<10
+(function checkWindowAtobCompatibility() {
+ if ('atob' in window) {
+ return;
+ }
+
+ // https://github.com/davidchambers/Base64.js
+ var digits =
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
+ window.atob = function (input) {
+ input = input.replace(/=+$/, '');
+ if (input.length % 4 === 1) {
+ throw new Error('bad atob input');
+ }
+ for (
+ // initialize result and counters
+ var bc = 0, bs, buffer, idx = 0, output = '';
+ // get next character
+ buffer = input.charAt(idx++);
+ // character found in table?
+ // initialize bit storage and add its ascii value
+ ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,
+ // and if not first of each 4 characters,
+ // convert the first 8 bits to one ascii character
+ bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0
+ ) {
+ // try to find character in table (0-63, not found => -1)
+ buffer = digits.indexOf(buffer);
+ }
+ return output;
+ };
+})();
+
+// Function.prototype.bind?
+// Support: Android<4.0, iOS<6.0
+(function checkFunctionPrototypeBindCompatibility() {
+ if (typeof Function.prototype.bind !== 'undefined') {
+ return;
+ }
+
+ Function.prototype.bind = function functionPrototypeBind(obj) {
+ var fn = this, headArgs = Array.prototype.slice.call(arguments, 1);
+ var bound = function functionPrototypeBindBound() {
+ var args = headArgs.concat(Array.prototype.slice.call(arguments));
+ return fn.apply(obj, args);
+ };
+ return bound;
+ };
+})();
+
+// HTMLElement dataset property
+// Support: IE<11, Safari<5.1, Android<4.0
+(function checkDatasetProperty() {
+ var div = document.createElement('div');
+ if ('dataset' in div) {
+ return; // dataset property exists
+ }
+
+ Object.defineProperty(HTMLElement.prototype, 'dataset', {
+ get: function() {
+ if (this._dataset) {
+ return this._dataset;
+ }
+
+ var dataset = {};
+ for (var j = 0, jj = this.attributes.length; j < jj; j++) {
+ var attribute = this.attributes[j];
+ if (attribute.name.substring(0, 5) !== 'data-') {
+ continue;
+ }
+ var key = attribute.name.substring(5).replace(/\-([a-z])/g,
+ function(all, ch) {
+ return ch.toUpperCase();
+ });
+ dataset[key] = attribute.value;
+ }
+
+ Object.defineProperty(this, '_dataset', {
+ value: dataset,
+ writable: false,
+ enumerable: false
+ });
+ return dataset;
+ },
+ enumerable: true
+ });
+})();
+
+// HTMLElement classList property
+// Support: IE<10, Android<4.0, iOS<5.0
+(function checkClassListProperty() {
+ var div = document.createElement('div');
+ if ('classList' in div) {
+ return; // classList property exists
+ }
+
+ function changeList(element, itemName, add, remove) {
+ var s = element.className || '';
+ var list = s.split(/\s+/g);
+ if (list[0] === '') {
+ list.shift();
+ }
+ var index = list.indexOf(itemName);
+ if (index < 0 && add) {
+ list.push(itemName);
+ }
+ if (index >= 0 && remove) {
+ list.splice(index, 1);
+ }
+ element.className = list.join(' ');
+ return (index >= 0);
+ }
+
+ var classListPrototype = {
+ add: function(name) {
+ changeList(this.element, name, true, false);
+ },
+ contains: function(name) {
+ return changeList(this.element, name, false, false);
+ },
+ remove: function(name) {
+ changeList(this.element, name, false, true);
+ },
+ toggle: function(name) {
+ changeList(this.element, name, true, true);
+ }
+ };
+
+ Object.defineProperty(HTMLElement.prototype, 'classList', {
+ get: function() {
+ if (this._classList) {
+ return this._classList;
+ }
+
+ var classList = Object.create(classListPrototype, {
+ element: {
+ value: this,
+ writable: false,
+ enumerable: true
+ }
+ });
+ Object.defineProperty(this, '_classList', {
+ value: classList,
+ writable: false,
+ enumerable: false
+ });
+ return classList;
+ },
+ enumerable: true
+ });
+})();
+
+// Check console compatibility
+// In older IE versions the console object is not available
+// unless console is open.
+// Support: IE<10
+(function checkConsoleCompatibility() {
+ if (!('console' in window)) {
+ window.console = {
+ log: function() {},
+ error: function() {},
+ warn: function() {}
+ };
+ } else if (!('bind' in console.log)) {
+ // native functions in IE9 might not have bind
+ console.log = (function(fn) {
+ return function(msg) { return fn(msg); };
+ })(console.log);
+ console.error = (function(fn) {
+ return function(msg) { return fn(msg); };
+ })(console.error);
+ console.warn = (function(fn) {
+ return function(msg) { return fn(msg); };
+ })(console.warn);
+ }
+})();
+
+// Check onclick compatibility in Opera
+// Support: Opera<15
+(function checkOnClickCompatibility() {
+ // workaround for reported Opera bug DSK-354448:
+ // onclick fires on disabled buttons with opaque content
+ function ignoreIfTargetDisabled(event) {
+ if (isDisabled(event.target)) {
+ event.stopPropagation();
+ }
+ }
+ function isDisabled(node) {
+ return node.disabled || (node.parentNode && isDisabled(node.parentNode));
+ }
+ if (navigator.userAgent.indexOf('Opera') !== -1) {
+ // use browser detection since we cannot feature-check this bug
+ document.addEventListener('click', ignoreIfTargetDisabled, true);
+ }
+})();
+
+// Checks if possible to use URL.createObjectURL()
+// Support: IE
+(function checkOnBlobSupport() {
+ // sometimes IE loosing the data created with createObjectURL(), see #3977
+ if (navigator.userAgent.indexOf('Trident') >= 0) {
+ PDFJS.disableCreateObjectURL = true;
+ }
+})();
+
+// Checks if navigator.language is supported
+(function checkNavigatorLanguage() {
+ if ('language' in navigator) {
+ return;
+ }
+ PDFJS.locale = navigator.userLanguage || 'en-US';
+})();
+
+(function checkRangeRequests() {
+ // Safari has issues with cached range requests see:
+ // https://github.com/mozilla/pdf.js/issues/3260
+ // Last tested with version 6.0.4.
+ // Support: Safari 6.0+
+ var isSafari = Object.prototype.toString.call(
+ window.HTMLElement).indexOf('Constructor') > 0;
+
+ // Older versions of Android (pre 3.0) has issues with range requests, see:
+ // https://github.com/mozilla/pdf.js/issues/3381.
+ // Make sure that we only match webkit-based Android browsers,
+ // since Firefox/Fennec works as expected.
+ // Support: Android<3.0
+ var regex = /Android\s[0-2][^\d]/;
+ var isOldAndroid = regex.test(navigator.userAgent);
+
+ // Range requests are broken in Chrome 39 and 40, https://crbug.com/442318
+ var isChromeWithRangeBug = /Chrome\/(39|40)\./.test(navigator.userAgent);
+
+ if (isSafari || isOldAndroid || isChromeWithRangeBug) {
+ PDFJS.disableRange = true;
+ PDFJS.disableStream = true;
+ }
+})();
+
+// Check if the browser supports manipulation of the history.
+// Support: IE<10, Android<4.2
+(function checkHistoryManipulation() {
+ // Android 2.x has so buggy pushState support that it was removed in
+ // Android 3.0 and restored as late as in Android 4.2.
+ // Support: Android 2.x
+ if (!history.pushState || navigator.userAgent.indexOf('Android 2.') >= 0) {
+ PDFJS.disableHistory = true;
+ }
+})();
+
+// Support: IE<11, Chrome<21, Android<4.4, Safari<6
+(function checkSetPresenceInImageData() {
+ // IE < 11 will use window.CanvasPixelArray which lacks set function.
+ if (window.CanvasPixelArray) {
+ if (typeof window.CanvasPixelArray.prototype.set !== 'function') {
+ window.CanvasPixelArray.prototype.set = function(arr) {
+ for (var i = 0, ii = this.length; i < ii; i++) {
+ this[i] = arr[i];
+ }
+ };
+ }
+ } else {
+ // Old Chrome and Android use an inaccessible CanvasPixelArray prototype.
+ // Because we cannot feature detect it, we rely on user agent parsing.
+ var polyfill = false, versionMatch;
+ if (navigator.userAgent.indexOf('Chrom') >= 0) {
+ versionMatch = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);
+ // Chrome < 21 lacks the set function.
+ polyfill = versionMatch && parseInt(versionMatch[2]) < 21;
+ } else if (navigator.userAgent.indexOf('Android') >= 0) {
+ // Android < 4.4 lacks the set function.
+ // Android >= 4.4 will contain Chrome in the user agent,
+ // thus pass the Chrome check above and not reach this block.
+ polyfill = /Android\s[0-4][^\d]/g.test(navigator.userAgent);
+ } else if (navigator.userAgent.indexOf('Safari') >= 0) {
+ versionMatch = navigator.userAgent.
+ match(/Version\/([0-9]+)\.([0-9]+)\.([0-9]+) Safari\//);
+ // Safari < 6 lacks the set function.
+ polyfill = versionMatch && parseInt(versionMatch[1]) < 6;
+ }
+
+ if (polyfill) {
+ var contextPrototype = window.CanvasRenderingContext2D.prototype;
+ contextPrototype._createImageData = contextPrototype.createImageData;
+ contextPrototype.createImageData = function(w, h) {
+ var imageData = this._createImageData(w, h);
+ imageData.data.set = function(arr) {
+ for (var i = 0, ii = this.length; i < ii; i++) {
+ this[i] = arr[i];
+ }
+ };
+ return imageData;
+ };
+ }
+ }
+})();
+
+// Support: IE<10, Android<4.0, iOS
+(function checkRequestAnimationFrame() {
+ function fakeRequestAnimationFrame(callback) {
+ window.setTimeout(callback, 20);
+ }
+
+ var isIOS = /(iPad|iPhone|iPod)/g.test(navigator.userAgent);
+ if (isIOS) {
+ // requestAnimationFrame on iOS is broken, replacing with fake one.
+ window.requestAnimationFrame = fakeRequestAnimationFrame;
+ return;
+ }
+ if ('requestAnimationFrame' in window) {
+ return;
+ }
+ window.requestAnimationFrame =
+ window.mozRequestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ fakeRequestAnimationFrame;
+})();
+
+(function checkCanvasSizeLimitation() {
+ var isIOS = /(iPad|iPhone|iPod)/g.test(navigator.userAgent);
+ var isAndroid = /Android/g.test(navigator.userAgent);
+ if (isIOS || isAndroid) {
+ // 5MP
+ PDFJS.maxCanvasPixels = 5242880;
+ }
+})();
+
+// Disable fullscreen support for certain problematic configurations.
+// Support: IE11+ (when embedded).
+(function checkFullscreenSupport() {
+ var isEmbeddedIE = (navigator.userAgent.indexOf('Trident') >= 0 &&
+ window.parent !== window);
+ if (isEmbeddedIE) {
+ PDFJS.disableFullscreen = true;
+ }
+})();
diff --git a/09/miniwebsite/ViewerJS/example.local.css b/09/miniwebsite/ViewerJS/example.local.css
new file mode 100644
index 0000000..034347d
--- /dev/null
+++ b/09/miniwebsite/ViewerJS/example.local.css
@@ -0,0 +1,27 @@
+/* This is just a sample file with CSS rules. You should write your own @font-face declarations
+ * to add support for your desired fonts.
+ */
+
+@font-face {
+ font-family: 'Novecentowide Book';
+ src: url("/ViewerJS/fonts/Novecentowide-Bold-webfont.eot");
+ src: url("/ViewerJS/fonts/Novecentowide-Bold-webfont.eot?#iefix") format("embedded-opentype"),
+ url("/ViewerJS/fonts/Novecentowide-Bold-webfont.woff") format("woff"),
+ url("/fonts/Novecentowide-Bold-webfont.ttf") format("truetype"),
+ url("/fonts/Novecentowide-Bold-webfont.svg#NovecentowideBookBold") format("svg");
+ font-weight: normal;
+ font-style: normal;
+}
+
+@font-face {
+ font-family: 'exotica';
+ src: url('/ViewerJS/fonts/Exotica-webfont.eot');
+ src: url('/ViewerJS/fonts/Exotica-webfont.eot?#iefix') format('embedded-opentype'),
+ url('/ViewerJS/fonts/Exotica-webfont.woff') format('woff'),
+ url('/ViewerJS/fonts/Exotica-webfont.ttf') format('truetype'),
+ url('/ViewerJS/fonts/Exotica-webfont.svg#exoticamedium') format('svg');
+ font-weight: normal;
+ font-style: normal;
+
+}
+
diff --git a/09/miniwebsite/ViewerJS/images/kogmbh.png b/09/miniwebsite/ViewerJS/images/kogmbh.png
new file mode 100644
index 0000000..00e8f4d
Binary files /dev/null and b/09/miniwebsite/ViewerJS/images/kogmbh.png differ
diff --git a/09/miniwebsite/ViewerJS/images/nlnet.png b/09/miniwebsite/ViewerJS/images/nlnet.png
new file mode 100644
index 0000000..e75ab2e
Binary files /dev/null and b/09/miniwebsite/ViewerJS/images/nlnet.png differ
diff --git a/09/miniwebsite/ViewerJS/images/texture.png b/09/miniwebsite/ViewerJS/images/texture.png
new file mode 100644
index 0000000..df00864
Binary files /dev/null and b/09/miniwebsite/ViewerJS/images/texture.png differ
diff --git a/09/miniwebsite/ViewerJS/images/toolbarButton-download.png b/09/miniwebsite/ViewerJS/images/toolbarButton-download.png
new file mode 100644
index 0000000..8676d8e
Binary files /dev/null and b/09/miniwebsite/ViewerJS/images/toolbarButton-download.png differ
diff --git a/09/miniwebsite/ViewerJS/images/toolbarButton-fullscreen.png b/09/miniwebsite/ViewerJS/images/toolbarButton-fullscreen.png
new file mode 100644
index 0000000..fa73095
Binary files /dev/null and b/09/miniwebsite/ViewerJS/images/toolbarButton-fullscreen.png differ
diff --git a/09/miniwebsite/ViewerJS/images/toolbarButton-menuArrows.png b/09/miniwebsite/ViewerJS/images/toolbarButton-menuArrows.png
new file mode 100644
index 0000000..31b06b5
Binary files /dev/null and b/09/miniwebsite/ViewerJS/images/toolbarButton-menuArrows.png differ
diff --git a/09/miniwebsite/ViewerJS/images/toolbarButton-pageDown.png b/09/miniwebsite/ViewerJS/images/toolbarButton-pageDown.png
new file mode 100644
index 0000000..762ac43
Binary files /dev/null and b/09/miniwebsite/ViewerJS/images/toolbarButton-pageDown.png differ
diff --git a/09/miniwebsite/ViewerJS/images/toolbarButton-pageUp.png b/09/miniwebsite/ViewerJS/images/toolbarButton-pageUp.png
new file mode 100644
index 0000000..3155b8b
Binary files /dev/null and b/09/miniwebsite/ViewerJS/images/toolbarButton-pageUp.png differ
diff --git a/09/miniwebsite/ViewerJS/images/toolbarButton-presentation.png b/09/miniwebsite/ViewerJS/images/toolbarButton-presentation.png
new file mode 100644
index 0000000..0f22423
Binary files /dev/null and b/09/miniwebsite/ViewerJS/images/toolbarButton-presentation.png differ
diff --git a/09/miniwebsite/ViewerJS/images/toolbarButton-zoomIn.png b/09/miniwebsite/ViewerJS/images/toolbarButton-zoomIn.png
new file mode 100644
index 0000000..670acd9
Binary files /dev/null and b/09/miniwebsite/ViewerJS/images/toolbarButton-zoomIn.png differ
diff --git a/09/miniwebsite/ViewerJS/images/toolbarButton-zoomOut.png b/09/miniwebsite/ViewerJS/images/toolbarButton-zoomOut.png
new file mode 100644
index 0000000..810fbf9
Binary files /dev/null and b/09/miniwebsite/ViewerJS/images/toolbarButton-zoomOut.png differ
diff --git a/09/miniwebsite/ViewerJS/index.html b/09/miniwebsite/ViewerJS/index.html
new file mode 100644
index 0000000..2eb1fd4
--- /dev/null
+++ b/09/miniwebsite/ViewerJS/index.html
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+
+ ViewerJS
+
+
+
+
+
+
+
+
+
diff --git a/09/miniwebsite/ViewerJS/pdf.js b/09/miniwebsite/ViewerJS/pdf.js
new file mode 100644
index 0000000..463d7d0
--- /dev/null
+++ b/09/miniwebsite/ViewerJS/pdf.js
@@ -0,0 +1,8052 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+/* Copyright 2012 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*jshint globalstrict: false */
+/* globals PDFJS */
+
+// Initializing PDFJS global object (if still undefined)
+if (typeof PDFJS === 'undefined') {
+ (typeof window !== 'undefined' ? window : this).PDFJS = {};
+}
+
+PDFJS.version = '1.1.114';
+PDFJS.build = '3fd44fd';
+
+(function pdfjsWrapper() {
+ // Use strict in our context only - users might not want it
+ 'use strict';
+
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+/* Copyright 2012 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* globals Cmd, ColorSpace, Dict, MozBlobBuilder, Name, PDFJS, Ref, URL,
+ Promise */
+
+'use strict';
+
+var globalScope = (typeof window === 'undefined') ? this : window;
+
+var isWorker = (typeof window === 'undefined');
+
+var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
+
+var TextRenderingMode = {
+ FILL: 0,
+ STROKE: 1,
+ FILL_STROKE: 2,
+ INVISIBLE: 3,
+ FILL_ADD_TO_PATH: 4,
+ STROKE_ADD_TO_PATH: 5,
+ FILL_STROKE_ADD_TO_PATH: 6,
+ ADD_TO_PATH: 7,
+ FILL_STROKE_MASK: 3,
+ ADD_TO_PATH_FLAG: 4
+};
+
+var ImageKind = {
+ GRAYSCALE_1BPP: 1,
+ RGB_24BPP: 2,
+ RGBA_32BPP: 3
+};
+
+var AnnotationType = {
+ WIDGET: 1,
+ TEXT: 2,
+ LINK: 3
+};
+
+var StreamType = {
+ UNKNOWN: 0,
+ FLATE: 1,
+ LZW: 2,
+ DCT: 3,
+ JPX: 4,
+ JBIG: 5,
+ A85: 6,
+ AHX: 7,
+ CCF: 8,
+ RL: 9
+};
+
+var FontType = {
+ UNKNOWN: 0,
+ TYPE1: 1,
+ TYPE1C: 2,
+ CIDFONTTYPE0: 3,
+ CIDFONTTYPE0C: 4,
+ TRUETYPE: 5,
+ CIDFONTTYPE2: 6,
+ TYPE3: 7,
+ OPENTYPE: 8,
+ TYPE0: 9,
+ MMTYPE1: 10
+};
+
+// The global PDFJS object exposes the API
+// In production, it will be declared outside a global wrapper
+// In development, it will be declared here
+if (!globalScope.PDFJS) {
+ globalScope.PDFJS = {};
+}
+
+globalScope.PDFJS.pdfBug = false;
+
+PDFJS.VERBOSITY_LEVELS = {
+ errors: 0,
+ warnings: 1,
+ infos: 5
+};
+
+// All the possible operations for an operator list.
+var OPS = PDFJS.OPS = {
+ // Intentionally start from 1 so it is easy to spot bad operators that will be
+ // 0's.
+ dependency: 1,
+ setLineWidth: 2,
+ setLineCap: 3,
+ setLineJoin: 4,
+ setMiterLimit: 5,
+ setDash: 6,
+ setRenderingIntent: 7,
+ setFlatness: 8,
+ setGState: 9,
+ save: 10,
+ restore: 11,
+ transform: 12,
+ moveTo: 13,
+ lineTo: 14,
+ curveTo: 15,
+ curveTo2: 16,
+ curveTo3: 17,
+ closePath: 18,
+ rectangle: 19,
+ stroke: 20,
+ closeStroke: 21,
+ fill: 22,
+ eoFill: 23,
+ fillStroke: 24,
+ eoFillStroke: 25,
+ closeFillStroke: 26,
+ closeEOFillStroke: 27,
+ endPath: 28,
+ clip: 29,
+ eoClip: 30,
+ beginText: 31,
+ endText: 32,
+ setCharSpacing: 33,
+ setWordSpacing: 34,
+ setHScale: 35,
+ setLeading: 36,
+ setFont: 37,
+ setTextRenderingMode: 38,
+ setTextRise: 39,
+ moveText: 40,
+ setLeadingMoveText: 41,
+ setTextMatrix: 42,
+ nextLine: 43,
+ showText: 44,
+ showSpacedText: 45,
+ nextLineShowText: 46,
+ nextLineSetSpacingShowText: 47,
+ setCharWidth: 48,
+ setCharWidthAndBounds: 49,
+ setStrokeColorSpace: 50,
+ setFillColorSpace: 51,
+ setStrokeColor: 52,
+ setStrokeColorN: 53,
+ setFillColor: 54,
+ setFillColorN: 55,
+ setStrokeGray: 56,
+ setFillGray: 57,
+ setStrokeRGBColor: 58,
+ setFillRGBColor: 59,
+ setStrokeCMYKColor: 60,
+ setFillCMYKColor: 61,
+ shadingFill: 62,
+ beginInlineImage: 63,
+ beginImageData: 64,
+ endInlineImage: 65,
+ paintXObject: 66,
+ markPoint: 67,
+ markPointProps: 68,
+ beginMarkedContent: 69,
+ beginMarkedContentProps: 70,
+ endMarkedContent: 71,
+ beginCompat: 72,
+ endCompat: 73,
+ paintFormXObjectBegin: 74,
+ paintFormXObjectEnd: 75,
+ beginGroup: 76,
+ endGroup: 77,
+ beginAnnotations: 78,
+ endAnnotations: 79,
+ beginAnnotation: 80,
+ endAnnotation: 81,
+ paintJpegXObject: 82,
+ paintImageMaskXObject: 83,
+ paintImageMaskXObjectGroup: 84,
+ paintImageXObject: 85,
+ paintInlineImageXObject: 86,
+ paintInlineImageXObjectGroup: 87,
+ paintImageXObjectRepeat: 88,
+ paintImageMaskXObjectRepeat: 89,
+ paintSolidColorImageMask: 90,
+ constructPath: 91
+};
+
+// A notice for devs. These are good for things that are helpful to devs, such
+// as warning that Workers were disabled, which is important to devs but not
+// end users.
+function info(msg) {
+ if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.infos) {
+ console.log('Info: ' + msg);
+ }
+}
+
+// Non-fatal warnings.
+function warn(msg) {
+ if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.warnings) {
+ console.log('Warning: ' + msg);
+ }
+}
+
+// Fatal errors that should trigger the fallback UI and halt execution by
+// throwing an exception.
+function error(msg) {
+ if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.errors) {
+ console.log('Error: ' + msg);
+ console.log(backtrace());
+ }
+ UnsupportedManager.notify(UNSUPPORTED_FEATURES.unknown);
+ throw new Error(msg);
+}
+
+function backtrace() {
+ try {
+ throw new Error();
+ } catch (e) {
+ return e.stack ? e.stack.split('\n').slice(2).join('\n') : '';
+ }
+}
+
+function assert(cond, msg) {
+ if (!cond) {
+ error(msg);
+ }
+}
+
+var UNSUPPORTED_FEATURES = PDFJS.UNSUPPORTED_FEATURES = {
+ unknown: 'unknown',
+ forms: 'forms',
+ javaScript: 'javaScript',
+ smask: 'smask',
+ shadingPattern: 'shadingPattern',
+ font: 'font'
+};
+
+var UnsupportedManager = PDFJS.UnsupportedManager =
+ (function UnsupportedManagerClosure() {
+ var listeners = [];
+ return {
+ listen: function (cb) {
+ listeners.push(cb);
+ },
+ notify: function (featureId) {
+ warn('Unsupported feature "' + featureId + '"');
+ for (var i = 0, ii = listeners.length; i < ii; i++) {
+ listeners[i](featureId);
+ }
+ }
+ };
+})();
+
+// Combines two URLs. The baseUrl shall be absolute URL. If the url is an
+// absolute URL, it will be returned as is.
+function combineUrl(baseUrl, url) {
+ if (!url) {
+ return baseUrl;
+ }
+ if (/^[a-z][a-z0-9+\-.]*:/i.test(url)) {
+ return url;
+ }
+ var i;
+ if (url.charAt(0) === '/') {
+ // absolute path
+ i = baseUrl.indexOf('://');
+ if (url.charAt(1) === '/') {
+ ++i;
+ } else {
+ i = baseUrl.indexOf('/', i + 3);
+ }
+ return baseUrl.substring(0, i) + url;
+ } else {
+ // relative path
+ var pathLength = baseUrl.length;
+ i = baseUrl.lastIndexOf('#');
+ pathLength = i >= 0 ? i : pathLength;
+ i = baseUrl.lastIndexOf('?', pathLength);
+ pathLength = i >= 0 ? i : pathLength;
+ var prefixLength = baseUrl.lastIndexOf('/', pathLength);
+ return baseUrl.substring(0, prefixLength + 1) + url;
+ }
+}
+
+// Validates if URL is safe and allowed, e.g. to avoid XSS.
+function isValidUrl(url, allowRelative) {
+ if (!url) {
+ return false;
+ }
+ // RFC 3986 (http://tools.ietf.org/html/rfc3986#section-3.1)
+ // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+ var protocol = /^[a-z][a-z0-9+\-.]*(?=:)/i.exec(url);
+ if (!protocol) {
+ return allowRelative;
+ }
+ protocol = protocol[0].toLowerCase();
+ switch (protocol) {
+ case 'http':
+ case 'https':
+ case 'ftp':
+ case 'mailto':
+ case 'tel':
+ return true;
+ default:
+ return false;
+ }
+}
+PDFJS.isValidUrl = isValidUrl;
+
+function shadow(obj, prop, value) {
+ Object.defineProperty(obj, prop, { value: value,
+ enumerable: true,
+ configurable: true,
+ writable: false });
+ return value;
+}
+PDFJS.shadow = shadow;
+
+var PasswordResponses = PDFJS.PasswordResponses = {
+ NEED_PASSWORD: 1,
+ INCORRECT_PASSWORD: 2
+};
+
+var PasswordException = (function PasswordExceptionClosure() {
+ function PasswordException(msg, code) {
+ this.name = 'PasswordException';
+ this.message = msg;
+ this.code = code;
+ }
+
+ PasswordException.prototype = new Error();
+ PasswordException.constructor = PasswordException;
+
+ return PasswordException;
+})();
+PDFJS.PasswordException = PasswordException;
+
+var UnknownErrorException = (function UnknownErrorExceptionClosure() {
+ function UnknownErrorException(msg, details) {
+ this.name = 'UnknownErrorException';
+ this.message = msg;
+ this.details = details;
+ }
+
+ UnknownErrorException.prototype = new Error();
+ UnknownErrorException.constructor = UnknownErrorException;
+
+ return UnknownErrorException;
+})();
+PDFJS.UnknownErrorException = UnknownErrorException;
+
+var InvalidPDFException = (function InvalidPDFExceptionClosure() {
+ function InvalidPDFException(msg) {
+ this.name = 'InvalidPDFException';
+ this.message = msg;
+ }
+
+ InvalidPDFException.prototype = new Error();
+ InvalidPDFException.constructor = InvalidPDFException;
+
+ return InvalidPDFException;
+})();
+PDFJS.InvalidPDFException = InvalidPDFException;
+
+var MissingPDFException = (function MissingPDFExceptionClosure() {
+ function MissingPDFException(msg) {
+ this.name = 'MissingPDFException';
+ this.message = msg;
+ }
+
+ MissingPDFException.prototype = new Error();
+ MissingPDFException.constructor = MissingPDFException;
+
+ return MissingPDFException;
+})();
+PDFJS.MissingPDFException = MissingPDFException;
+
+var UnexpectedResponseException =
+ (function UnexpectedResponseExceptionClosure() {
+ function UnexpectedResponseException(msg, status) {
+ this.name = 'UnexpectedResponseException';
+ this.message = msg;
+ this.status = status;
+ }
+
+ UnexpectedResponseException.prototype = new Error();
+ UnexpectedResponseException.constructor = UnexpectedResponseException;
+
+ return UnexpectedResponseException;
+})();
+PDFJS.UnexpectedResponseException = UnexpectedResponseException;
+
+var NotImplementedException = (function NotImplementedExceptionClosure() {
+ function NotImplementedException(msg) {
+ this.message = msg;
+ }
+
+ NotImplementedException.prototype = new Error();
+ NotImplementedException.prototype.name = 'NotImplementedException';
+ NotImplementedException.constructor = NotImplementedException;
+
+ return NotImplementedException;
+})();
+
+var MissingDataException = (function MissingDataExceptionClosure() {
+ function MissingDataException(begin, end) {
+ this.begin = begin;
+ this.end = end;
+ this.message = 'Missing data [' + begin + ', ' + end + ')';
+ }
+
+ MissingDataException.prototype = new Error();
+ MissingDataException.prototype.name = 'MissingDataException';
+ MissingDataException.constructor = MissingDataException;
+
+ return MissingDataException;
+})();
+
+var XRefParseException = (function XRefParseExceptionClosure() {
+ function XRefParseException(msg) {
+ this.message = msg;
+ }
+
+ XRefParseException.prototype = new Error();
+ XRefParseException.prototype.name = 'XRefParseException';
+ XRefParseException.constructor = XRefParseException;
+
+ return XRefParseException;
+})();
+
+
+function bytesToString(bytes) {
+ assert(bytes !== null && typeof bytes === 'object' &&
+ bytes.length !== undefined, 'Invalid argument for bytesToString');
+ var length = bytes.length;
+ var MAX_ARGUMENT_COUNT = 8192;
+ if (length < MAX_ARGUMENT_COUNT) {
+ return String.fromCharCode.apply(null, bytes);
+ }
+ var strBuf = [];
+ for (var i = 0; i < length; i += MAX_ARGUMENT_COUNT) {
+ var chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length);
+ var chunk = bytes.subarray(i, chunkEnd);
+ strBuf.push(String.fromCharCode.apply(null, chunk));
+ }
+ return strBuf.join('');
+}
+
+function stringToBytes(str) {
+ assert(typeof str === 'string', 'Invalid argument for stringToBytes');
+ var length = str.length;
+ var bytes = new Uint8Array(length);
+ for (var i = 0; i < length; ++i) {
+ bytes[i] = str.charCodeAt(i) & 0xFF;
+ }
+ return bytes;
+}
+
+function string32(value) {
+ return String.fromCharCode((value >> 24) & 0xff, (value >> 16) & 0xff,
+ (value >> 8) & 0xff, value & 0xff);
+}
+
+function log2(x) {
+ var n = 1, i = 0;
+ while (x > n) {
+ n <<= 1;
+ i++;
+ }
+ return i;
+}
+
+function readInt8(data, start) {
+ return (data[start] << 24) >> 24;
+}
+
+function readUint16(data, offset) {
+ return (data[offset] << 8) | data[offset + 1];
+}
+
+function readUint32(data, offset) {
+ return ((data[offset] << 24) | (data[offset + 1] << 16) |
+ (data[offset + 2] << 8) | data[offset + 3]) >>> 0;
+}
+
+// Lazy test the endianness of the platform
+// NOTE: This will be 'true' for simulated TypedArrays
+function isLittleEndian() {
+ var buffer8 = new Uint8Array(2);
+ buffer8[0] = 1;
+ var buffer16 = new Uint16Array(buffer8.buffer);
+ return (buffer16[0] === 1);
+}
+
+Object.defineProperty(PDFJS, 'isLittleEndian', {
+ configurable: true,
+ get: function PDFJS_isLittleEndian() {
+ return shadow(PDFJS, 'isLittleEndian', isLittleEndian());
+ }
+});
+
+//#if !(FIREFOX || MOZCENTRAL || B2G || CHROME)
+//// Lazy test if the userAgant support CanvasTypedArrays
+function hasCanvasTypedArrays() {
+ var canvas = document.createElement('canvas');
+ canvas.width = canvas.height = 1;
+ var ctx = canvas.getContext('2d');
+ var imageData = ctx.createImageData(1, 1);
+ return (typeof imageData.data.buffer !== 'undefined');
+}
+
+Object.defineProperty(PDFJS, 'hasCanvasTypedArrays', {
+ configurable: true,
+ get: function PDFJS_hasCanvasTypedArrays() {
+ return shadow(PDFJS, 'hasCanvasTypedArrays', hasCanvasTypedArrays());
+ }
+});
+
+var Uint32ArrayView = (function Uint32ArrayViewClosure() {
+
+ function Uint32ArrayView(buffer, length) {
+ this.buffer = buffer;
+ this.byteLength = buffer.length;
+ this.length = length === undefined ? (this.byteLength >> 2) : length;
+ ensureUint32ArrayViewProps(this.length);
+ }
+ Uint32ArrayView.prototype = Object.create(null);
+
+ var uint32ArrayViewSetters = 0;
+ function createUint32ArrayProp(index) {
+ return {
+ get: function () {
+ var buffer = this.buffer, offset = index << 2;
+ return (buffer[offset] | (buffer[offset + 1] << 8) |
+ (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24)) >>> 0;
+ },
+ set: function (value) {
+ var buffer = this.buffer, offset = index << 2;
+ buffer[offset] = value & 255;
+ buffer[offset + 1] = (value >> 8) & 255;
+ buffer[offset + 2] = (value >> 16) & 255;
+ buffer[offset + 3] = (value >>> 24) & 255;
+ }
+ };
+ }
+
+ function ensureUint32ArrayViewProps(length) {
+ while (uint32ArrayViewSetters < length) {
+ Object.defineProperty(Uint32ArrayView.prototype,
+ uint32ArrayViewSetters,
+ createUint32ArrayProp(uint32ArrayViewSetters));
+ uint32ArrayViewSetters++;
+ }
+ }
+
+ return Uint32ArrayView;
+})();
+//#else
+//PDFJS.hasCanvasTypedArrays = true;
+//#endif
+
+var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
+
+var Util = PDFJS.Util = (function UtilClosure() {
+ function Util() {}
+
+ var rgbBuf = ['rgb(', 0, ',', 0, ',', 0, ')'];
+
+ // makeCssRgb() can be called thousands of times. Using |rgbBuf| avoids
+ // creating many intermediate strings.
+ Util.makeCssRgb = function Util_makeCssRgb(r, g, b) {
+ rgbBuf[1] = r;
+ rgbBuf[3] = g;
+ rgbBuf[5] = b;
+ return rgbBuf.join('');
+ };
+
+ // Concatenates two transformation matrices together and returns the result.
+ Util.transform = function Util_transform(m1, m2) {
+ return [
+ m1[0] * m2[0] + m1[2] * m2[1],
+ m1[1] * m2[0] + m1[3] * m2[1],
+ m1[0] * m2[2] + m1[2] * m2[3],
+ m1[1] * m2[2] + m1[3] * m2[3],
+ m1[0] * m2[4] + m1[2] * m2[5] + m1[4],
+ m1[1] * m2[4] + m1[3] * m2[5] + m1[5]
+ ];
+ };
+
+ // For 2d affine transforms
+ Util.applyTransform = function Util_applyTransform(p, m) {
+ var xt = p[0] * m[0] + p[1] * m[2] + m[4];
+ var yt = p[0] * m[1] + p[1] * m[3] + m[5];
+ return [xt, yt];
+ };
+
+ Util.applyInverseTransform = function Util_applyInverseTransform(p, m) {
+ var d = m[0] * m[3] - m[1] * m[2];
+ var xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d;
+ var yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d;
+ return [xt, yt];
+ };
+
+ // Applies the transform to the rectangle and finds the minimum axially
+ // aligned bounding box.
+ Util.getAxialAlignedBoundingBox =
+ function Util_getAxialAlignedBoundingBox(r, m) {
+
+ var p1 = Util.applyTransform(r, m);
+ var p2 = Util.applyTransform(r.slice(2, 4), m);
+ var p3 = Util.applyTransform([r[0], r[3]], m);
+ var p4 = Util.applyTransform([r[2], r[1]], m);
+ return [
+ Math.min(p1[0], p2[0], p3[0], p4[0]),
+ Math.min(p1[1], p2[1], p3[1], p4[1]),
+ Math.max(p1[0], p2[0], p3[0], p4[0]),
+ Math.max(p1[1], p2[1], p3[1], p4[1])
+ ];
+ };
+
+ Util.inverseTransform = function Util_inverseTransform(m) {
+ var d = m[0] * m[3] - m[1] * m[2];
+ return [m[3] / d, -m[1] / d, -m[2] / d, m[0] / d,
+ (m[2] * m[5] - m[4] * m[3]) / d, (m[4] * m[1] - m[5] * m[0]) / d];
+ };
+
+ // Apply a generic 3d matrix M on a 3-vector v:
+ // | a b c | | X |
+ // | d e f | x | Y |
+ // | g h i | | Z |
+ // M is assumed to be serialized as [a,b,c,d,e,f,g,h,i],
+ // with v as [X,Y,Z]
+ Util.apply3dTransform = function Util_apply3dTransform(m, v) {
+ return [
+ m[0] * v[0] + m[1] * v[1] + m[2] * v[2],
+ m[3] * v[0] + m[4] * v[1] + m[5] * v[2],
+ m[6] * v[0] + m[7] * v[1] + m[8] * v[2]
+ ];
+ };
+
+ // This calculation uses Singular Value Decomposition.
+ // The SVD can be represented with formula A = USV. We are interested in the
+ // matrix S here because it represents the scale values.
+ Util.singularValueDecompose2dScale =
+ function Util_singularValueDecompose2dScale(m) {
+
+ var transpose = [m[0], m[2], m[1], m[3]];
+
+ // Multiply matrix m with its transpose.
+ var a = m[0] * transpose[0] + m[1] * transpose[2];
+ var b = m[0] * transpose[1] + m[1] * transpose[3];
+ var c = m[2] * transpose[0] + m[3] * transpose[2];
+ var d = m[2] * transpose[1] + m[3] * transpose[3];
+
+ // Solve the second degree polynomial to get roots.
+ var first = (a + d) / 2;
+ var second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2;
+ var sx = first + second || 1;
+ var sy = first - second || 1;
+
+ // Scale values are the square roots of the eigenvalues.
+ return [Math.sqrt(sx), Math.sqrt(sy)];
+ };
+
+ // Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2)
+ // For coordinate systems whose origin lies in the bottom-left, this
+ // means normalization to (BL,TR) ordering. For systems with origin in the
+ // top-left, this means (TL,BR) ordering.
+ Util.normalizeRect = function Util_normalizeRect(rect) {
+ var r = rect.slice(0); // clone rect
+ if (rect[0] > rect[2]) {
+ r[0] = rect[2];
+ r[2] = rect[0];
+ }
+ if (rect[1] > rect[3]) {
+ r[1] = rect[3];
+ r[3] = rect[1];
+ }
+ return r;
+ };
+
+ // Returns a rectangle [x1, y1, x2, y2] corresponding to the
+ // intersection of rect1 and rect2. If no intersection, returns 'false'
+ // The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2]
+ Util.intersect = function Util_intersect(rect1, rect2) {
+ function compare(a, b) {
+ return a - b;
+ }
+
+ // Order points along the axes
+ var orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare),
+ orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare),
+ result = [];
+
+ rect1 = Util.normalizeRect(rect1);
+ rect2 = Util.normalizeRect(rect2);
+
+ // X: first and second points belong to different rectangles?
+ if ((orderedX[0] === rect1[0] && orderedX[1] === rect2[0]) ||
+ (orderedX[0] === rect2[0] && orderedX[1] === rect1[0])) {
+ // Intersection must be between second and third points
+ result[0] = orderedX[1];
+ result[2] = orderedX[2];
+ } else {
+ return false;
+ }
+
+ // Y: first and second points belong to different rectangles?
+ if ((orderedY[0] === rect1[1] && orderedY[1] === rect2[1]) ||
+ (orderedY[0] === rect2[1] && orderedY[1] === rect1[1])) {
+ // Intersection must be between second and third points
+ result[1] = orderedY[1];
+ result[3] = orderedY[2];
+ } else {
+ return false;
+ }
+
+ return result;
+ };
+
+ Util.sign = function Util_sign(num) {
+ return num < 0 ? -1 : 1;
+ };
+
+ Util.appendToArray = function Util_appendToArray(arr1, arr2) {
+ Array.prototype.push.apply(arr1, arr2);
+ };
+
+ Util.prependToArray = function Util_prependToArray(arr1, arr2) {
+ Array.prototype.unshift.apply(arr1, arr2);
+ };
+
+ Util.extendObj = function extendObj(obj1, obj2) {
+ for (var key in obj2) {
+ obj1[key] = obj2[key];
+ }
+ };
+
+ Util.getInheritableProperty = function Util_getInheritableProperty(dict,
+ name) {
+ while (dict && !dict.has(name)) {
+ dict = dict.get('Parent');
+ }
+ if (!dict) {
+ return null;
+ }
+ return dict.get(name);
+ };
+
+ Util.inherit = function Util_inherit(sub, base, prototype) {
+ sub.prototype = Object.create(base.prototype);
+ sub.prototype.constructor = sub;
+ for (var prop in prototype) {
+ sub.prototype[prop] = prototype[prop];
+ }
+ };
+
+ Util.loadScript = function Util_loadScript(src, callback) {
+ var script = document.createElement('script');
+ var loaded = false;
+ script.setAttribute('src', src);
+ if (callback) {
+ script.onload = function() {
+ if (!loaded) {
+ callback();
+ }
+ loaded = true;
+ };
+ }
+ document.getElementsByTagName('head')[0].appendChild(script);
+ };
+
+ return Util;
+})();
+
+/**
+ * PDF page viewport created based on scale, rotation and offset.
+ * @class
+ * @alias PDFJS.PageViewport
+ */
+var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
+ /**
+ * @constructor
+ * @private
+ * @param viewBox {Array} xMin, yMin, xMax and yMax coordinates.
+ * @param scale {number} scale of the viewport.
+ * @param rotation {number} rotations of the viewport in degrees.
+ * @param offsetX {number} offset X
+ * @param offsetY {number} offset Y
+ * @param dontFlip {boolean} if true, axis Y will not be flipped.
+ */
+ function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) {
+ this.viewBox = viewBox;
+ this.scale = scale;
+ this.rotation = rotation;
+ this.offsetX = offsetX;
+ this.offsetY = offsetY;
+
+ // creating transform to convert pdf coordinate system to the normal
+ // canvas like coordinates taking in account scale and rotation
+ var centerX = (viewBox[2] + viewBox[0]) / 2;
+ var centerY = (viewBox[3] + viewBox[1]) / 2;
+ var rotateA, rotateB, rotateC, rotateD;
+ rotation = rotation % 360;
+ rotation = rotation < 0 ? rotation + 360 : rotation;
+ switch (rotation) {
+ case 180:
+ rotateA = -1; rotateB = 0; rotateC = 0; rotateD = 1;
+ break;
+ case 90:
+ rotateA = 0; rotateB = 1; rotateC = 1; rotateD = 0;
+ break;
+ case 270:
+ rotateA = 0; rotateB = -1; rotateC = -1; rotateD = 0;
+ break;
+ //case 0:
+ default:
+ rotateA = 1; rotateB = 0; rotateC = 0; rotateD = -1;
+ break;
+ }
+
+ if (dontFlip) {
+ rotateC = -rotateC; rotateD = -rotateD;
+ }
+
+ var offsetCanvasX, offsetCanvasY;
+ var width, height;
+ if (rotateA === 0) {
+ offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX;
+ offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY;
+ width = Math.abs(viewBox[3] - viewBox[1]) * scale;
+ height = Math.abs(viewBox[2] - viewBox[0]) * scale;
+ } else {
+ offsetCanvasX = Math.abs(centerX - viewBox[0]) * scale + offsetX;
+ offsetCanvasY = Math.abs(centerY - viewBox[1]) * scale + offsetY;
+ width = Math.abs(viewBox[2] - viewBox[0]) * scale;
+ height = Math.abs(viewBox[3] - viewBox[1]) * scale;
+ }
+ // creating transform for the following operations:
+ // translate(-centerX, -centerY), rotate and flip vertically,
+ // scale, and translate(offsetCanvasX, offsetCanvasY)
+ this.transform = [
+ rotateA * scale,
+ rotateB * scale,
+ rotateC * scale,
+ rotateD * scale,
+ offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY,
+ offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY
+ ];
+
+ this.width = width;
+ this.height = height;
+ this.fontScale = scale;
+ }
+ PageViewport.prototype = /** @lends PDFJS.PageViewport.prototype */ {
+ /**
+ * Clones viewport with additional properties.
+ * @param args {Object} (optional) If specified, may contain the 'scale' or
+ * 'rotation' properties to override the corresponding properties in
+ * the cloned viewport.
+ * @returns {PDFJS.PageViewport} Cloned viewport.
+ */
+ clone: function PageViewPort_clone(args) {
+ args = args || {};
+ var scale = 'scale' in args ? args.scale : this.scale;
+ var rotation = 'rotation' in args ? args.rotation : this.rotation;
+ return new PageViewport(this.viewBox.slice(), scale, rotation,
+ this.offsetX, this.offsetY, args.dontFlip);
+ },
+ /**
+ * Converts PDF point to the viewport coordinates. For examples, useful for
+ * converting PDF location into canvas pixel coordinates.
+ * @param x {number} X coordinate.
+ * @param y {number} Y coordinate.
+ * @returns {Object} Object that contains 'x' and 'y' properties of the
+ * point in the viewport coordinate space.
+ * @see {@link convertToPdfPoint}
+ * @see {@link convertToViewportRectangle}
+ */
+ convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) {
+ return Util.applyTransform([x, y], this.transform);
+ },
+ /**
+ * Converts PDF rectangle to the viewport coordinates.
+ * @param rect {Array} xMin, yMin, xMax and yMax coordinates.
+ * @returns {Array} Contains corresponding coordinates of the rectangle
+ * in the viewport coordinate space.
+ * @see {@link convertToViewportPoint}
+ */
+ convertToViewportRectangle:
+ function PageViewport_convertToViewportRectangle(rect) {
+ var tl = Util.applyTransform([rect[0], rect[1]], this.transform);
+ var br = Util.applyTransform([rect[2], rect[3]], this.transform);
+ return [tl[0], tl[1], br[0], br[1]];
+ },
+ /**
+ * Converts viewport coordinates to the PDF location. For examples, useful
+ * for converting canvas pixel location into PDF one.
+ * @param x {number} X coordinate.
+ * @param y {number} Y coordinate.
+ * @returns {Object} Object that contains 'x' and 'y' properties of the
+ * point in the PDF coordinate space.
+ * @see {@link convertToViewportPoint}
+ */
+ convertToPdfPoint: function PageViewport_convertToPdfPoint(x, y) {
+ return Util.applyInverseTransform([x, y], this.transform);
+ }
+ };
+ return PageViewport;
+})();
+
+var PDFStringTranslateTable = [
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x2D8, 0x2C7, 0x2C6, 0x2D9, 0x2DD, 0x2DB, 0x2DA, 0x2DC, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014,
+ 0x2013, 0x192, 0x2044, 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C,
+ 0x201D, 0x2018, 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x141, 0x152, 0x160,
+ 0x178, 0x17D, 0x131, 0x142, 0x153, 0x161, 0x17E, 0, 0x20AC
+];
+
+function stringToPDFString(str) {
+ var i, n = str.length, strBuf = [];
+ if (str[0] === '\xFE' && str[1] === '\xFF') {
+ // UTF16BE BOM
+ for (i = 2; i < n; i += 2) {
+ strBuf.push(String.fromCharCode(
+ (str.charCodeAt(i) << 8) | str.charCodeAt(i + 1)));
+ }
+ } else {
+ for (i = 0; i < n; ++i) {
+ var code = PDFStringTranslateTable[str.charCodeAt(i)];
+ strBuf.push(code ? String.fromCharCode(code) : str.charAt(i));
+ }
+ }
+ return strBuf.join('');
+}
+
+function stringToUTF8String(str) {
+ return decodeURIComponent(escape(str));
+}
+
+function isEmptyObj(obj) {
+ for (var key in obj) {
+ return false;
+ }
+ return true;
+}
+
+function isBool(v) {
+ return typeof v === 'boolean';
+}
+
+function isInt(v) {
+ return typeof v === 'number' && ((v | 0) === v);
+}
+
+function isNum(v) {
+ return typeof v === 'number';
+}
+
+function isString(v) {
+ return typeof v === 'string';
+}
+
+function isName(v) {
+ return v instanceof Name;
+}
+
+function isCmd(v, cmd) {
+ return v instanceof Cmd && (cmd === undefined || v.cmd === cmd);
+}
+
+function isDict(v, type) {
+ if (!(v instanceof Dict)) {
+ return false;
+ }
+ if (!type) {
+ return true;
+ }
+ var dictType = v.get('Type');
+ return isName(dictType) && dictType.name === type;
+}
+
+function isArray(v) {
+ return v instanceof Array;
+}
+
+function isStream(v) {
+ return typeof v === 'object' && v !== null && v.getBytes !== undefined;
+}
+
+function isArrayBuffer(v) {
+ return typeof v === 'object' && v !== null && v.byteLength !== undefined;
+}
+
+function isRef(v) {
+ return v instanceof Ref;
+}
+
+/**
+ * Promise Capability object.
+ *
+ * @typedef {Object} PromiseCapability
+ * @property {Promise} promise - A promise object.
+ * @property {function} resolve - Fullfills the promise.
+ * @property {function} reject - Rejects the promise.
+ */
+
+/**
+ * Creates a promise capability object.
+ * @alias PDFJS.createPromiseCapability
+ *
+ * @return {PromiseCapability} A capability object contains:
+ * - a Promise, resolve and reject methods.
+ */
+function createPromiseCapability() {
+ var capability = {};
+ capability.promise = new Promise(function (resolve, reject) {
+ capability.resolve = resolve;
+ capability.reject = reject;
+ });
+ return capability;
+}
+
+PDFJS.createPromiseCapability = createPromiseCapability;
+
+/**
+ * Polyfill for Promises:
+ * The following promise implementation tries to generally implement the
+ * Promise/A+ spec. Some notable differences from other promise libaries are:
+ * - There currently isn't a seperate deferred and promise object.
+ * - Unhandled rejections eventually show an error if they aren't handled.
+ *
+ * Based off of the work in:
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=810490
+ */
+(function PromiseClosure() {
+ if (globalScope.Promise) {
+ // Promises existing in the DOM/Worker, checking presence of all/resolve
+ if (typeof globalScope.Promise.all !== 'function') {
+ globalScope.Promise.all = function (iterable) {
+ var count = 0, results = [], resolve, reject;
+ var promise = new globalScope.Promise(function (resolve_, reject_) {
+ resolve = resolve_;
+ reject = reject_;
+ });
+ iterable.forEach(function (p, i) {
+ count++;
+ p.then(function (result) {
+ results[i] = result;
+ count--;
+ if (count === 0) {
+ resolve(results);
+ }
+ }, reject);
+ });
+ if (count === 0) {
+ resolve(results);
+ }
+ return promise;
+ };
+ }
+ if (typeof globalScope.Promise.resolve !== 'function') {
+ globalScope.Promise.resolve = function (value) {
+ return new globalScope.Promise(function (resolve) { resolve(value); });
+ };
+ }
+ if (typeof globalScope.Promise.reject !== 'function') {
+ globalScope.Promise.reject = function (reason) {
+ return new globalScope.Promise(function (resolve, reject) {
+ reject(reason);
+ });
+ };
+ }
+ if (typeof globalScope.Promise.prototype.catch !== 'function') {
+ globalScope.Promise.prototype.catch = function (onReject) {
+ return globalScope.Promise.prototype.then(undefined, onReject);
+ };
+ }
+ return;
+ }
+//#if !MOZCENTRAL
+ var STATUS_PENDING = 0;
+ var STATUS_RESOLVED = 1;
+ var STATUS_REJECTED = 2;
+
+ // In an attempt to avoid silent exceptions, unhandled rejections are
+ // tracked and if they aren't handled in a certain amount of time an
+ // error is logged.
+ var REJECTION_TIMEOUT = 500;
+
+ var HandlerManager = {
+ handlers: [],
+ running: false,
+ unhandledRejections: [],
+ pendingRejectionCheck: false,
+
+ scheduleHandlers: function scheduleHandlers(promise) {
+ if (promise._status === STATUS_PENDING) {
+ return;
+ }
+
+ this.handlers = this.handlers.concat(promise._handlers);
+ promise._handlers = [];
+
+ if (this.running) {
+ return;
+ }
+ this.running = true;
+
+ setTimeout(this.runHandlers.bind(this), 0);
+ },
+
+ runHandlers: function runHandlers() {
+ var RUN_TIMEOUT = 1; // ms
+ var timeoutAt = Date.now() + RUN_TIMEOUT;
+ while (this.handlers.length > 0) {
+ var handler = this.handlers.shift();
+
+ var nextStatus = handler.thisPromise._status;
+ var nextValue = handler.thisPromise._value;
+
+ try {
+ if (nextStatus === STATUS_RESOLVED) {
+ if (typeof handler.onResolve === 'function') {
+ nextValue = handler.onResolve(nextValue);
+ }
+ } else if (typeof handler.onReject === 'function') {
+ nextValue = handler.onReject(nextValue);
+ nextStatus = STATUS_RESOLVED;
+
+ if (handler.thisPromise._unhandledRejection) {
+ this.removeUnhandeledRejection(handler.thisPromise);
+ }
+ }
+ } catch (ex) {
+ nextStatus = STATUS_REJECTED;
+ nextValue = ex;
+ }
+
+ handler.nextPromise._updateStatus(nextStatus, nextValue);
+ if (Date.now() >= timeoutAt) {
+ break;
+ }
+ }
+
+ if (this.handlers.length > 0) {
+ setTimeout(this.runHandlers.bind(this), 0);
+ return;
+ }
+
+ this.running = false;
+ },
+
+ addUnhandledRejection: function addUnhandledRejection(promise) {
+ this.unhandledRejections.push({
+ promise: promise,
+ time: Date.now()
+ });
+ this.scheduleRejectionCheck();
+ },
+
+ removeUnhandeledRejection: function removeUnhandeledRejection(promise) {
+ promise._unhandledRejection = false;
+ for (var i = 0; i < this.unhandledRejections.length; i++) {
+ if (this.unhandledRejections[i].promise === promise) {
+ this.unhandledRejections.splice(i);
+ i--;
+ }
+ }
+ },
+
+ scheduleRejectionCheck: function scheduleRejectionCheck() {
+ if (this.pendingRejectionCheck) {
+ return;
+ }
+ this.pendingRejectionCheck = true;
+ setTimeout(function rejectionCheck() {
+ this.pendingRejectionCheck = false;
+ var now = Date.now();
+ for (var i = 0; i < this.unhandledRejections.length; i++) {
+ if (now - this.unhandledRejections[i].time > REJECTION_TIMEOUT) {
+ var unhandled = this.unhandledRejections[i].promise._value;
+ var msg = 'Unhandled rejection: ' + unhandled;
+ if (unhandled.stack) {
+ msg += '\n' + unhandled.stack;
+ }
+ warn(msg);
+ this.unhandledRejections.splice(i);
+ i--;
+ }
+ }
+ if (this.unhandledRejections.length) {
+ this.scheduleRejectionCheck();
+ }
+ }.bind(this), REJECTION_TIMEOUT);
+ }
+ };
+
+ function Promise(resolver) {
+ this._status = STATUS_PENDING;
+ this._handlers = [];
+ try {
+ resolver.call(this, this._resolve.bind(this), this._reject.bind(this));
+ } catch (e) {
+ this._reject(e);
+ }
+ }
+ /**
+ * Builds a promise that is resolved when all the passed in promises are
+ * resolved.
+ * @param {array} array of data and/or promises to wait for.
+ * @return {Promise} New dependant promise.
+ */
+ Promise.all = function Promise_all(promises) {
+ var resolveAll, rejectAll;
+ var deferred = new Promise(function (resolve, reject) {
+ resolveAll = resolve;
+ rejectAll = reject;
+ });
+ var unresolved = promises.length;
+ var results = [];
+ if (unresolved === 0) {
+ resolveAll(results);
+ return deferred;
+ }
+ function reject(reason) {
+ if (deferred._status === STATUS_REJECTED) {
+ return;
+ }
+ results = [];
+ rejectAll(reason);
+ }
+ for (var i = 0, ii = promises.length; i < ii; ++i) {
+ var promise = promises[i];
+ var resolve = (function(i) {
+ return function(value) {
+ if (deferred._status === STATUS_REJECTED) {
+ return;
+ }
+ results[i] = value;
+ unresolved--;
+ if (unresolved === 0) {
+ resolveAll(results);
+ }
+ };
+ })(i);
+ if (Promise.isPromise(promise)) {
+ promise.then(resolve, reject);
+ } else {
+ resolve(promise);
+ }
+ }
+ return deferred;
+ };
+
+ /**
+ * Checks if the value is likely a promise (has a 'then' function).
+ * @return {boolean} true if value is thenable
+ */
+ Promise.isPromise = function Promise_isPromise(value) {
+ return value && typeof value.then === 'function';
+ };
+
+ /**
+ * Creates resolved promise
+ * @param value resolve value
+ * @returns {Promise}
+ */
+ Promise.resolve = function Promise_resolve(value) {
+ return new Promise(function (resolve) { resolve(value); });
+ };
+
+ /**
+ * Creates rejected promise
+ * @param reason rejection value
+ * @returns {Promise}
+ */
+ Promise.reject = function Promise_reject(reason) {
+ return new Promise(function (resolve, reject) { reject(reason); });
+ };
+
+ Promise.prototype = {
+ _status: null,
+ _value: null,
+ _handlers: null,
+ _unhandledRejection: null,
+
+ _updateStatus: function Promise__updateStatus(status, value) {
+ if (this._status === STATUS_RESOLVED ||
+ this._status === STATUS_REJECTED) {
+ return;
+ }
+
+ if (status === STATUS_RESOLVED &&
+ Promise.isPromise(value)) {
+ value.then(this._updateStatus.bind(this, STATUS_RESOLVED),
+ this._updateStatus.bind(this, STATUS_REJECTED));
+ return;
+ }
+
+ this._status = status;
+ this._value = value;
+
+ if (status === STATUS_REJECTED && this._handlers.length === 0) {
+ this._unhandledRejection = true;
+ HandlerManager.addUnhandledRejection(this);
+ }
+
+ HandlerManager.scheduleHandlers(this);
+ },
+
+ _resolve: function Promise_resolve(value) {
+ this._updateStatus(STATUS_RESOLVED, value);
+ },
+
+ _reject: function Promise_reject(reason) {
+ this._updateStatus(STATUS_REJECTED, reason);
+ },
+
+ then: function Promise_then(onResolve, onReject) {
+ var nextPromise = new Promise(function (resolve, reject) {
+ this.resolve = resolve;
+ this.reject = reject;
+ });
+ this._handlers.push({
+ thisPromise: this,
+ onResolve: onResolve,
+ onReject: onReject,
+ nextPromise: nextPromise
+ });
+ HandlerManager.scheduleHandlers(this);
+ return nextPromise;
+ },
+
+ catch: function Promise_catch(onReject) {
+ return this.then(undefined, onReject);
+ }
+ };
+
+ globalScope.Promise = Promise;
+//#else
+//throw new Error('DOM Promise is not present');
+//#endif
+})();
+
+var StatTimer = (function StatTimerClosure() {
+ function rpad(str, pad, length) {
+ while (str.length < length) {
+ str += pad;
+ }
+ return str;
+ }
+ function StatTimer() {
+ this.started = {};
+ this.times = [];
+ this.enabled = true;
+ }
+ StatTimer.prototype = {
+ time: function StatTimer_time(name) {
+ if (!this.enabled) {
+ return;
+ }
+ if (name in this.started) {
+ warn('Timer is already running for ' + name);
+ }
+ this.started[name] = Date.now();
+ },
+ timeEnd: function StatTimer_timeEnd(name) {
+ if (!this.enabled) {
+ return;
+ }
+ if (!(name in this.started)) {
+ warn('Timer has not been started for ' + name);
+ }
+ this.times.push({
+ 'name': name,
+ 'start': this.started[name],
+ 'end': Date.now()
+ });
+ // Remove timer from started so it can be called again.
+ delete this.started[name];
+ },
+ toString: function StatTimer_toString() {
+ var i, ii;
+ var times = this.times;
+ var out = '';
+ // Find the longest name for padding purposes.
+ var longest = 0;
+ for (i = 0, ii = times.length; i < ii; ++i) {
+ var name = times[i]['name'];
+ if (name.length > longest) {
+ longest = name.length;
+ }
+ }
+ for (i = 0, ii = times.length; i < ii; ++i) {
+ var span = times[i];
+ var duration = span.end - span.start;
+ out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\n';
+ }
+ return out;
+ }
+ };
+ return StatTimer;
+})();
+
+PDFJS.createBlob = function createBlob(data, contentType) {
+ if (typeof Blob !== 'undefined') {
+ return new Blob([data], { type: contentType });
+ }
+ // Blob builder is deprecated in FF14 and removed in FF18.
+ var bb = new MozBlobBuilder();
+ bb.append(data);
+ return bb.getBlob(contentType);
+};
+
+PDFJS.createObjectURL = (function createObjectURLClosure() {
+ // Blob/createObjectURL is not available, falling back to data schema.
+ var digits =
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
+
+ return function createObjectURL(data, contentType) {
+ if (!PDFJS.disableCreateObjectURL &&
+ typeof URL !== 'undefined' && URL.createObjectURL) {
+ var blob = PDFJS.createBlob(data, contentType);
+ return URL.createObjectURL(blob);
+ }
+
+ var buffer = 'data:' + contentType + ';base64,';
+ for (var i = 0, ii = data.length; i < ii; i += 3) {
+ var b1 = data[i] & 0xFF;
+ var b2 = data[i + 1] & 0xFF;
+ var b3 = data[i + 2] & 0xFF;
+ var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4);
+ var d3 = i + 1 < ii ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64;
+ var d4 = i + 2 < ii ? (b3 & 0x3F) : 64;
+ buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4];
+ }
+ return buffer;
+ };
+})();
+
+function MessageHandler(name, comObj) {
+ this.name = name;
+ this.comObj = comObj;
+ this.callbackIndex = 1;
+ this.postMessageTransfers = true;
+ var callbacksCapabilities = this.callbacksCapabilities = {};
+ var ah = this.actionHandler = {};
+
+ ah['console_log'] = [function ahConsoleLog(data) {
+ console.log.apply(console, data);
+ }];
+ ah['console_error'] = [function ahConsoleError(data) {
+ console.error.apply(console, data);
+ }];
+ ah['_unsupported_feature'] = [function ah_unsupportedFeature(data) {
+ UnsupportedManager.notify(data);
+ }];
+
+ comObj.onmessage = function messageHandlerComObjOnMessage(event) {
+ var data = event.data;
+ if (data.isReply) {
+ var callbackId = data.callbackId;
+ if (data.callbackId in callbacksCapabilities) {
+ var callback = callbacksCapabilities[callbackId];
+ delete callbacksCapabilities[callbackId];
+ if ('error' in data) {
+ callback.reject(data.error);
+ } else {
+ callback.resolve(data.data);
+ }
+ } else {
+ error('Cannot resolve callback ' + callbackId);
+ }
+ } else if (data.action in ah) {
+ var action = ah[data.action];
+ if (data.callbackId) {
+ Promise.resolve().then(function () {
+ return action[0].call(action[1], data.data);
+ }).then(function (result) {
+ comObj.postMessage({
+ isReply: true,
+ callbackId: data.callbackId,
+ data: result
+ });
+ }, function (reason) {
+ comObj.postMessage({
+ isReply: true,
+ callbackId: data.callbackId,
+ error: reason
+ });
+ });
+ } else {
+ action[0].call(action[1], data.data);
+ }
+ } else {
+ error('Unknown action from worker: ' + data.action);
+ }
+ };
+}
+
+MessageHandler.prototype = {
+ on: function messageHandlerOn(actionName, handler, scope) {
+ var ah = this.actionHandler;
+ if (ah[actionName]) {
+ error('There is already an actionName called "' + actionName + '"');
+ }
+ ah[actionName] = [handler, scope];
+ },
+ /**
+ * Sends a message to the comObj to invoke the action with the supplied data.
+ * @param {String} actionName Action to call.
+ * @param {JSON} data JSON data to send.
+ * @param {Array} [transfers] Optional list of transfers/ArrayBuffers
+ */
+ send: function messageHandlerSend(actionName, data, transfers) {
+ var message = {
+ action: actionName,
+ data: data
+ };
+ this.postMessage(message, transfers);
+ },
+ /**
+ * Sends a message to the comObj to invoke the action with the supplied data.
+ * Expects that other side will callback with the response.
+ * @param {String} actionName Action to call.
+ * @param {JSON} data JSON data to send.
+ * @param {Array} [transfers] Optional list of transfers/ArrayBuffers.
+ * @returns {Promise} Promise to be resolved with response data.
+ */
+ sendWithPromise:
+ function messageHandlerSendWithPromise(actionName, data, transfers) {
+ var callbackId = this.callbackIndex++;
+ var message = {
+ action: actionName,
+ data: data,
+ callbackId: callbackId
+ };
+ var capability = createPromiseCapability();
+ this.callbacksCapabilities[callbackId] = capability;
+ try {
+ this.postMessage(message, transfers);
+ } catch (e) {
+ capability.reject(e);
+ }
+ return capability.promise;
+ },
+ /**
+ * Sends raw message to the comObj.
+ * @private
+ * @param message {Object} Raw message.
+ * @param transfers List of transfers/ArrayBuffers, or undefined.
+ */
+ postMessage: function (message, transfers) {
+ if (transfers && this.postMessageTransfers) {
+ this.comObj.postMessage(message, transfers);
+ } else {
+ this.comObj.postMessage(message);
+ }
+ }
+};
+
+function loadJpegStream(id, imageUrl, objs) {
+ var img = new Image();
+ img.onload = (function loadJpegStream_onloadClosure() {
+ objs.resolve(id, img);
+ });
+ img.onerror = (function loadJpegStream_onerrorClosure() {
+ objs.resolve(id, null);
+ warn('Error during JPEG image loading');
+ });
+ img.src = imageUrl;
+}
+
+
+/**
+ * The maximum allowed image size in total pixels e.g. width * height. Images
+ * above this value will not be drawn. Use -1 for no limit.
+ * @var {number}
+ */
+PDFJS.maxImageSize = (PDFJS.maxImageSize === undefined ?
+ -1 : PDFJS.maxImageSize);
+
+/**
+ * The url of where the predefined Adobe CMaps are located. Include trailing
+ * slash.
+ * @var {string}
+ */
+PDFJS.cMapUrl = (PDFJS.cMapUrl === undefined ? null : PDFJS.cMapUrl);
+
+/**
+ * Specifies if CMaps are binary packed.
+ * @var {boolean}
+ */
+PDFJS.cMapPacked = PDFJS.cMapPacked === undefined ? false : PDFJS.cMapPacked;
+
+/**
+ * By default fonts are converted to OpenType fonts and loaded via font face
+ * rules. If disabled, the font will be rendered using a built in font renderer
+ * that constructs the glyphs with primitive path commands.
+ * @var {boolean}
+ */
+PDFJS.disableFontFace = (PDFJS.disableFontFace === undefined ?
+ false : PDFJS.disableFontFace);
+
+/**
+ * Path for image resources, mainly for annotation icons. Include trailing
+ * slash.
+ * @var {string}
+ */
+PDFJS.imageResourcesPath = (PDFJS.imageResourcesPath === undefined ?
+ '' : PDFJS.imageResourcesPath);
+
+/**
+ * Disable the web worker and run all code on the main thread. This will happen
+ * automatically if the browser doesn't support workers or sending typed arrays
+ * to workers.
+ * @var {boolean}
+ */
+PDFJS.disableWorker = (PDFJS.disableWorker === undefined ?
+ false : PDFJS.disableWorker);
+
+/**
+ * Path and filename of the worker file. Required when the worker is enabled in
+ * development mode. If unspecified in the production build, the worker will be
+ * loaded based on the location of the pdf.js file.
+ * @var {string}
+ */
+PDFJS.workerSrc = (PDFJS.workerSrc === undefined ? null : PDFJS.workerSrc);
+
+/**
+ * Disable range request loading of PDF files. When enabled and if the server
+ * supports partial content requests then the PDF will be fetched in chunks.
+ * Enabled (false) by default.
+ * @var {boolean}
+ */
+PDFJS.disableRange = (PDFJS.disableRange === undefined ?
+ false : PDFJS.disableRange);
+
+/**
+ * Disable streaming of PDF file data. By default PDF.js attempts to load PDF
+ * in chunks. This default behavior can be disabled.
+ * @var {boolean}
+ */
+PDFJS.disableStream = (PDFJS.disableStream === undefined ?
+ false : PDFJS.disableStream);
+
+/**
+ * Disable pre-fetching of PDF file data. When range requests are enabled PDF.js
+ * will automatically keep fetching more data even if it isn't needed to display
+ * the current page. This default behavior can be disabled.
+ *
+ * NOTE: It is also necessary to disable streaming, see above,
+ * in order for disabling of pre-fetching to work correctly.
+ * @var {boolean}
+ */
+PDFJS.disableAutoFetch = (PDFJS.disableAutoFetch === undefined ?
+ false : PDFJS.disableAutoFetch);
+
+/**
+ * Enables special hooks for debugging PDF.js.
+ * @var {boolean}
+ */
+PDFJS.pdfBug = (PDFJS.pdfBug === undefined ? false : PDFJS.pdfBug);
+
+/**
+ * Enables transfer usage in postMessage for ArrayBuffers.
+ * @var {boolean}
+ */
+PDFJS.postMessageTransfers = (PDFJS.postMessageTransfers === undefined ?
+ true : PDFJS.postMessageTransfers);
+
+/**
+ * Disables URL.createObjectURL usage.
+ * @var {boolean}
+ */
+PDFJS.disableCreateObjectURL = (PDFJS.disableCreateObjectURL === undefined ?
+ false : PDFJS.disableCreateObjectURL);
+
+/**
+ * Disables WebGL usage.
+ * @var {boolean}
+ */
+PDFJS.disableWebGL = (PDFJS.disableWebGL === undefined ?
+ true : PDFJS.disableWebGL);
+
+/**
+ * Disables fullscreen support, and by extension Presentation Mode,
+ * in browsers which support the fullscreen API.
+ * @var {boolean}
+ */
+PDFJS.disableFullscreen = (PDFJS.disableFullscreen === undefined ?
+ false : PDFJS.disableFullscreen);
+
+/**
+ * Enables CSS only zooming.
+ * @var {boolean}
+ */
+PDFJS.useOnlyCssZoom = (PDFJS.useOnlyCssZoom === undefined ?
+ false : PDFJS.useOnlyCssZoom);
+
+/**
+ * Controls the logging level.
+ * The constants from PDFJS.VERBOSITY_LEVELS should be used:
+ * - errors
+ * - warnings [default]
+ * - infos
+ * @var {number}
+ */
+PDFJS.verbosity = (PDFJS.verbosity === undefined ?
+ PDFJS.VERBOSITY_LEVELS.warnings : PDFJS.verbosity);
+
+/**
+ * The maximum supported canvas size in total pixels e.g. width * height.
+ * The default value is 4096 * 4096. Use -1 for no limit.
+ * @var {number}
+ */
+PDFJS.maxCanvasPixels = (PDFJS.maxCanvasPixels === undefined ?
+ 16777216 : PDFJS.maxCanvasPixels);
+
+/**
+ * Opens external links in a new window if enabled. The default behavior opens
+ * external links in the PDF.js window.
+ * @var {boolean}
+ */
+PDFJS.openExternalLinksInNewWindow = (
+ PDFJS.openExternalLinksInNewWindow === undefined ?
+ false : PDFJS.openExternalLinksInNewWindow);
+
+/**
+ * Document initialization / loading parameters object.
+ *
+ * @typedef {Object} DocumentInitParameters
+ * @property {string} url - The URL of the PDF.
+ * @property {TypedArray|Array|string} data - Binary PDF data. Use typed arrays
+ * (Uint8Array) to improve the memory usage. If PDF data is BASE64-encoded,
+ * use atob() to convert it to a binary string first.
+ * @property {Object} httpHeaders - Basic authentication headers.
+ * @property {boolean} withCredentials - Indicates whether or not cross-site
+ * Access-Control requests should be made using credentials such as cookies
+ * or authorization headers. The default is false.
+ * @property {string} password - For decrypting password-protected PDFs.
+ * @property {TypedArray} initialData - A typed array with the first portion or
+ * all of the pdf data. Used by the extension since some data is already
+ * loaded before the switch to range requests.
+ * @property {number} length - The PDF file length. It's used for progress
+ * reports and range requests operations.
+ * @property {PDFDataRangeTransport} range
+ */
+
+/**
+ * @typedef {Object} PDFDocumentStats
+ * @property {Array} streamTypes - Used stream types in the document (an item
+ * is set to true if specific stream ID was used in the document).
+ * @property {Array} fontTypes - Used font type in the document (an item is set
+ * to true if specific font ID was used in the document).
+ */
+
+/**
+ * This is the main entry point for loading a PDF and interacting with it.
+ * NOTE: If a URL is used to fetch the PDF data a standard XMLHttpRequest(XHR)
+ * is used, which means it must follow the same origin rules that any XHR does
+ * e.g. No cross domain requests without CORS.
+ *
+ * @param {string|TypedArray|DocumentInitParameters|PDFDataRangeTransport} src
+ * Can be a url to where a PDF is located, a typed array (Uint8Array)
+ * already populated with data or parameter object.
+ *
+ * @param {PDFDataRangeTransport} pdfDataRangeTransport (deprecated) It is used
+ * if you want to manually serve range requests for data in the PDF.
+ *
+ * @param {function} passwordCallback (deprecated) It is used to request a
+ * password if wrong or no password was provided. The callback receives two
+ * parameters: function that needs to be called with new password and reason
+ * (see {PasswordResponses}).
+ *
+ * @param {function} progressCallback (deprecated) It is used to be able to
+ * monitor the loading progress of the PDF file (necessary to implement e.g.
+ * a loading bar). The callback receives an {Object} with the properties:
+ * {number} loaded and {number} total.
+ *
+ * @return {PDFDocumentLoadingTask}
+ */
+PDFJS.getDocument = function getDocument(src,
+ pdfDataRangeTransport,
+ passwordCallback,
+ progressCallback) {
+ var task = new PDFDocumentLoadingTask();
+
+ // Support of the obsolete arguments (for compatibility with API v1.0)
+ if (pdfDataRangeTransport) {
+ if (!(pdfDataRangeTransport instanceof PDFDataRangeTransport)) {
+ // Not a PDFDataRangeTransport instance, trying to add missing properties.
+ pdfDataRangeTransport = Object.create(pdfDataRangeTransport);
+ pdfDataRangeTransport.length = src.length;
+ pdfDataRangeTransport.initialData = src.initialData;
+ }
+ src = Object.create(src);
+ src.range = pdfDataRangeTransport;
+ }
+ task.onPassword = passwordCallback || null;
+ task.onProgress = progressCallback || null;
+
+ var workerInitializedCapability, transport;
+ var source;
+ if (typeof src === 'string') {
+ source = { url: src };
+ } else if (isArrayBuffer(src)) {
+ source = { data: src };
+ } else if (src instanceof PDFDataRangeTransport) {
+ source = { range: src };
+ } else {
+ if (typeof src !== 'object') {
+ error('Invalid parameter in getDocument, need either Uint8Array, ' +
+ 'string or a parameter object');
+ }
+ if (!src.url && !src.data && !src.range) {
+ error('Invalid parameter object: need either .data, .range or .url');
+ }
+
+ source = src;
+ }
+
+ var params = {};
+ for (var key in source) {
+ if (key === 'url' && typeof window !== 'undefined') {
+ // The full path is required in the 'url' field.
+ params[key] = combineUrl(window.location.href, source[key]);
+ continue;
+ } else if (key === 'range') {
+ continue;
+ } else if (key === 'data' && !(source[key] instanceof Uint8Array)) {
+ // Converting string or array-like data to Uint8Array.
+ var pdfBytes = source[key];
+ if (typeof pdfBytes === 'string') {
+ params[key] = stringToBytes(pdfBytes);
+ } else if (typeof pdfBytes === 'object' && pdfBytes !== null &&
+ !isNaN(pdfBytes.length)) {
+ params[key] = new Uint8Array(pdfBytes);
+ } else {
+ error('Invalid PDF binary data: either typed array, string or ' +
+ 'array-like object is expected in the data property.');
+ }
+ continue;
+ }
+ params[key] = source[key];
+ }
+
+ workerInitializedCapability = createPromiseCapability();
+ transport = new WorkerTransport(workerInitializedCapability, source.range);
+ workerInitializedCapability.promise.then(function transportInitialized() {
+ transport.fetchDocument(task, params);
+ });
+
+ return task;
+};
+
+/**
+ * PDF document loading operation.
+ * @class
+ */
+var PDFDocumentLoadingTask = (function PDFDocumentLoadingTaskClosure() {
+ /** @constructs PDFDocumentLoadingTask */
+ function PDFDocumentLoadingTask() {
+ this._capability = createPromiseCapability();
+
+ /**
+ * Callback to request a password if wrong or no password was provided.
+ * The callback receives two parameters: function that needs to be called
+ * with new password and reason (see {PasswordResponses}).
+ */
+ this.onPassword = null;
+
+ /**
+ * Callback to be able to monitor the loading progress of the PDF file
+ * (necessary to implement e.g. a loading bar). The callback receives
+ * an {Object} with the properties: {number} loaded and {number} total.
+ */
+ this.onProgress = null;
+ }
+
+ PDFDocumentLoadingTask.prototype =
+ /** @lends PDFDocumentLoadingTask.prototype */ {
+ /**
+ * @return {Promise}
+ */
+ get promise() {
+ return this._capability.promise;
+ },
+
+ // TODO add cancel or abort method
+
+ /**
+ * Registers callbacks to indicate the document loading completion.
+ *
+ * @param {function} onFulfilled The callback for the loading completion.
+ * @param {function} onRejected The callback for the loading failure.
+ * @return {Promise} A promise that is resolved after the onFulfilled or
+ * onRejected callback.
+ */
+ then: function PDFDocumentLoadingTask_then(onFulfilled, onRejected) {
+ return this.promise.then.apply(this.promise, arguments);
+ }
+ };
+
+ return PDFDocumentLoadingTask;
+})();
+
+/**
+ * Abstract class to support range requests file loading.
+ * @class
+ */
+var PDFDataRangeTransport = (function pdfDataRangeTransportClosure() {
+ /**
+ * @constructs PDFDataRangeTransport
+ * @param {number} length
+ * @param {Uint8Array} initialData
+ */
+ function PDFDataRangeTransport(length, initialData) {
+ this.length = length;
+ this.initialData = initialData;
+
+ this._rangeListeners = [];
+ this._progressListeners = [];
+ this._progressiveReadListeners = [];
+ this._readyCapability = createPromiseCapability();
+ }
+ PDFDataRangeTransport.prototype =
+ /** @lends PDFDataRangeTransport.prototype */ {
+ addRangeListener:
+ function PDFDataRangeTransport_addRangeListener(listener) {
+ this._rangeListeners.push(listener);
+ },
+
+ addProgressListener:
+ function PDFDataRangeTransport_addProgressListener(listener) {
+ this._progressListeners.push(listener);
+ },
+
+ addProgressiveReadListener:
+ function PDFDataRangeTransport_addProgressiveReadListener(listener) {
+ this._progressiveReadListeners.push(listener);
+ },
+
+ onDataRange: function PDFDataRangeTransport_onDataRange(begin, chunk) {
+ var listeners = this._rangeListeners;
+ for (var i = 0, n = listeners.length; i < n; ++i) {
+ listeners[i](begin, chunk);
+ }
+ },
+
+ onDataProgress: function PDFDataRangeTransport_onDataProgress(loaded) {
+ this._readyCapability.promise.then(function () {
+ var listeners = this._progressListeners;
+ for (var i = 0, n = listeners.length; i < n; ++i) {
+ listeners[i](loaded);
+ }
+ }.bind(this));
+ },
+
+ onDataProgressiveRead:
+ function PDFDataRangeTransport_onDataProgress(chunk) {
+ this._readyCapability.promise.then(function () {
+ var listeners = this._progressiveReadListeners;
+ for (var i = 0, n = listeners.length; i < n; ++i) {
+ listeners[i](chunk);
+ }
+ }.bind(this));
+ },
+
+ transportReady: function PDFDataRangeTransport_transportReady() {
+ this._readyCapability.resolve();
+ },
+
+ requestDataRange:
+ function PDFDataRangeTransport_requestDataRange(begin, end) {
+ throw new Error('Abstract method PDFDataRangeTransport.requestDataRange');
+ }
+ };
+ return PDFDataRangeTransport;
+})();
+
+PDFJS.PDFDataRangeTransport = PDFDataRangeTransport;
+
+/**
+ * Proxy to a PDFDocument in the worker thread. Also, contains commonly used
+ * properties that can be read synchronously.
+ * @class
+ */
+var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
+ function PDFDocumentProxy(pdfInfo, transport) {
+ this.pdfInfo = pdfInfo;
+ this.transport = transport;
+ }
+ PDFDocumentProxy.prototype = /** @lends PDFDocumentProxy.prototype */ {
+ /**
+ * @return {number} Total number of pages the PDF contains.
+ */
+ get numPages() {
+ return this.pdfInfo.numPages;
+ },
+ /**
+ * @return {string} A unique ID to identify a PDF. Not guaranteed to be
+ * unique.
+ */
+ get fingerprint() {
+ return this.pdfInfo.fingerprint;
+ },
+ /**
+ * @param {number} pageNumber The page number to get. The first page is 1.
+ * @return {Promise} A promise that is resolved with a {@link PDFPageProxy}
+ * object.
+ */
+ getPage: function PDFDocumentProxy_getPage(pageNumber) {
+ return this.transport.getPage(pageNumber);
+ },
+ /**
+ * @param {{num: number, gen: number}} ref The page reference. Must have
+ * the 'num' and 'gen' properties.
+ * @return {Promise} A promise that is resolved with the page index that is
+ * associated with the reference.
+ */
+ getPageIndex: function PDFDocumentProxy_getPageIndex(ref) {
+ return this.transport.getPageIndex(ref);
+ },
+ /**
+ * @return {Promise} A promise that is resolved with a lookup table for
+ * mapping named destinations to reference numbers.
+ *
+ * This can be slow for large documents: use getDestination instead
+ */
+ getDestinations: function PDFDocumentProxy_getDestinations() {
+ return this.transport.getDestinations();
+ },
+ /**
+ * @param {string} id The named destination to get.
+ * @return {Promise} A promise that is resolved with all information
+ * of the given named destination.
+ */
+ getDestination: function PDFDocumentProxy_getDestination(id) {
+ return this.transport.getDestination(id);
+ },
+ /**
+ * @return {Promise} A promise that is resolved with a lookup table for
+ * mapping named attachments to their content.
+ */
+ getAttachments: function PDFDocumentProxy_getAttachments() {
+ return this.transport.getAttachments();
+ },
+ /**
+ * @return {Promise} A promise that is resolved with an array of all the
+ * JavaScript strings in the name tree.
+ */
+ getJavaScript: function PDFDocumentProxy_getJavaScript() {
+ return this.transport.getJavaScript();
+ },
+ /**
+ * @return {Promise} A promise that is resolved with an {Array} that is a
+ * tree outline (if it has one) of the PDF. The tree is in the format of:
+ * [
+ * {
+ * title: string,
+ * bold: boolean,
+ * italic: boolean,
+ * color: rgb array,
+ * dest: dest obj,
+ * items: array of more items like this
+ * },
+ * ...
+ * ].
+ */
+ getOutline: function PDFDocumentProxy_getOutline() {
+ return this.transport.getOutline();
+ },
+ /**
+ * @return {Promise} A promise that is resolved with an {Object} that has
+ * info and metadata properties. Info is an {Object} filled with anything
+ * available in the information dictionary and similarly metadata is a
+ * {Metadata} object with information from the metadata section of the PDF.
+ */
+ getMetadata: function PDFDocumentProxy_getMetadata() {
+ return this.transport.getMetadata();
+ },
+ /**
+ * @return {Promise} A promise that is resolved with a TypedArray that has
+ * the raw data from the PDF.
+ */
+ getData: function PDFDocumentProxy_getData() {
+ return this.transport.getData();
+ },
+ /**
+ * @return {Promise} A promise that is resolved when the document's data
+ * is loaded. It is resolved with an {Object} that contains the length
+ * property that indicates size of the PDF data in bytes.
+ */
+ getDownloadInfo: function PDFDocumentProxy_getDownloadInfo() {
+ return this.transport.downloadInfoCapability.promise;
+ },
+ /**
+ * @return {Promise} A promise this is resolved with current stats about
+ * document structures (see {@link PDFDocumentStats}).
+ */
+ getStats: function PDFDocumentProxy_getStats() {
+ return this.transport.getStats();
+ },
+ /**
+ * Cleans up resources allocated by the document, e.g. created @font-face.
+ */
+ cleanup: function PDFDocumentProxy_cleanup() {
+ this.transport.startCleanup();
+ },
+ /**
+ * Destroys current document instance and terminates worker.
+ */
+ destroy: function PDFDocumentProxy_destroy() {
+ this.transport.destroy();
+ }
+ };
+ return PDFDocumentProxy;
+})();
+
+/**
+ * Page text content.
+ *
+ * @typedef {Object} TextContent
+ * @property {array} items - array of {@link TextItem}
+ * @property {Object} styles - {@link TextStyles} objects, indexed by font
+ * name.
+ */
+
+/**
+ * Page text content part.
+ *
+ * @typedef {Object} TextItem
+ * @property {string} str - text content.
+ * @property {string} dir - text direction: 'ttb', 'ltr' or 'rtl'.
+ * @property {array} transform - transformation matrix.
+ * @property {number} width - width in device space.
+ * @property {number} height - height in device space.
+ * @property {string} fontName - font name used by pdf.js for converted font.
+ */
+
+/**
+ * Text style.
+ *
+ * @typedef {Object} TextStyle
+ * @property {number} ascent - font ascent.
+ * @property {number} descent - font descent.
+ * @property {boolean} vertical - text is in vertical mode.
+ * @property {string} fontFamily - possible font family
+ */
+
+/**
+ * Page render parameters.
+ *
+ * @typedef {Object} RenderParameters
+ * @property {Object} canvasContext - A 2D context of a DOM Canvas object.
+ * @property {PDFJS.PageViewport} viewport - Rendering viewport obtained by
+ * calling of PDFPage.getViewport method.
+ * @property {string} intent - Rendering intent, can be 'display' or 'print'
+ * (default value is 'display').
+ * @property {Object} imageLayer - (optional) An object that has beginLayout,
+ * endLayout and appendImage functions.
+ * @property {function} continueCallback - (deprecated) A function that will be
+ * called each time the rendering is paused. To continue
+ * rendering call the function that is the first argument
+ * to the callback.
+ */
+
+/**
+ * PDF page operator list.
+ *
+ * @typedef {Object} PDFOperatorList
+ * @property {Array} fnArray - Array containing the operator functions.
+ * @property {Array} argsArray - Array containing the arguments of the
+ * functions.
+ */
+
+/**
+ * Proxy to a PDFPage in the worker thread.
+ * @class
+ */
+var PDFPageProxy = (function PDFPageProxyClosure() {
+ function PDFPageProxy(pageIndex, pageInfo, transport) {
+ this.pageIndex = pageIndex;
+ this.pageInfo = pageInfo;
+ this.transport = transport;
+ this.stats = new StatTimer();
+ this.stats.enabled = !!globalScope.PDFJS.enableStats;
+ this.commonObjs = transport.commonObjs;
+ this.objs = new PDFObjects();
+ this.cleanupAfterRender = false;
+ this.pendingDestroy = false;
+ this.intentStates = {};
+ }
+ PDFPageProxy.prototype = /** @lends PDFPageProxy.prototype */ {
+ /**
+ * @return {number} Page number of the page. First page is 1.
+ */
+ get pageNumber() {
+ return this.pageIndex + 1;
+ },
+ /**
+ * @return {number} The number of degrees the page is rotated clockwise.
+ */
+ get rotate() {
+ return this.pageInfo.rotate;
+ },
+ /**
+ * @return {Object} The reference that points to this page. It has 'num' and
+ * 'gen' properties.
+ */
+ get ref() {
+ return this.pageInfo.ref;
+ },
+ /**
+ * @return {Array} An array of the visible portion of the PDF page in the
+ * user space units - [x1, y1, x2, y2].
+ */
+ get view() {
+ return this.pageInfo.view;
+ },
+ /**
+ * @param {number} scale The desired scale of the viewport.
+ * @param {number} rotate Degrees to rotate the viewport. If omitted this
+ * defaults to the page rotation.
+ * @return {PDFJS.PageViewport} Contains 'width' and 'height' properties
+ * along with transforms required for rendering.
+ */
+ getViewport: function PDFPageProxy_getViewport(scale, rotate) {
+ if (arguments.length < 2) {
+ rotate = this.rotate;
+ }
+ return new PDFJS.PageViewport(this.view, scale, rotate, 0, 0);
+ },
+ /**
+ * @return {Promise} A promise that is resolved with an {Array} of the
+ * annotation objects.
+ */
+ getAnnotations: function PDFPageProxy_getAnnotations() {
+ if (this.annotationsPromise) {
+ return this.annotationsPromise;
+ }
+
+ var promise = this.transport.getAnnotations(this.pageIndex);
+ this.annotationsPromise = promise;
+ return promise;
+ },
+ /**
+ * Begins the process of rendering a page to the desired context.
+ * @param {RenderParameters} params Page render parameters.
+ * @return {RenderTask} An object that contains the promise, which
+ * is resolved when the page finishes rendering.
+ */
+ render: function PDFPageProxy_render(params) {
+ var stats = this.stats;
+ stats.time('Overall');
+
+ // If there was a pending destroy cancel it so no cleanup happens during
+ // this call to render.
+ this.pendingDestroy = false;
+
+ var renderingIntent = (params.intent === 'print' ? 'print' : 'display');
+
+ if (!this.intentStates[renderingIntent]) {
+ this.intentStates[renderingIntent] = {};
+ }
+ var intentState = this.intentStates[renderingIntent];
+
+ // If there's no displayReadyCapability yet, then the operatorList
+ // was never requested before. Make the request and create the promise.
+ if (!intentState.displayReadyCapability) {
+ intentState.receivingOperatorList = true;
+ intentState.displayReadyCapability = createPromiseCapability();
+ intentState.operatorList = {
+ fnArray: [],
+ argsArray: [],
+ lastChunk: false
+ };
+
+ this.stats.time('Page Request');
+ this.transport.messageHandler.send('RenderPageRequest', {
+ pageIndex: this.pageNumber - 1,
+ intent: renderingIntent
+ });
+ }
+
+ var internalRenderTask = new InternalRenderTask(complete, params,
+ this.objs,
+ this.commonObjs,
+ intentState.operatorList,
+ this.pageNumber);
+ if (!intentState.renderTasks) {
+ intentState.renderTasks = [];
+ }
+ intentState.renderTasks.push(internalRenderTask);
+ var renderTask = internalRenderTask.task;
+
+ // Obsolete parameter support
+ if (params.continueCallback) {
+ renderTask.onContinue = params.continueCallback;
+ }
+
+ var self = this;
+ intentState.displayReadyCapability.promise.then(
+ function pageDisplayReadyPromise(transparency) {
+ if (self.pendingDestroy) {
+ complete();
+ return;
+ }
+ stats.time('Rendering');
+ internalRenderTask.initalizeGraphics(transparency);
+ internalRenderTask.operatorListChanged();
+ },
+ function pageDisplayReadPromiseError(reason) {
+ complete(reason);
+ }
+ );
+
+ function complete(error) {
+ var i = intentState.renderTasks.indexOf(internalRenderTask);
+ if (i >= 0) {
+ intentState.renderTasks.splice(i, 1);
+ }
+
+ if (self.cleanupAfterRender) {
+ self.pendingDestroy = true;
+ }
+ self._tryDestroy();
+
+ if (error) {
+ internalRenderTask.capability.reject(error);
+ } else {
+ internalRenderTask.capability.resolve();
+ }
+ stats.timeEnd('Rendering');
+ stats.timeEnd('Overall');
+ }
+
+ return renderTask;
+ },
+
+ /**
+ * @return {Promise} A promise resolved with an {@link PDFOperatorList}
+ * object that represents page's operator list.
+ */
+ getOperatorList: function PDFPageProxy_getOperatorList() {
+ function operatorListChanged() {
+ if (intentState.operatorList.lastChunk) {
+ intentState.opListReadCapability.resolve(intentState.operatorList);
+ }
+ }
+
+ var renderingIntent = 'oplist';
+ if (!this.intentStates[renderingIntent]) {
+ this.intentStates[renderingIntent] = {};
+ }
+ var intentState = this.intentStates[renderingIntent];
+
+ if (!intentState.opListReadCapability) {
+ var opListTask = {};
+ opListTask.operatorListChanged = operatorListChanged;
+ intentState.receivingOperatorList = true;
+ intentState.opListReadCapability = createPromiseCapability();
+ intentState.renderTasks = [];
+ intentState.renderTasks.push(opListTask);
+ intentState.operatorList = {
+ fnArray: [],
+ argsArray: [],
+ lastChunk: false
+ };
+
+ this.transport.messageHandler.send('RenderPageRequest', {
+ pageIndex: this.pageIndex,
+ intent: renderingIntent
+ });
+ }
+ return intentState.opListReadCapability.promise;
+ },
+
+ /**
+ * @return {Promise} That is resolved a {@link TextContent}
+ * object that represent the page text content.
+ */
+ getTextContent: function PDFPageProxy_getTextContent() {
+ return this.transport.messageHandler.sendWithPromise('GetTextContent', {
+ pageIndex: this.pageNumber - 1
+ });
+ },
+ /**
+ * Destroys resources allocated by the page.
+ */
+ destroy: function PDFPageProxy_destroy() {
+ this.pendingDestroy = true;
+ this._tryDestroy();
+ },
+ /**
+ * For internal use only. Attempts to clean up if rendering is in a state
+ * where that's possible.
+ * @ignore
+ */
+ _tryDestroy: function PDFPageProxy__destroy() {
+ if (!this.pendingDestroy ||
+ Object.keys(this.intentStates).some(function(intent) {
+ var intentState = this.intentStates[intent];
+ return (intentState.renderTasks.length !== 0 ||
+ intentState.receivingOperatorList);
+ }, this)) {
+ return;
+ }
+
+ Object.keys(this.intentStates).forEach(function(intent) {
+ delete this.intentStates[intent];
+ }, this);
+ this.objs.clear();
+ this.annotationsPromise = null;
+ this.pendingDestroy = false;
+ },
+ /**
+ * For internal use only.
+ * @ignore
+ */
+ _startRenderPage: function PDFPageProxy_startRenderPage(transparency,
+ intent) {
+ var intentState = this.intentStates[intent];
+ // TODO Refactor RenderPageRequest to separate rendering
+ // and operator list logic
+ if (intentState.displayReadyCapability) {
+ intentState.displayReadyCapability.resolve(transparency);
+ }
+ },
+ /**
+ * For internal use only.
+ * @ignore
+ */
+ _renderPageChunk: function PDFPageProxy_renderPageChunk(operatorListChunk,
+ intent) {
+ var intentState = this.intentStates[intent];
+ var i, ii;
+ // Add the new chunk to the current operator list.
+ for (i = 0, ii = operatorListChunk.length; i < ii; i++) {
+ intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]);
+ intentState.operatorList.argsArray.push(
+ operatorListChunk.argsArray[i]);
+ }
+ intentState.operatorList.lastChunk = operatorListChunk.lastChunk;
+
+ // Notify all the rendering tasks there are more operators to be consumed.
+ for (i = 0; i < intentState.renderTasks.length; i++) {
+ intentState.renderTasks[i].operatorListChanged();
+ }
+
+ if (operatorListChunk.lastChunk) {
+ intentState.receivingOperatorList = false;
+ this._tryDestroy();
+ }
+ }
+ };
+ return PDFPageProxy;
+})();
+
+/**
+ * For internal use only.
+ * @ignore
+ */
+var WorkerTransport = (function WorkerTransportClosure() {
+ function WorkerTransport(workerInitializedCapability, pdfDataRangeTransport) {
+ this.pdfDataRangeTransport = pdfDataRangeTransport;
+ this.workerInitializedCapability = workerInitializedCapability;
+ this.commonObjs = new PDFObjects();
+
+ this.loadingTask = null;
+
+ this.pageCache = [];
+ this.pagePromises = [];
+ this.downloadInfoCapability = createPromiseCapability();
+
+ // If worker support isn't disabled explicit and the browser has worker
+ // support, create a new web worker and test if it/the browser fullfills
+ // all requirements to run parts of pdf.js in a web worker.
+ // Right now, the requirement is, that an Uint8Array is still an Uint8Array
+ // as it arrives on the worker. Chrome added this with version 15.
+//#if !SINGLE_FILE
+ if (!globalScope.PDFJS.disableWorker && typeof Worker !== 'undefined') {
+ var workerSrc = PDFJS.workerSrc;
+ if (!workerSrc) {
+ error('No PDFJS.workerSrc specified');
+ }
+
+ try {
+ // Some versions of FF can't create a worker on localhost, see:
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=683280
+ var worker = new Worker(workerSrc);
+ var messageHandler = new MessageHandler('main', worker);
+ this.messageHandler = messageHandler;
+
+ messageHandler.on('test', function transportTest(data) {
+ var supportTypedArray = data && data.supportTypedArray;
+ if (supportTypedArray) {
+ this.worker = worker;
+ if (!data.supportTransfers) {
+ PDFJS.postMessageTransfers = false;
+ }
+ this.setupMessageHandler(messageHandler);
+ workerInitializedCapability.resolve();
+ } else {
+ this.setupFakeWorker();
+ }
+ }.bind(this));
+
+ var testObj = new Uint8Array([PDFJS.postMessageTransfers ? 255 : 0]);
+ // Some versions of Opera throw a DATA_CLONE_ERR on serializing the
+ // typed array. Also, checking if we can use transfers.
+ try {
+ messageHandler.send('test', testObj, [testObj.buffer]);
+ } catch (ex) {
+ info('Cannot use postMessage transfers');
+ testObj[0] = 0;
+ messageHandler.send('test', testObj);
+ }
+ return;
+ } catch (e) {
+ info('The worker has been disabled.');
+ }
+ }
+//#endif
+ // Either workers are disabled, not supported or have thrown an exception.
+ // Thus, we fallback to a faked worker.
+ this.setupFakeWorker();
+ }
+ WorkerTransport.prototype = {
+ destroy: function WorkerTransport_destroy() {
+ this.pageCache = [];
+ this.pagePromises = [];
+ var self = this;
+ this.messageHandler.sendWithPromise('Terminate', null).then(function () {
+ FontLoader.clear();
+ if (self.worker) {
+ self.worker.terminate();
+ }
+ });
+ },
+
+ setupFakeWorker: function WorkerTransport_setupFakeWorker() {
+ globalScope.PDFJS.disableWorker = true;
+
+ if (!PDFJS.fakeWorkerFilesLoadedCapability) {
+ PDFJS.fakeWorkerFilesLoadedCapability = createPromiseCapability();
+ // In the developer build load worker_loader which in turn loads all the
+ // other files and resolves the promise. In production only the
+ // pdf.worker.js file is needed.
+//#if !PRODUCTION
+ Util.loadScript(PDFJS.workerSrc);
+//#endif
+//#if PRODUCTION && SINGLE_FILE
+// PDFJS.fakeWorkerFilesLoadedCapability.resolve();
+//#endif
+//#if PRODUCTION && !SINGLE_FILE
+// Util.loadScript(PDFJS.workerSrc, function() {
+// PDFJS.fakeWorkerFilesLoadedCapability.resolve();
+// });
+//#endif
+ }
+ PDFJS.fakeWorkerFilesLoadedCapability.promise.then(function () {
+ warn('Setting up fake worker.');
+ // If we don't use a worker, just post/sendMessage to the main thread.
+ var fakeWorker = {
+ postMessage: function WorkerTransport_postMessage(obj) {
+ fakeWorker.onmessage({data: obj});
+ },
+ terminate: function WorkerTransport_terminate() {}
+ };
+
+ var messageHandler = new MessageHandler('main', fakeWorker);
+ this.setupMessageHandler(messageHandler);
+
+ // If the main thread is our worker, setup the handling for the messages
+ // the main thread sends to it self.
+ PDFJS.WorkerMessageHandler.setup(messageHandler);
+
+ this.workerInitializedCapability.resolve();
+ }.bind(this));
+ },
+
+ setupMessageHandler:
+ function WorkerTransport_setupMessageHandler(messageHandler) {
+ this.messageHandler = messageHandler;
+
+ function updatePassword(password) {
+ messageHandler.send('UpdatePassword', password);
+ }
+
+ var pdfDataRangeTransport = this.pdfDataRangeTransport;
+ if (pdfDataRangeTransport) {
+ pdfDataRangeTransport.addRangeListener(function(begin, chunk) {
+ messageHandler.send('OnDataRange', {
+ begin: begin,
+ chunk: chunk
+ });
+ });
+
+ pdfDataRangeTransport.addProgressListener(function(loaded) {
+ messageHandler.send('OnDataProgress', {
+ loaded: loaded
+ });
+ });
+
+ pdfDataRangeTransport.addProgressiveReadListener(function(chunk) {
+ messageHandler.send('OnDataRange', {
+ chunk: chunk
+ });
+ });
+
+ messageHandler.on('RequestDataRange',
+ function transportDataRange(data) {
+ pdfDataRangeTransport.requestDataRange(data.begin, data.end);
+ }, this);
+ }
+
+ messageHandler.on('GetDoc', function transportDoc(data) {
+ var pdfInfo = data.pdfInfo;
+ this.numPages = data.pdfInfo.numPages;
+ var pdfDocument = new PDFDocumentProxy(pdfInfo, this);
+ this.pdfDocument = pdfDocument;
+ this.loadingTask._capability.resolve(pdfDocument);
+ }, this);
+
+ messageHandler.on('NeedPassword',
+ function transportNeedPassword(exception) {
+ var loadingTask = this.loadingTask;
+ if (loadingTask.onPassword) {
+ return loadingTask.onPassword(updatePassword,
+ PasswordResponses.NEED_PASSWORD);
+ }
+ loadingTask._capability.reject(
+ new PasswordException(exception.message, exception.code));
+ }, this);
+
+ messageHandler.on('IncorrectPassword',
+ function transportIncorrectPassword(exception) {
+ var loadingTask = this.loadingTask;
+ if (loadingTask.onPassword) {
+ return loadingTask.onPassword(updatePassword,
+ PasswordResponses.INCORRECT_PASSWORD);
+ }
+ loadingTask._capability.reject(
+ new PasswordException(exception.message, exception.code));
+ }, this);
+
+ messageHandler.on('InvalidPDF', function transportInvalidPDF(exception) {
+ this.loadingTask._capability.reject(
+ new InvalidPDFException(exception.message));
+ }, this);
+
+ messageHandler.on('MissingPDF', function transportMissingPDF(exception) {
+ this.loadingTask._capability.reject(
+ new MissingPDFException(exception.message));
+ }, this);
+
+ messageHandler.on('UnexpectedResponse',
+ function transportUnexpectedResponse(exception) {
+ this.loadingTask._capability.reject(
+ new UnexpectedResponseException(exception.message, exception.status));
+ }, this);
+
+ messageHandler.on('UnknownError',
+ function transportUnknownError(exception) {
+ this.loadingTask._capability.reject(
+ new UnknownErrorException(exception.message, exception.details));
+ }, this);
+
+ messageHandler.on('DataLoaded', function transportPage(data) {
+ this.downloadInfoCapability.resolve(data);
+ }, this);
+
+ messageHandler.on('PDFManagerReady', function transportPage(data) {
+ if (this.pdfDataRangeTransport) {
+ this.pdfDataRangeTransport.transportReady();
+ }
+ }, this);
+
+ messageHandler.on('StartRenderPage', function transportRender(data) {
+ var page = this.pageCache[data.pageIndex];
+
+ page.stats.timeEnd('Page Request');
+ page._startRenderPage(data.transparency, data.intent);
+ }, this);
+
+ messageHandler.on('RenderPageChunk', function transportRender(data) {
+ var page = this.pageCache[data.pageIndex];
+
+ page._renderPageChunk(data.operatorList, data.intent);
+ }, this);
+
+ messageHandler.on('commonobj', function transportObj(data) {
+ var id = data[0];
+ var type = data[1];
+ if (this.commonObjs.hasData(id)) {
+ return;
+ }
+
+ switch (type) {
+ case 'Font':
+ var exportedData = data[2];
+
+ var font;
+ if ('error' in exportedData) {
+ var error = exportedData.error;
+ warn('Error during font loading: ' + error);
+ this.commonObjs.resolve(id, error);
+ break;
+ } else {
+ font = new FontFaceObject(exportedData);
+ }
+
+ FontLoader.bind(
+ [font],
+ function fontReady(fontObjs) {
+ this.commonObjs.resolve(id, font);
+ }.bind(this)
+ );
+ break;
+ case 'FontPath':
+ this.commonObjs.resolve(id, data[2]);
+ break;
+ default:
+ error('Got unknown common object type ' + type);
+ }
+ }, this);
+
+ messageHandler.on('obj', function transportObj(data) {
+ var id = data[0];
+ var pageIndex = data[1];
+ var type = data[2];
+ var pageProxy = this.pageCache[pageIndex];
+ var imageData;
+ if (pageProxy.objs.hasData(id)) {
+ return;
+ }
+
+ switch (type) {
+ case 'JpegStream':
+ imageData = data[3];
+ loadJpegStream(id, imageData, pageProxy.objs);
+ break;
+ case 'Image':
+ imageData = data[3];
+ pageProxy.objs.resolve(id, imageData);
+
+ // heuristics that will allow not to store large data
+ var MAX_IMAGE_SIZE_TO_STORE = 8000000;
+ if (imageData && 'data' in imageData &&
+ imageData.data.length > MAX_IMAGE_SIZE_TO_STORE) {
+ pageProxy.cleanupAfterRender = true;
+ }
+ break;
+ default:
+ error('Got unknown object type ' + type);
+ }
+ }, this);
+
+ messageHandler.on('DocProgress', function transportDocProgress(data) {
+ var loadingTask = this.loadingTask;
+ if (loadingTask.onProgress) {
+ loadingTask.onProgress({
+ loaded: data.loaded,
+ total: data.total
+ });
+ }
+ }, this);
+
+ messageHandler.on('PageError', function transportError(data) {
+ var page = this.pageCache[data.pageNum - 1];
+ var intentState = page.intentStates[data.intent];
+ if (intentState.displayReadyCapability) {
+ intentState.displayReadyCapability.reject(data.error);
+ } else {
+ error(data.error);
+ }
+ }, this);
+
+ messageHandler.on('JpegDecode', function(data) {
+ var imageUrl = data[0];
+ var components = data[1];
+ if (components !== 3 && components !== 1) {
+ return Promise.reject(
+ new Error('Only 3 components or 1 component can be returned'));
+ }
+
+ return new Promise(function (resolve, reject) {
+ var img = new Image();
+ img.onload = function () {
+ var width = img.width;
+ var height = img.height;
+ var size = width * height;
+ var rgbaLength = size * 4;
+ var buf = new Uint8Array(size * components);
+ var tmpCanvas = createScratchCanvas(width, height);
+ var tmpCtx = tmpCanvas.getContext('2d');
+ tmpCtx.drawImage(img, 0, 0);
+ var data = tmpCtx.getImageData(0, 0, width, height).data;
+ var i, j;
+
+ if (components === 3) {
+ for (i = 0, j = 0; i < rgbaLength; i += 4, j += 3) {
+ buf[j] = data[i];
+ buf[j + 1] = data[i + 1];
+ buf[j + 2] = data[i + 2];
+ }
+ } else if (components === 1) {
+ for (i = 0, j = 0; i < rgbaLength; i += 4, j++) {
+ buf[j] = data[i];
+ }
+ }
+ resolve({ data: buf, width: width, height: height});
+ };
+ img.onerror = function () {
+ reject(new Error('JpegDecode failed to load image'));
+ };
+ img.src = imageUrl;
+ });
+ });
+ },
+
+ fetchDocument: function WorkerTransport_fetchDocument(loadingTask, source) {
+ this.loadingTask = loadingTask;
+
+ source.disableAutoFetch = PDFJS.disableAutoFetch;
+ source.disableStream = PDFJS.disableStream;
+ source.chunkedViewerLoading = !!this.pdfDataRangeTransport;
+ if (this.pdfDataRangeTransport) {
+ source.length = this.pdfDataRangeTransport.length;
+ source.initialData = this.pdfDataRangeTransport.initialData;
+ }
+ this.messageHandler.send('GetDocRequest', {
+ source: source,
+ disableRange: PDFJS.disableRange,
+ maxImageSize: PDFJS.maxImageSize,
+ cMapUrl: PDFJS.cMapUrl,
+ cMapPacked: PDFJS.cMapPacked,
+ disableFontFace: PDFJS.disableFontFace,
+ disableCreateObjectURL: PDFJS.disableCreateObjectURL,
+ verbosity: PDFJS.verbosity
+ });
+ },
+
+ getData: function WorkerTransport_getData() {
+ return this.messageHandler.sendWithPromise('GetData', null);
+ },
+
+ getPage: function WorkerTransport_getPage(pageNumber, capability) {
+ if (pageNumber <= 0 || pageNumber > this.numPages ||
+ (pageNumber|0) !== pageNumber) {
+ return Promise.reject(new Error('Invalid page request'));
+ }
+
+ var pageIndex = pageNumber - 1;
+ if (pageIndex in this.pagePromises) {
+ return this.pagePromises[pageIndex];
+ }
+ var promise = this.messageHandler.sendWithPromise('GetPage', {
+ pageIndex: pageIndex
+ }).then(function (pageInfo) {
+ var page = new PDFPageProxy(pageIndex, pageInfo, this);
+ this.pageCache[pageIndex] = page;
+ return page;
+ }.bind(this));
+ this.pagePromises[pageIndex] = promise;
+ return promise;
+ },
+
+ getPageIndex: function WorkerTransport_getPageIndexByRef(ref) {
+ return this.messageHandler.sendWithPromise('GetPageIndex', { ref: ref });
+ },
+
+ getAnnotations: function WorkerTransport_getAnnotations(pageIndex) {
+ return this.messageHandler.sendWithPromise('GetAnnotations',
+ { pageIndex: pageIndex });
+ },
+
+ getDestinations: function WorkerTransport_getDestinations() {
+ return this.messageHandler.sendWithPromise('GetDestinations', null);
+ },
+
+ getDestination: function WorkerTransport_getDestination(id) {
+ return this.messageHandler.sendWithPromise('GetDestination', { id: id } );
+ },
+
+ getAttachments: function WorkerTransport_getAttachments() {
+ return this.messageHandler.sendWithPromise('GetAttachments', null);
+ },
+
+ getJavaScript: function WorkerTransport_getJavaScript() {
+ return this.messageHandler.sendWithPromise('GetJavaScript', null);
+ },
+
+ getOutline: function WorkerTransport_getOutline() {
+ return this.messageHandler.sendWithPromise('GetOutline', null);
+ },
+
+ getMetadata: function WorkerTransport_getMetadata() {
+ return this.messageHandler.sendWithPromise('GetMetadata', null).
+ then(function transportMetadata(results) {
+ return {
+ info: results[0],
+ metadata: (results[1] ? new PDFJS.Metadata(results[1]) : null)
+ };
+ });
+ },
+
+ getStats: function WorkerTransport_getStats() {
+ return this.messageHandler.sendWithPromise('GetStats', null);
+ },
+
+ startCleanup: function WorkerTransport_startCleanup() {
+ this.messageHandler.sendWithPromise('Cleanup', null).
+ then(function endCleanup() {
+ for (var i = 0, ii = this.pageCache.length; i < ii; i++) {
+ var page = this.pageCache[i];
+ if (page) {
+ page.destroy();
+ }
+ }
+ this.commonObjs.clear();
+ FontLoader.clear();
+ }.bind(this));
+ }
+ };
+ return WorkerTransport;
+
+})();
+
+/**
+ * A PDF document and page is built of many objects. E.g. there are objects
+ * for fonts, images, rendering code and such. These objects might get processed
+ * inside of a worker. The `PDFObjects` implements some basic functions to
+ * manage these objects.
+ * @ignore
+ */
+var PDFObjects = (function PDFObjectsClosure() {
+ function PDFObjects() {
+ this.objs = {};
+ }
+
+ PDFObjects.prototype = {
+ /**
+ * Internal function.
+ * Ensures there is an object defined for `objId`.
+ */
+ ensureObj: function PDFObjects_ensureObj(objId) {
+ if (this.objs[objId]) {
+ return this.objs[objId];
+ }
+
+ var obj = {
+ capability: createPromiseCapability(),
+ data: null,
+ resolved: false
+ };
+ this.objs[objId] = obj;
+
+ return obj;
+ },
+
+ /**
+ * If called *without* callback, this returns the data of `objId` but the
+ * object needs to be resolved. If it isn't, this function throws.
+ *
+ * If called *with* a callback, the callback is called with the data of the
+ * object once the object is resolved. That means, if you call this
+ * function and the object is already resolved, the callback gets called
+ * right away.
+ */
+ get: function PDFObjects_get(objId, callback) {
+ // If there is a callback, then the get can be async and the object is
+ // not required to be resolved right now
+ if (callback) {
+ this.ensureObj(objId).capability.promise.then(callback);
+ return null;
+ }
+
+ // If there isn't a callback, the user expects to get the resolved data
+ // directly.
+ var obj = this.objs[objId];
+
+ // If there isn't an object yet or the object isn't resolved, then the
+ // data isn't ready yet!
+ if (!obj || !obj.resolved) {
+ error('Requesting object that isn\'t resolved yet ' + objId);
+ }
+
+ return obj.data;
+ },
+
+ /**
+ * Resolves the object `objId` with optional `data`.
+ */
+ resolve: function PDFObjects_resolve(objId, data) {
+ var obj = this.ensureObj(objId);
+
+ obj.resolved = true;
+ obj.data = data;
+ obj.capability.resolve(data);
+ },
+
+ isResolved: function PDFObjects_isResolved(objId) {
+ var objs = this.objs;
+
+ if (!objs[objId]) {
+ return false;
+ } else {
+ return objs[objId].resolved;
+ }
+ },
+
+ hasData: function PDFObjects_hasData(objId) {
+ return this.isResolved(objId);
+ },
+
+ /**
+ * Returns the data of `objId` if object exists, null otherwise.
+ */
+ getData: function PDFObjects_getData(objId) {
+ var objs = this.objs;
+ if (!objs[objId] || !objs[objId].resolved) {
+ return null;
+ } else {
+ return objs[objId].data;
+ }
+ },
+
+ clear: function PDFObjects_clear() {
+ this.objs = {};
+ }
+ };
+ return PDFObjects;
+})();
+
+/**
+ * Allows controlling of the rendering tasks.
+ * @class
+ */
+var RenderTask = (function RenderTaskClosure() {
+ function RenderTask(internalRenderTask) {
+ this._internalRenderTask = internalRenderTask;
+
+ /**
+ * Callback for incremental rendering -- a function that will be called
+ * each time the rendering is paused. To continue rendering call the
+ * function that is the first argument to the callback.
+ * @type {function}
+ */
+ this.onContinue = null;
+ }
+
+ RenderTask.prototype = /** @lends RenderTask.prototype */ {
+ /**
+ * Promise for rendering task completion.
+ * @return {Promise}
+ */
+ get promise() {
+ return this._internalRenderTask.capability.promise;
+ },
+
+ /**
+ * Cancels the rendering task. If the task is currently rendering it will
+ * not be cancelled until graphics pauses with a timeout. The promise that
+ * this object extends will resolved when cancelled.
+ */
+ cancel: function RenderTask_cancel() {
+ this._internalRenderTask.cancel();
+ },
+
+ /**
+ * Registers callbacks to indicate the rendering task completion.
+ *
+ * @param {function} onFulfilled The callback for the rendering completion.
+ * @param {function} onRejected The callback for the rendering failure.
+ * @return {Promise} A promise that is resolved after the onFulfilled or
+ * onRejected callback.
+ */
+ then: function RenderTask_then(onFulfilled, onRejected) {
+ return this.promise.then.apply(this.promise, arguments);
+ }
+ };
+
+ return RenderTask;
+})();
+
+/**
+ * For internal use only.
+ * @ignore
+ */
+var InternalRenderTask = (function InternalRenderTaskClosure() {
+
+ function InternalRenderTask(callback, params, objs, commonObjs, operatorList,
+ pageNumber) {
+ this.callback = callback;
+ this.params = params;
+ this.objs = objs;
+ this.commonObjs = commonObjs;
+ this.operatorListIdx = null;
+ this.operatorList = operatorList;
+ this.pageNumber = pageNumber;
+ this.running = false;
+ this.graphicsReadyCallback = null;
+ this.graphicsReady = false;
+ this.cancelled = false;
+ this.capability = createPromiseCapability();
+ this.task = new RenderTask(this);
+ // caching this-bound methods
+ this._continueBound = this._continue.bind(this);
+ this._scheduleNextBound = this._scheduleNext.bind(this);
+ this._nextBound = this._next.bind(this);
+ }
+
+ InternalRenderTask.prototype = {
+
+ initalizeGraphics:
+ function InternalRenderTask_initalizeGraphics(transparency) {
+
+ if (this.cancelled) {
+ return;
+ }
+ if (PDFJS.pdfBug && 'StepperManager' in globalScope &&
+ globalScope.StepperManager.enabled) {
+ this.stepper = globalScope.StepperManager.create(this.pageNumber - 1);
+ this.stepper.init(this.operatorList);
+ this.stepper.nextBreakPoint = this.stepper.getNextBreakPoint();
+ }
+
+ var params = this.params;
+ this.gfx = new CanvasGraphics(params.canvasContext, this.commonObjs,
+ this.objs, params.imageLayer);
+
+ this.gfx.beginDrawing(params.viewport, transparency);
+ this.operatorListIdx = 0;
+ this.graphicsReady = true;
+ if (this.graphicsReadyCallback) {
+ this.graphicsReadyCallback();
+ }
+ },
+
+ cancel: function InternalRenderTask_cancel() {
+ this.running = false;
+ this.cancelled = true;
+ this.callback('cancelled');
+ },
+
+ operatorListChanged: function InternalRenderTask_operatorListChanged() {
+ if (!this.graphicsReady) {
+ if (!this.graphicsReadyCallback) {
+ this.graphicsReadyCallback = this._continueBound;
+ }
+ return;
+ }
+
+ if (this.stepper) {
+ this.stepper.updateOperatorList(this.operatorList);
+ }
+
+ if (this.running) {
+ return;
+ }
+ this._continue();
+ },
+
+ _continue: function InternalRenderTask__continue() {
+ this.running = true;
+ if (this.cancelled) {
+ return;
+ }
+ if (this.task.onContinue) {
+ this.task.onContinue.call(this.task, this._scheduleNextBound);
+ } else {
+ this._scheduleNext();
+ }
+ },
+
+ _scheduleNext: function InternalRenderTask__scheduleNext() {
+ window.requestAnimationFrame(this._nextBound);
+ },
+
+ _next: function InternalRenderTask__next() {
+ if (this.cancelled) {
+ return;
+ }
+ this.operatorListIdx = this.gfx.executeOperatorList(this.operatorList,
+ this.operatorListIdx,
+ this._continueBound,
+ this.stepper);
+ if (this.operatorListIdx === this.operatorList.argsArray.length) {
+ this.running = false;
+ if (this.operatorList.lastChunk) {
+ this.gfx.endDrawing();
+ this.callback();
+ }
+ }
+ }
+
+ };
+
+ return InternalRenderTask;
+})();
+
+
+var Metadata = PDFJS.Metadata = (function MetadataClosure() {
+ function fixMetadata(meta) {
+ return meta.replace(/>\\376\\377([^<]+)/g, function(all, codes) {
+ var bytes = codes.replace(/\\([0-3])([0-7])([0-7])/g,
+ function(code, d1, d2, d3) {
+ return String.fromCharCode(d1 * 64 + d2 * 8 + d3 * 1);
+ });
+ var chars = '';
+ for (var i = 0; i < bytes.length; i += 2) {
+ var code = bytes.charCodeAt(i) * 256 + bytes.charCodeAt(i + 1);
+ chars += code >= 32 && code < 127 && code !== 60 && code !== 62 &&
+ code !== 38 && false ? String.fromCharCode(code) :
+ '' + (0x10000 + code).toString(16).substring(1) + ';';
+ }
+ return '>' + chars;
+ });
+ }
+
+ function Metadata(meta) {
+ if (typeof meta === 'string') {
+ // Ghostscript produces invalid metadata
+ meta = fixMetadata(meta);
+
+ var parser = new DOMParser();
+ meta = parser.parseFromString(meta, 'application/xml');
+ } else if (!(meta instanceof Document)) {
+ error('Metadata: Invalid metadata object');
+ }
+
+ this.metaDocument = meta;
+ this.metadata = {};
+ this.parse();
+ }
+
+ Metadata.prototype = {
+ parse: function Metadata_parse() {
+ var doc = this.metaDocument;
+ var rdf = doc.documentElement;
+
+ if (rdf.nodeName.toLowerCase() !== 'rdf:rdf') { // Wrapped in
+ rdf = rdf.firstChild;
+ while (rdf && rdf.nodeName.toLowerCase() !== 'rdf:rdf') {
+ rdf = rdf.nextSibling;
+ }
+ }
+
+ var nodeName = (rdf) ? rdf.nodeName.toLowerCase() : null;
+ if (!rdf || nodeName !== 'rdf:rdf' || !rdf.hasChildNodes()) {
+ return;
+ }
+
+ var children = rdf.childNodes, desc, entry, name, i, ii, length, iLength;
+ for (i = 0, length = children.length; i < length; i++) {
+ desc = children[i];
+ if (desc.nodeName.toLowerCase() !== 'rdf:description') {
+ continue;
+ }
+
+ for (ii = 0, iLength = desc.childNodes.length; ii < iLength; ii++) {
+ if (desc.childNodes[ii].nodeName.toLowerCase() !== '#text') {
+ entry = desc.childNodes[ii];
+ name = entry.nodeName.toLowerCase();
+ this.metadata[name] = entry.textContent.trim();
+ }
+ }
+ }
+ },
+
+ get: function Metadata_get(name) {
+ return this.metadata[name] || null;
+ },
+
+ has: function Metadata_has(name) {
+ return typeof this.metadata[name] !== 'undefined';
+ }
+ };
+
+ return Metadata;
+})();
+
+
+//