You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1577 lines
44 KiB
1577 lines
44 KiB
/* -*- 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 multiple arguments were passed, pass them all to the log function. |
|
if (arguments.length > 1) { |
|
var logArguments = ['Error:']; |
|
logArguments.push.apply(logArguments, arguments); |
|
console.log.apply(console, logArguments); |
|
// Join the arguments into a single string for the lines below. |
|
msg = [].join.call(arguments, ' '); |
|
} else { |
|
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': |
|
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; |
|
} |
|
|
|
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; |
|
})(); |
|
|
|
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; |
|
})(); |
|
|
|
var InvalidPDFException = (function InvalidPDFExceptionClosure() { |
|
function InvalidPDFException(msg) { |
|
this.name = 'InvalidPDFException'; |
|
this.message = msg; |
|
} |
|
|
|
InvalidPDFException.prototype = new Error(); |
|
InvalidPDFException.constructor = InvalidPDFException; |
|
|
|
return InvalidPDFException; |
|
})(); |
|
|
|
var MissingPDFException = (function MissingPDFExceptionClosure() { |
|
function MissingPDFException(msg) { |
|
this.name = 'MissingPDFException'; |
|
this.message = msg; |
|
} |
|
|
|
MissingPDFException.prototype = new Error(); |
|
MissingPDFException.constructor = MissingPDFException; |
|
|
|
return MissingPDFException; |
|
})(); |
|
|
|
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) { |
|
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 stringToArray(str) { |
|
var length = str.length; |
|
var array = []; |
|
for (var i = 0; i < length; ++i) { |
|
array[i] = str.charCodeAt(i); |
|
} |
|
return array; |
|
} |
|
|
|
function stringToBytes(str) { |
|
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(rgb) { |
|
rgbBuf[1] = rgb[0]; |
|
rgbBuf[3] = rgb[1]; |
|
rgbBuf[5] = rgb[2]; |
|
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 isNull(v) { |
|
return v === null; |
|
} |
|
|
|
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; |
|
}
|
|
|