2012-09-01 07:48:21 +09:00
|
|
|
/* 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.
|
|
|
|
*/
|
2017-02-17 21:44:49 +09:00
|
|
|
/* globals global, process, __pdfjsdev_webpack__ */
|
2011-10-26 10:18:22 +09:00
|
|
|
|
|
|
|
'use strict';
|
|
|
|
|
2015-11-22 01:32:47 +09:00
|
|
|
(function (root, factory) {
|
|
|
|
if (typeof define === 'function' && define.amd) {
|
2017-02-24 07:35:35 +09:00
|
|
|
define('pdfjs/shared/util', ['exports', 'pdfjs/shared/compatibility'],
|
|
|
|
factory);
|
2015-11-22 01:32:47 +09:00
|
|
|
} else if (typeof exports !== 'undefined') {
|
2017-02-24 07:35:35 +09:00
|
|
|
factory(exports, require('./compatibility.js'));
|
2015-11-22 01:32:47 +09:00
|
|
|
} else {
|
2017-02-24 07:35:35 +09:00
|
|
|
factory((root.pdfjsSharedUtil = {}), root.pdfjsSharedCompatibility);
|
2015-11-22 01:32:47 +09:00
|
|
|
}
|
2017-02-24 07:35:35 +09:00
|
|
|
}(this, function (exports, compatibility) {
|
2013-08-13 02:48:06 +09:00
|
|
|
|
2016-03-03 09:48:21 +09:00
|
|
|
var globalScope = (typeof window !== 'undefined') ? window :
|
|
|
|
(typeof global !== 'undefined') ? global :
|
|
|
|
(typeof self !== 'undefined') ? self : this;
|
2013-08-13 02:48:06 +09:00
|
|
|
|
|
|
|
var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
|
|
|
|
|
2013-08-20 08:33:20 +09:00
|
|
|
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
|
|
|
|
};
|
|
|
|
|
2014-02-26 08:11:15 +09:00
|
|
|
var ImageKind = {
|
|
|
|
GRAYSCALE_1BPP: 1,
|
|
|
|
RGB_24BPP: 2,
|
|
|
|
RGBA_32BPP: 3
|
|
|
|
};
|
|
|
|
|
2014-06-18 07:43:33 +09:00
|
|
|
var AnnotationType = {
|
2015-12-15 22:52:17 +09:00
|
|
|
TEXT: 1,
|
|
|
|
LINK: 2,
|
|
|
|
FREETEXT: 3,
|
|
|
|
LINE: 4,
|
|
|
|
SQUARE: 5,
|
|
|
|
CIRCLE: 6,
|
|
|
|
POLYGON: 7,
|
|
|
|
POLYLINE: 8,
|
|
|
|
HIGHLIGHT: 9,
|
|
|
|
UNDERLINE: 10,
|
|
|
|
SQUIGGLY: 11,
|
|
|
|
STRIKEOUT: 12,
|
|
|
|
STAMP: 13,
|
|
|
|
CARET: 14,
|
|
|
|
INK: 15,
|
|
|
|
POPUP: 16,
|
|
|
|
FILEATTACHMENT: 17,
|
|
|
|
SOUND: 18,
|
|
|
|
MOVIE: 19,
|
|
|
|
WIDGET: 20,
|
|
|
|
SCREEN: 21,
|
|
|
|
PRINTERMARK: 22,
|
|
|
|
TRAPNET: 23,
|
|
|
|
WATERMARK: 24,
|
|
|
|
THREED: 25,
|
|
|
|
REDACT: 26
|
2014-06-18 07:43:33 +09:00
|
|
|
};
|
|
|
|
|
2015-11-22 07:25:17 +09:00
|
|
|
var AnnotationFlag = {
|
|
|
|
INVISIBLE: 0x01,
|
|
|
|
HIDDEN: 0x02,
|
|
|
|
PRINT: 0x04,
|
|
|
|
NOZOOM: 0x08,
|
|
|
|
NOROTATE: 0x10,
|
|
|
|
NOVIEW: 0x20,
|
|
|
|
READONLY: 0x40,
|
|
|
|
LOCKED: 0x80,
|
|
|
|
TOGGLENOVIEW: 0x100,
|
|
|
|
LOCKEDCONTENTS: 0x200
|
|
|
|
};
|
|
|
|
|
2016-09-14 23:32:51 +09:00
|
|
|
var AnnotationFieldFlag = {
|
2016-09-22 04:06:44 +09:00
|
|
|
READONLY: 0x0000001,
|
|
|
|
REQUIRED: 0x0000002,
|
|
|
|
NOEXPORT: 0x0000004,
|
|
|
|
MULTILINE: 0x0001000,
|
|
|
|
PASSWORD: 0x0002000,
|
|
|
|
NOTOGGLETOOFF: 0x0004000,
|
|
|
|
RADIO: 0x0008000,
|
|
|
|
PUSHBUTTON: 0x0010000,
|
|
|
|
COMBO: 0x0020000,
|
|
|
|
EDIT: 0x0040000,
|
|
|
|
SORT: 0x0080000,
|
|
|
|
FILESELECT: 0x0100000,
|
|
|
|
MULTISELECT: 0x0200000,
|
|
|
|
DONOTSPELLCHECK: 0x0400000,
|
|
|
|
DONOTSCROLL: 0x0800000,
|
|
|
|
COMB: 0x1000000,
|
|
|
|
RICHTEXT: 0x2000000,
|
|
|
|
RADIOSINUNISON: 0x2000000,
|
|
|
|
COMMITONSELCHANGE: 0x4000000,
|
2016-09-14 23:32:51 +09:00
|
|
|
};
|
|
|
|
|
2014-12-26 04:11:23 +09:00
|
|
|
var AnnotationBorderStyleType = {
|
|
|
|
SOLID: 1,
|
|
|
|
DASHED: 2,
|
|
|
|
BEVELED: 3,
|
|
|
|
INSET: 4,
|
|
|
|
UNDERLINE: 5
|
|
|
|
};
|
|
|
|
|
2014-06-16 23:52:04 +09:00
|
|
|
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
|
|
|
|
};
|
|
|
|
|
2016-03-03 09:48:21 +09:00
|
|
|
var VERBOSITY_LEVELS = {
|
2013-12-19 06:39:03 +09:00
|
|
|
errors: 0,
|
|
|
|
warnings: 1,
|
|
|
|
infos: 5
|
|
|
|
};
|
|
|
|
|
2017-02-12 23:54:41 +09:00
|
|
|
var CMapCompressionType = {
|
|
|
|
NONE: 0,
|
|
|
|
BINARY: 1,
|
|
|
|
STREAM: 2,
|
|
|
|
};
|
|
|
|
|
2013-11-14 04:43:38 +09:00
|
|
|
// All the possible operations for an operator list.
|
2016-03-03 09:48:21 +09:00
|
|
|
var OPS = {
|
2013-11-18 19:58:38 +09:00
|
|
|
// Intentionally start from 1 so it is easy to spot bad operators that will be
|
2013-11-14 04:43:38 +09:00
|
|
|
// 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,
|
2014-02-24 23:00:08 +09:00
|
|
|
paintInlineImageXObjectGroup: 87,
|
2014-02-25 00:59:02 +09:00
|
|
|
paintImageXObjectRepeat: 88,
|
2014-03-17 00:17:13 +09:00
|
|
|
paintImageMaskXObjectRepeat: 89,
|
2014-04-30 23:09:04 +09:00
|
|
|
paintSolidColorImageMask: 90,
|
|
|
|
constructPath: 91
|
2013-11-14 04:43:38 +09:00
|
|
|
};
|
2013-08-13 02:48:06 +09:00
|
|
|
|
2016-03-03 09:48:21 +09:00
|
|
|
var verbosity = VERBOSITY_LEVELS.warnings;
|
|
|
|
|
|
|
|
function setVerbosityLevel(level) {
|
|
|
|
verbosity = level;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getVerbosityLevel() {
|
|
|
|
return verbosity;
|
|
|
|
}
|
|
|
|
|
2014-01-04 02:34:13 +09:00
|
|
|
// 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.
|
2012-05-15 09:19:09 +09:00
|
|
|
function info(msg) {
|
2016-03-03 09:48:21 +09:00
|
|
|
if (verbosity >= VERBOSITY_LEVELS.infos) {
|
2014-01-16 06:28:31 +09:00
|
|
|
console.log('Info: ' + msg);
|
2012-05-15 09:19:09 +09:00
|
|
|
}
|
2011-10-25 08:55:23 +09:00
|
|
|
}
|
|
|
|
|
2014-01-04 02:34:13 +09:00
|
|
|
// Non-fatal warnings.
|
2012-05-15 09:19:09 +09:00
|
|
|
function warn(msg) {
|
2016-03-03 09:48:21 +09:00
|
|
|
if (verbosity >= VERBOSITY_LEVELS.warnings) {
|
2014-01-16 06:28:31 +09:00
|
|
|
console.log('Warning: ' + msg);
|
2011-10-25 08:55:23 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-25 20:20:55 +09:00
|
|
|
// Deprecated API function -- display regardless of the PDFJS.verbosity setting.
|
2015-10-21 22:54:31 +09:00
|
|
|
function deprecated(details) {
|
2016-01-25 20:20:55 +09:00
|
|
|
console.log('Deprecated API usage: ' + details);
|
2015-10-21 22:54:31 +09:00
|
|
|
}
|
|
|
|
|
2012-05-15 09:19:09 +09:00
|
|
|
// Fatal errors that should trigger the fallback UI and halt execution by
|
|
|
|
// throwing an exception.
|
2011-10-25 08:55:23 +09:00
|
|
|
function error(msg) {
|
2016-03-03 09:48:21 +09:00
|
|
|
if (verbosity >= VERBOSITY_LEVELS.errors) {
|
2014-01-16 06:28:31 +09:00
|
|
|
console.log('Error: ' + msg);
|
2015-03-29 04:44:41 +09:00
|
|
|
console.log(backtrace());
|
2012-08-31 20:40:37 +09:00
|
|
|
}
|
2011-10-25 08:55:23 +09:00
|
|
|
throw new Error(msg);
|
|
|
|
}
|
|
|
|
|
2012-05-15 09:19:09 +09:00
|
|
|
function backtrace() {
|
|
|
|
try {
|
|
|
|
throw new Error();
|
|
|
|
} catch (e) {
|
|
|
|
return e.stack ? e.stack.split('\n').slice(2).join('\n') : '';
|
|
|
|
}
|
2011-10-25 08:55:23 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
function assert(cond, msg) {
|
2014-03-03 21:21:57 +09:00
|
|
|
if (!cond) {
|
2011-10-25 08:55:23 +09:00
|
|
|
error(msg);
|
2014-03-03 21:21:57 +09:00
|
|
|
}
|
2011-10-25 08:55:23 +09:00
|
|
|
}
|
|
|
|
|
2016-03-03 09:48:21 +09:00
|
|
|
var UNSUPPORTED_FEATURES = {
|
2014-01-04 02:34:13 +09:00
|
|
|
unknown: 'unknown',
|
|
|
|
forms: 'forms',
|
|
|
|
javaScript: 'javaScript',
|
|
|
|
smask: 'smask',
|
|
|
|
shadingPattern: 'shadingPattern',
|
|
|
|
font: 'font'
|
|
|
|
};
|
|
|
|
|
2016-01-16 06:05:46 +09:00
|
|
|
// Checks if URLs have the same origin. For non-HTTP based URLs, returns false.
|
|
|
|
function isSameOrigin(baseUrl, otherUrl) {
|
|
|
|
try {
|
|
|
|
var base = new URL(baseUrl);
|
|
|
|
if (!base.origin || base.origin === 'null') {
|
|
|
|
return false; // non-HTTP url
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
var other = new URL(otherUrl, base);
|
|
|
|
return base.origin === other.origin;
|
|
|
|
}
|
|
|
|
|
2016-10-03 21:35:29 +09:00
|
|
|
// Checks if URLs use one of the whitelisted protocols, e.g. to avoid XSS.
|
|
|
|
function isValidProtocol(url) {
|
|
|
|
if (!url) {
|
2013-07-13 03:36:20 +09:00
|
|
|
return false;
|
|
|
|
}
|
2016-10-03 21:35:29 +09:00
|
|
|
switch (url.protocol) {
|
|
|
|
case 'http:':
|
|
|
|
case 'https:':
|
|
|
|
case 'ftp:':
|
|
|
|
case 'mailto:':
|
|
|
|
case 'tel:':
|
2013-07-13 03:36:20 +09:00
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2015-12-22 20:59:23 +09:00
|
|
|
|
2016-10-03 21:35:29 +09:00
|
|
|
/**
|
|
|
|
* Attempts to create a valid absolute URL (utilizing `isValidProtocol`).
|
|
|
|
* @param {URL|string} url - An absolute, or relative, URL.
|
|
|
|
* @param {URL|string} baseUrl - An absolute URL.
|
|
|
|
* @returns Either a valid {URL}, or `null` otherwise.
|
|
|
|
*/
|
|
|
|
function createValidAbsoluteUrl(url, baseUrl) {
|
|
|
|
if (!url) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
var absoluteUrl = baseUrl ? new URL(url, baseUrl) : new URL(url);
|
|
|
|
if (isValidProtocol(absoluteUrl)) {
|
|
|
|
return absoluteUrl;
|
|
|
|
}
|
|
|
|
} catch (ex) { /* `new URL()` will throw on incorrect data. */ }
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2011-10-25 08:55:23 +09:00
|
|
|
function shadow(obj, prop, value) {
|
2017-04-25 23:07:59 +09:00
|
|
|
Object.defineProperty(obj, prop, { value,
|
2011-10-25 08:55:23 +09:00
|
|
|
enumerable: true,
|
|
|
|
configurable: true,
|
|
|
|
writable: false });
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2016-01-22 05:47:48 +09:00
|
|
|
function getLookupTableFactory(initializer) {
|
|
|
|
var lookup;
|
|
|
|
return function () {
|
|
|
|
if (initializer) {
|
|
|
|
lookup = Object.create(null);
|
|
|
|
initializer(lookup);
|
|
|
|
initializer = null;
|
|
|
|
}
|
|
|
|
return lookup;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-03-03 09:48:21 +09:00
|
|
|
var PasswordResponses = {
|
2013-05-10 07:35:23 +09:00
|
|
|
NEED_PASSWORD: 1,
|
|
|
|
INCORRECT_PASSWORD: 2
|
|
|
|
};
|
|
|
|
|
2012-05-18 04:34:39 +09:00
|
|
|
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;
|
|
|
|
})();
|
2012-05-15 03:45:07 +09:00
|
|
|
|
2012-10-16 19:10:37 +09:00
|
|
|
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;
|
|
|
|
})();
|
|
|
|
|
2013-01-30 03:13:28 +09:00
|
|
|
var MissingPDFException = (function MissingPDFExceptionClosure() {
|
|
|
|
function MissingPDFException(msg) {
|
|
|
|
this.name = 'MissingPDFException';
|
|
|
|
this.message = msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
MissingPDFException.prototype = new Error();
|
|
|
|
MissingPDFException.constructor = MissingPDFException;
|
|
|
|
|
|
|
|
return MissingPDFException;
|
|
|
|
})();
|
|
|
|
|
2014-09-13 23:47:16 +09:00
|
|
|
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;
|
|
|
|
})();
|
|
|
|
|
2013-02-07 08:19:29 +09:00
|
|
|
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;
|
2013-11-14 08:27:46 +09:00
|
|
|
this.message = 'Missing data [' + begin + ', ' + end + ')';
|
2013-02-07 08:19:29 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
})();
|
|
|
|
|
2016-01-05 05:33:41 +09:00
|
|
|
var NullCharactersRegExp = /\x00/g;
|
|
|
|
|
|
|
|
function removeNullCharacters(str) {
|
|
|
|
if (typeof str !== 'string') {
|
|
|
|
warn('The argument for removeNullCharacters must be a string.');
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
return str.replace(NullCharactersRegExp, '');
|
|
|
|
}
|
2013-02-07 08:19:29 +09:00
|
|
|
|
2011-10-25 08:55:23 +09:00
|
|
|
function bytesToString(bytes) {
|
2014-12-30 22:18:51 +09:00
|
|
|
assert(bytes !== null && typeof bytes === 'object' &&
|
|
|
|
bytes.length !== undefined, 'Invalid argument for bytesToString');
|
2011-10-25 08:55:23 +09:00
|
|
|
var length = bytes.length;
|
2014-03-27 21:01:43 +09:00
|
|
|
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));
|
2014-02-28 08:23:56 +09:00
|
|
|
}
|
|
|
|
return strBuf.join('');
|
2011-10-25 08:55:23 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
function stringToBytes(str) {
|
2014-12-30 22:18:51 +09:00
|
|
|
assert(typeof str === 'string', 'Invalid argument for stringToBytes');
|
2011-10-25 08:55:23 +09:00
|
|
|
var length = str.length;
|
|
|
|
var bytes = new Uint8Array(length);
|
2014-03-27 21:01:43 +09:00
|
|
|
for (var i = 0; i < length; ++i) {
|
|
|
|
bytes[i] = str.charCodeAt(i) & 0xFF;
|
2014-03-03 21:21:57 +09:00
|
|
|
}
|
2011-10-25 08:55:23 +09:00
|
|
|
return bytes;
|
|
|
|
}
|
|
|
|
|
2016-02-10 05:55:11 +09:00
|
|
|
/**
|
|
|
|
* Gets length of the array (Array, Uint8Array, or string) in bytes.
|
|
|
|
* @param {Array|Uint8Array|string} arr
|
|
|
|
* @returns {number}
|
|
|
|
*/
|
|
|
|
function arrayByteLength(arr) {
|
|
|
|
if (arr.length !== undefined) {
|
|
|
|
return arr.length;
|
|
|
|
}
|
|
|
|
assert(arr.byteLength !== undefined);
|
|
|
|
return arr.byteLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Combines array items (arrays) into single Uint8Array object.
|
|
|
|
* @param {Array} arr - the array of the arrays (Array, Uint8Array, or string).
|
|
|
|
* @returns {Uint8Array}
|
|
|
|
*/
|
|
|
|
function arraysToBytes(arr) {
|
|
|
|
// Shortcut: if first and only item is Uint8Array, return it.
|
|
|
|
if (arr.length === 1 && (arr[0] instanceof Uint8Array)) {
|
|
|
|
return arr[0];
|
|
|
|
}
|
|
|
|
var resultLength = 0;
|
|
|
|
var i, ii = arr.length;
|
2016-12-11 06:15:23 +09:00
|
|
|
var item, itemLength;
|
2016-02-10 05:55:11 +09:00
|
|
|
for (i = 0; i < ii; i++) {
|
|
|
|
item = arr[i];
|
|
|
|
itemLength = arrayByteLength(item);
|
|
|
|
resultLength += itemLength;
|
|
|
|
}
|
|
|
|
var pos = 0;
|
|
|
|
var data = new Uint8Array(resultLength);
|
|
|
|
for (i = 0; i < ii; i++) {
|
|
|
|
item = arr[i];
|
|
|
|
if (!(item instanceof Uint8Array)) {
|
|
|
|
if (typeof item === 'string') {
|
|
|
|
item = stringToBytes(item);
|
|
|
|
} else {
|
|
|
|
item = new Uint8Array(item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
itemLength = item.byteLength;
|
|
|
|
data.set(item, pos);
|
|
|
|
pos += itemLength;
|
|
|
|
}
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2014-03-27 21:01:43 +09:00
|
|
|
function string32(value) {
|
|
|
|
return String.fromCharCode((value >> 24) & 0xff, (value >> 16) & 0xff,
|
|
|
|
(value >> 8) & 0xff, value & 0xff);
|
|
|
|
}
|
|
|
|
|
2014-04-17 04:31:16 +09:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-03-21 00:57:11 +09:00
|
|
|
// Lazy test the endianness of the platform
|
|
|
|
// NOTE: This will be 'true' for simulated TypedArrays
|
|
|
|
function isLittleEndian() {
|
2017-04-14 03:16:35 +09:00
|
|
|
var buffer8 = new Uint8Array(4);
|
2014-03-21 00:57:11 +09:00
|
|
|
buffer8[0] = 1;
|
2017-04-14 03:16:35 +09:00
|
|
|
var view32 = new Uint32Array(buffer8.buffer, 0, 1);
|
|
|
|
return (view32[0] === 1);
|
2014-03-21 00:57:11 +09:00
|
|
|
}
|
|
|
|
|
2016-03-29 04:49:22 +09:00
|
|
|
// Checks if it's possible to eval JS expressions.
|
|
|
|
function isEvalSupported() {
|
|
|
|
try {
|
Switch to using ESLint, instead of JSHint, for linting
*Please note that most of the necessary code adjustments were made in PR 7890.*
ESLint has a number of advantageous properties, compared to JSHint. Among those are:
- The ability to find subtle bugs, thanks to more rules (e.g. PR 7881).
- Much more customizable in general, and many rules allow fine-tuned behaviour rather than the just the on/off rules in JSHint.
- Many more rules that can help developers avoid bugs, and a lot of rules that can be used to enforce a consistent coding style. The latter should be particularily useful for new contributors (and reduce the amount of stylistic review comments necessary).
- The ability to easily specify exactly what rules to use/not to use, as opposed to JSHint which has a default set. *Note:* in future JSHint version some of the rules we depend on will be removed, according to warnings in http://jshint.com/docs/options/, so we wouldn't be able to update without losing lint coverage.
- More easily disable one, or more, rules temporarily. In JSHint this requires using a numeric code, which isn't very user friendly, whereas in ESLint the rule name is simply used instead.
By default there's no rules enabled in ESLint, but there are some default rule sets available. However, to prevent linting failures if we update ESLint in the future, it seemed easier to just explicitly specify what rules we want.
Obviously this makes the ESLint config file somewhat bigger than the old JSHint config file, but given how rarely that one has been updated over the years I don't think that matters too much.
I've tried, to the best of my ability, to ensure that we enable the same rules for ESLint that we had for JSHint. Furthermore, I've also enabled a number of rules that seemed to make sense, both to catch possible errors *and* various style guide violations.
Despite the ESLint README claiming that it's slower that JSHint, https://github.com/eslint/eslint#how-does-eslint-performance-compare-to-jshint, locally this patch actually reduces the runtime for `gulp` lint (by approximately 20-25%).
A couple of stylistic rules that would have been nice to enable, but where our code currently differs to much to make it feasible:
- `comma-dangle`, controls trailing commas in Objects and Arrays (among others).
- `object-curly-spacing`, controls spacing inside of Objects.
- `spaced-comment`, used to enforce spaces after `//` and `/*. (This is made difficult by the fact that there's still some usage of the old preprocessor left.)
Rules that I indend to look into possibly enabling in follow-ups, if it seems to make sense: `no-else-return`, `no-lonely-if`, `brace-style` with the `allowSingleLine` parameter removed.
Useful links:
- http://eslint.org/docs/user-guide/configuring
- http://eslint.org/docs/rules/
2016-12-15 23:52:29 +09:00
|
|
|
new Function(''); // eslint-disable-line no-new, no-new-func
|
2016-03-29 04:49:22 +09:00
|
|
|
return true;
|
|
|
|
} catch (e) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-25 08:55:23 +09:00
|
|
|
var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
|
|
|
|
|
2016-03-03 09:48:21 +09:00
|
|
|
var Util = (function UtilClosure() {
|
2011-12-09 07:18:43 +09:00
|
|
|
function Util() {}
|
2012-02-02 07:48:44 +09:00
|
|
|
|
2014-07-09 13:31:07 +09:00
|
|
|
var rgbBuf = ['rgb(', 0, ',', 0, ',', 0, ')'];
|
|
|
|
|
|
|
|
// makeCssRgb() can be called thousands of times. Using |rgbBuf| avoids
|
|
|
|
// creating many intermediate strings.
|
2014-10-28 05:30:47 +09:00
|
|
|
Util.makeCssRgb = function Util_makeCssRgb(r, g, b) {
|
|
|
|
rgbBuf[1] = r;
|
|
|
|
rgbBuf[3] = g;
|
|
|
|
rgbBuf[5] = b;
|
2014-07-09 13:31:07 +09:00
|
|
|
return rgbBuf.join('');
|
2011-10-25 08:55:23 +09:00
|
|
|
};
|
2012-02-02 07:48:44 +09:00
|
|
|
|
2013-04-16 08:14:07 +09:00
|
|
|
// 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]
|
|
|
|
];
|
|
|
|
};
|
|
|
|
|
2012-02-02 07:48:44 +09:00
|
|
|
// For 2d affine transforms
|
2012-04-05 05:43:26 +09:00
|
|
|
Util.applyTransform = function Util_applyTransform(p, m) {
|
2011-10-25 08:55:23 +09:00
|
|
|
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];
|
|
|
|
};
|
|
|
|
|
2012-05-02 02:48:07 +09:00
|
|
|
Util.applyInverseTransform = function Util_applyInverseTransform(p, m) {
|
2012-04-12 00:29:44 +09:00
|
|
|
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];
|
|
|
|
};
|
|
|
|
|
2013-03-13 09:20:38 +09:00
|
|
|
// 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])
|
|
|
|
];
|
|
|
|
};
|
|
|
|
|
2012-04-12 00:29:44 +09:00
|
|
|
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];
|
|
|
|
};
|
|
|
|
|
2012-02-02 07:48:44 +09:00
|
|
|
// 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]
|
2012-04-05 05:43:26 +09:00
|
|
|
Util.apply3dTransform = function Util_apply3dTransform(m, v) {
|
2012-02-02 07:48:44 +09:00
|
|
|
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]
|
|
|
|
];
|
2013-02-01 08:33:38 +09:00
|
|
|
};
|
2012-02-02 07:48:44 +09:00
|
|
|
|
2012-12-27 16:35:25 +09:00
|
|
|
// 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)];
|
|
|
|
};
|
|
|
|
|
2012-02-15 04:48:58 +09:00
|
|
|
// 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.
|
2012-04-05 05:43:26 +09:00
|
|
|
Util.normalizeRect = function Util_normalizeRect(rect) {
|
2012-02-15 04:48:58 +09:00
|
|
|
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;
|
2013-02-01 08:33:38 +09:00
|
|
|
};
|
2012-02-15 04:48:58 +09:00
|
|
|
|
|
|
|
// 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]
|
2012-04-05 05:43:26 +09:00
|
|
|
Util.intersect = function Util_intersect(rect1, rect2) {
|
2012-02-15 04:48:58 +09:00
|
|
|
function compare(a, b) {
|
|
|
|
return a - b;
|
2013-02-01 08:33:38 +09:00
|
|
|
}
|
2012-02-15 04:48:58 +09:00
|
|
|
|
|
|
|
// 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;
|
2012-04-12 00:29:44 +09:00
|
|
|
};
|
2012-02-15 04:48:58 +09:00
|
|
|
|
2012-04-05 05:43:26 +09:00
|
|
|
Util.sign = function Util_sign(num) {
|
2012-01-24 05:23:09 +09:00
|
|
|
return num < 0 ? -1 : 1;
|
|
|
|
};
|
|
|
|
|
2015-12-26 05:57:08 +09:00
|
|
|
var ROMAN_NUMBER_MAP = [
|
|
|
|
'', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM',
|
|
|
|
'', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC',
|
|
|
|
'', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'
|
|
|
|
];
|
|
|
|
/**
|
|
|
|
* Converts positive integers to (upper case) Roman numerals.
|
|
|
|
* @param {integer} number - The number that should be converted.
|
|
|
|
* @param {boolean} lowerCase - Indicates if the result should be converted
|
|
|
|
* to lower case letters. The default is false.
|
|
|
|
* @return {string} The resulting Roman number.
|
|
|
|
*/
|
|
|
|
Util.toRoman = function Util_toRoman(number, lowerCase) {
|
|
|
|
assert(isInt(number) && number > 0,
|
|
|
|
'The number should be a positive integer.');
|
|
|
|
var pos, romanBuf = [];
|
|
|
|
// Thousands
|
|
|
|
while (number >= 1000) {
|
|
|
|
number -= 1000;
|
|
|
|
romanBuf.push('M');
|
|
|
|
}
|
|
|
|
// Hundreds
|
|
|
|
pos = (number / 100) | 0;
|
|
|
|
number %= 100;
|
|
|
|
romanBuf.push(ROMAN_NUMBER_MAP[pos]);
|
|
|
|
// Tens
|
|
|
|
pos = (number / 10) | 0;
|
|
|
|
number %= 10;
|
|
|
|
romanBuf.push(ROMAN_NUMBER_MAP[10 + pos]);
|
|
|
|
// Ones
|
|
|
|
romanBuf.push(ROMAN_NUMBER_MAP[20 + number]);
|
|
|
|
|
|
|
|
var romanStr = romanBuf.join('');
|
|
|
|
return (lowerCase ? romanStr.toLowerCase() : romanStr);
|
|
|
|
};
|
|
|
|
|
2014-06-17 05:10:10 +09:00
|
|
|
Util.appendToArray = function Util_appendToArray(arr1, arr2) {
|
2013-04-09 07:14:56 +09:00
|
|
|
Array.prototype.push.apply(arr1, arr2);
|
|
|
|
};
|
|
|
|
|
2014-06-17 05:10:10 +09:00
|
|
|
Util.prependToArray = function Util_prependToArray(arr1, arr2) {
|
2013-04-09 07:14:56 +09:00
|
|
|
Array.prototype.unshift.apply(arr1, arr2);
|
|
|
|
};
|
|
|
|
|
|
|
|
Util.extendObj = function extendObj(obj1, obj2) {
|
|
|
|
for (var key in obj2) {
|
|
|
|
obj1[key] = obj2[key];
|
|
|
|
}
|
2013-03-14 04:24:55 +09:00
|
|
|
};
|
|
|
|
|
2016-09-25 08:45:49 +09:00
|
|
|
Util.getInheritableProperty =
|
|
|
|
function Util_getInheritableProperty(dict, name, getArray) {
|
2013-03-21 17:04:44 +09:00
|
|
|
while (dict && !dict.has(name)) {
|
|
|
|
dict = dict.get('Parent');
|
|
|
|
}
|
|
|
|
if (!dict) {
|
|
|
|
return null;
|
|
|
|
}
|
2016-09-25 08:45:49 +09:00
|
|
|
return getArray ? dict.getArray(name) : dict.get(name);
|
2013-03-21 17:04:44 +09:00
|
|
|
};
|
|
|
|
|
|
|
|
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];
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-08-13 02:48:06 +09:00
|
|
|
Util.loadScript = function Util_loadScript(src, callback) {
|
|
|
|
var script = document.createElement('script');
|
|
|
|
var loaded = false;
|
|
|
|
script.setAttribute('src', src);
|
|
|
|
if (callback) {
|
2013-08-16 23:19:42 +09:00
|
|
|
script.onload = function() {
|
2013-08-13 02:48:06 +09:00
|
|
|
if (!loaded) {
|
|
|
|
callback();
|
|
|
|
}
|
|
|
|
loaded = true;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
document.getElementsByTagName('head')[0].appendChild(script);
|
|
|
|
};
|
|
|
|
|
2011-12-09 07:18:43 +09:00
|
|
|
return Util;
|
2011-10-25 08:55:23 +09:00
|
|
|
})();
|
|
|
|
|
2014-05-06 04:09:47 +09:00
|
|
|
/**
|
|
|
|
* PDF page viewport created based on scale, rotation and offset.
|
|
|
|
* @class
|
2016-03-29 04:49:22 +09:00
|
|
|
* @alias PageViewport
|
2014-05-06 04:09:47 +09:00
|
|
|
*/
|
2016-03-03 09:48:21 +09:00
|
|
|
var PageViewport = (function PageViewportClosure() {
|
2014-05-06 04:09:47 +09:00
|
|
|
/**
|
|
|
|
* @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.
|
|
|
|
*/
|
2013-03-21 17:04:44 +09:00
|
|
|
function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) {
|
2013-03-09 11:08:37 +09:00
|
|
|
this.viewBox = viewBox;
|
|
|
|
this.scale = scale;
|
|
|
|
this.rotation = rotation;
|
|
|
|
this.offsetX = offsetX;
|
|
|
|
this.offsetY = offsetY;
|
|
|
|
|
2012-04-12 00:29:44 +09:00
|
|
|
// 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;
|
2013-03-21 17:04:44 +09:00
|
|
|
rotation = rotation % 360;
|
|
|
|
rotation = rotation < 0 ? rotation + 360 : rotation;
|
|
|
|
switch (rotation) {
|
2012-04-12 00:29:44 +09:00
|
|
|
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;
|
2017-01-20 00:26:32 +09:00
|
|
|
// case 0:
|
2012-04-12 00:29:44 +09:00
|
|
|
default:
|
|
|
|
rotateA = 1; rotateB = 0; rotateC = 0; rotateD = -1;
|
|
|
|
break;
|
|
|
|
}
|
2013-03-21 17:04:44 +09:00
|
|
|
|
|
|
|
if (dontFlip) {
|
|
|
|
rotateC = -rotateC; rotateD = -rotateD;
|
|
|
|
}
|
|
|
|
|
2012-04-12 00:29:44 +09:00
|
|
|
var offsetCanvasX, offsetCanvasY;
|
|
|
|
var width, height;
|
2013-02-01 08:33:38 +09:00
|
|
|
if (rotateA === 0) {
|
2012-04-12 00:29:44 +09:00
|
|
|
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;
|
2012-04-13 00:23:38 +09:00
|
|
|
this.fontScale = scale;
|
2012-04-12 00:29:44 +09:00
|
|
|
}
|
2016-03-29 04:49:22 +09:00
|
|
|
PageViewport.prototype = /** @lends PageViewport.prototype */ {
|
2014-05-06 04:09:47 +09:00
|
|
|
/**
|
|
|
|
* 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.
|
2016-03-29 04:49:22 +09:00
|
|
|
* @returns {PageViewport} Cloned viewport.
|
2014-05-06 04:09:47 +09:00
|
|
|
*/
|
2013-03-09 11:08:37 +09:00
|
|
|
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,
|
2013-03-21 17:04:44 +09:00
|
|
|
this.offsetX, this.offsetY, args.dontFlip);
|
2013-03-09 11:08:37 +09:00
|
|
|
},
|
2014-05-06 04:09:47 +09:00
|
|
|
/**
|
|
|
|
* 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}
|
|
|
|
*/
|
2012-04-12 02:18:29 +09:00
|
|
|
convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) {
|
2012-04-12 00:29:44 +09:00
|
|
|
return Util.applyTransform([x, y], this.transform);
|
|
|
|
},
|
2014-05-06 04:09:47 +09:00
|
|
|
/**
|
|
|
|
* 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}
|
|
|
|
*/
|
2012-04-12 02:18:29 +09:00
|
|
|
convertToViewportRectangle:
|
|
|
|
function PageViewport_convertToViewportRectangle(rect) {
|
2012-04-12 00:29:44 +09:00
|
|
|
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]];
|
|
|
|
},
|
2014-05-06 04:09:47 +09:00
|
|
|
/**
|
|
|
|
* 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}
|
|
|
|
*/
|
2012-04-12 02:18:29 +09:00
|
|
|
convertToPdfPoint: function PageViewport_convertToPdfPoint(x, y) {
|
2012-04-12 00:29:44 +09:00
|
|
|
return Util.applyInverseTransform([x, y], this.transform);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
return PageViewport;
|
|
|
|
})();
|
|
|
|
|
2011-10-25 08:55:23 +09:00
|
|
|
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) {
|
2014-02-28 08:23:56 +09:00
|
|
|
var i, n = str.length, strBuf = [];
|
2011-10-25 08:55:23 +09:00
|
|
|
if (str[0] === '\xFE' && str[1] === '\xFF') {
|
|
|
|
// UTF16BE BOM
|
2014-02-28 08:23:56 +09:00
|
|
|
for (i = 2; i < n; i += 2) {
|
|
|
|
strBuf.push(String.fromCharCode(
|
|
|
|
(str.charCodeAt(i) << 8) | str.charCodeAt(i + 1)));
|
|
|
|
}
|
2011-10-25 08:55:23 +09:00
|
|
|
} else {
|
|
|
|
for (i = 0; i < n; ++i) {
|
|
|
|
var code = PDFStringTranslateTable[str.charCodeAt(i)];
|
2014-02-28 08:23:56 +09:00
|
|
|
strBuf.push(code ? String.fromCharCode(code) : str.charAt(i));
|
2011-10-25 08:55:23 +09:00
|
|
|
}
|
|
|
|
}
|
2014-02-28 08:23:56 +09:00
|
|
|
return strBuf.join('');
|
2011-10-25 08:55:23 +09:00
|
|
|
}
|
|
|
|
|
2012-05-28 05:49:28 +09:00
|
|
|
function stringToUTF8String(str) {
|
|
|
|
return decodeURIComponent(escape(str));
|
|
|
|
}
|
|
|
|
|
2015-05-14 00:25:42 +09:00
|
|
|
function utf8StringToString(str) {
|
|
|
|
return unescape(encodeURIComponent(str));
|
|
|
|
}
|
|
|
|
|
2013-02-07 08:19:29 +09:00
|
|
|
function isEmptyObj(obj) {
|
|
|
|
for (var key in obj) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-10-25 08:55:23 +09:00
|
|
|
function isBool(v) {
|
2014-08-01 19:17:33 +09:00
|
|
|
return typeof v === 'boolean';
|
2011-10-25 08:55:23 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
function isInt(v) {
|
2014-06-02 19:16:15 +09:00
|
|
|
return typeof v === 'number' && ((v | 0) === v);
|
2011-10-25 08:55:23 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
function isNum(v) {
|
2014-06-02 19:16:15 +09:00
|
|
|
return typeof v === 'number';
|
2011-10-25 08:55:23 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
function isString(v) {
|
2014-06-02 19:16:15 +09:00
|
|
|
return typeof v === 'string';
|
2011-10-25 08:55:23 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
function isArray(v) {
|
|
|
|
return v instanceof Array;
|
|
|
|
}
|
|
|
|
|
|
|
|
function isArrayBuffer(v) {
|
2014-06-02 19:16:15 +09:00
|
|
|
return typeof v === 'object' && v !== null && v.byteLength !== undefined;
|
2011-10-25 08:55:23 +09:00
|
|
|
}
|
|
|
|
|
2016-06-06 16:11:33 +09:00
|
|
|
// Checks if ch is one of the following characters: SPACE, TAB, CR or LF.
|
|
|
|
function isSpace(ch) {
|
|
|
|
return (ch === 0x20 || ch === 0x09 || ch === 0x0D || ch === 0x0A);
|
|
|
|
}
|
|
|
|
|
2017-02-17 21:44:49 +09:00
|
|
|
function isNodeJS() {
|
|
|
|
// The if below protected by __pdfjsdev_webpack__ check from webpack parsing.
|
|
|
|
if (typeof __pdfjsdev_webpack__ === 'undefined') {
|
|
|
|
return typeof process === 'object' && process + '' === '[object process]';
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-04-29 03:51:53 +09:00
|
|
|
/**
|
|
|
|
* Promise Capability object.
|
|
|
|
*
|
|
|
|
* @typedef {Object} PromiseCapability
|
|
|
|
* @property {Promise} promise - A promise object.
|
2016-07-17 21:33:41 +09:00
|
|
|
* @property {function} resolve - Fulfills the promise.
|
2014-04-29 03:51:53 +09:00
|
|
|
* @property {function} reject - Rejects the promise.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates a promise capability object.
|
2016-03-29 04:49:22 +09:00
|
|
|
* @alias createPromiseCapability
|
2014-05-06 04:09:47 +09:00
|
|
|
*
|
2014-04-29 03:51:53 +09:00
|
|
|
* @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;
|
|
|
|
}
|
|
|
|
|
2012-02-22 02:52:09 +09:00
|
|
|
var StatTimer = (function StatTimerClosure() {
|
2012-01-12 09:48:51 +09:00
|
|
|
function rpad(str, pad, length) {
|
2014-03-03 21:21:57 +09:00
|
|
|
while (str.length < length) {
|
2012-01-12 09:48:51 +09:00
|
|
|
str += pad;
|
2014-03-03 21:21:57 +09:00
|
|
|
}
|
2012-01-12 09:48:51 +09:00
|
|
|
return str;
|
|
|
|
}
|
2012-02-22 02:52:09 +09:00
|
|
|
function StatTimer() {
|
2016-01-28 02:04:13 +09:00
|
|
|
this.started = Object.create(null);
|
2012-01-12 09:48:51 +09:00
|
|
|
this.times = [];
|
|
|
|
this.enabled = true;
|
|
|
|
}
|
2012-02-22 02:52:09 +09:00
|
|
|
StatTimer.prototype = {
|
2012-04-05 05:43:26 +09:00
|
|
|
time: function StatTimer_time(name) {
|
2014-03-03 21:21:57 +09:00
|
|
|
if (!this.enabled) {
|
2012-01-12 09:48:51 +09:00
|
|
|
return;
|
2014-03-03 21:21:57 +09:00
|
|
|
}
|
|
|
|
if (name in this.started) {
|
2013-08-01 03:17:36 +09:00
|
|
|
warn('Timer is already running for ' + name);
|
2014-03-03 21:21:57 +09:00
|
|
|
}
|
2012-01-12 09:48:51 +09:00
|
|
|
this.started[name] = Date.now();
|
|
|
|
},
|
2012-04-05 05:43:26 +09:00
|
|
|
timeEnd: function StatTimer_timeEnd(name) {
|
2014-03-03 21:21:57 +09:00
|
|
|
if (!this.enabled) {
|
2012-01-12 09:48:51 +09:00
|
|
|
return;
|
2014-03-03 21:21:57 +09:00
|
|
|
}
|
|
|
|
if (!(name in this.started)) {
|
2013-08-01 03:17:36 +09:00
|
|
|
warn('Timer has not been started for ' + name);
|
2014-03-03 21:21:57 +09:00
|
|
|
}
|
2012-01-12 09:48:51 +09:00
|
|
|
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];
|
|
|
|
},
|
2012-04-05 05:43:26 +09:00
|
|
|
toString: function StatTimer_toString() {
|
2014-04-08 04:05:17 +09:00
|
|
|
var i, ii;
|
2012-01-12 09:48:51 +09:00
|
|
|
var times = this.times;
|
|
|
|
var out = '';
|
|
|
|
// Find the longest name for padding purposes.
|
|
|
|
var longest = 0;
|
2014-04-08 04:05:17 +09:00
|
|
|
for (i = 0, ii = times.length; i < ii; ++i) {
|
2012-01-12 09:48:51 +09:00
|
|
|
var name = times[i]['name'];
|
2014-03-03 21:21:57 +09:00
|
|
|
if (name.length > longest) {
|
2012-01-12 09:48:51 +09:00
|
|
|
longest = name.length;
|
2014-03-03 21:21:57 +09:00
|
|
|
}
|
2012-01-12 09:48:51 +09:00
|
|
|
}
|
2014-04-08 04:05:17 +09:00
|
|
|
for (i = 0, ii = times.length; i < ii; ++i) {
|
2012-01-12 09:48:51 +09:00
|
|
|
var span = times[i];
|
|
|
|
var duration = span.end - span.start;
|
|
|
|
out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\n';
|
|
|
|
}
|
|
|
|
return out;
|
|
|
|
}
|
2012-02-09 09:38:43 +09:00
|
|
|
};
|
2012-02-22 02:52:09 +09:00
|
|
|
return StatTimer;
|
2012-01-12 09:48:51 +09:00
|
|
|
})();
|
2012-09-23 01:44:49 +09:00
|
|
|
|
2016-03-03 09:48:21 +09:00
|
|
|
var createBlob = function createBlob(data, contentType) {
|
2014-03-03 21:21:57 +09:00
|
|
|
if (typeof Blob !== 'undefined') {
|
2012-09-23 01:44:49 +09:00
|
|
|
return new Blob([data], { type: contentType });
|
2014-03-03 21:21:57 +09:00
|
|
|
}
|
2017-04-16 01:25:10 +09:00
|
|
|
throw new Error('The "Blob" constructor is not supported.');
|
2012-09-23 01:44:49 +09:00
|
|
|
};
|
2013-08-13 02:48:06 +09:00
|
|
|
|
2016-03-03 09:48:21 +09:00
|
|
|
var createObjectURL = (function createObjectURLClosure() {
|
2013-11-12 13:25:03 +09:00
|
|
|
// Blob/createObjectURL is not available, falling back to data schema.
|
|
|
|
var digits =
|
|
|
|
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
|
|
|
|
2017-04-16 01:25:10 +09:00
|
|
|
return function createObjectURL(data, contentType, forceDataSchema = false) {
|
2017-04-28 03:49:48 +09:00
|
|
|
if (!forceDataSchema && URL.createObjectURL) {
|
2016-03-03 09:48:21 +09:00
|
|
|
var blob = createBlob(data, contentType);
|
2014-01-11 07:30:41 +09:00
|
|
|
return URL.createObjectURL(blob);
|
|
|
|
}
|
|
|
|
|
2013-11-12 13:25:03 +09:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
})();
|
|
|
|
|
2015-10-28 00:07:20 +09:00
|
|
|
function MessageHandler(sourceName, targetName, comObj) {
|
|
|
|
this.sourceName = sourceName;
|
|
|
|
this.targetName = targetName;
|
2013-08-13 02:48:06 +09:00
|
|
|
this.comObj = comObj;
|
|
|
|
this.callbackIndex = 1;
|
2013-11-12 12:30:26 +09:00
|
|
|
this.postMessageTransfers = true;
|
2016-01-28 02:04:13 +09:00
|
|
|
var callbacksCapabilities = this.callbacksCapabilities = Object.create(null);
|
|
|
|
var ah = this.actionHandler = Object.create(null);
|
2013-08-13 02:48:06 +09:00
|
|
|
|
2017-05-03 23:39:54 +09:00
|
|
|
this._onComObjOnMessage = (event) => {
|
2013-08-13 02:48:06 +09:00
|
|
|
var data = event.data;
|
2015-10-28 00:07:20 +09:00
|
|
|
if (data.targetName !== this.sourceName) {
|
|
|
|
return;
|
|
|
|
}
|
2013-08-13 02:48:06 +09:00
|
|
|
if (data.isReply) {
|
|
|
|
var callbackId = data.callbackId;
|
2014-05-08 08:15:25 +09:00
|
|
|
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);
|
|
|
|
}
|
2013-08-13 02:48:06 +09:00
|
|
|
} else {
|
|
|
|
error('Cannot resolve callback ' + callbackId);
|
|
|
|
}
|
|
|
|
} else if (data.action in ah) {
|
|
|
|
var action = ah[data.action];
|
|
|
|
if (data.callbackId) {
|
2015-10-28 00:07:20 +09:00
|
|
|
var sourceName = this.sourceName;
|
|
|
|
var targetName = data.sourceName;
|
2014-05-08 08:15:25 +09:00
|
|
|
Promise.resolve().then(function () {
|
|
|
|
return action[0].call(action[1], data.data);
|
|
|
|
}).then(function (result) {
|
|
|
|
comObj.postMessage({
|
2017-04-25 23:07:59 +09:00
|
|
|
sourceName,
|
|
|
|
targetName,
|
2014-05-08 08:15:25 +09:00
|
|
|
isReply: true,
|
|
|
|
callbackId: data.callbackId,
|
|
|
|
data: result
|
|
|
|
});
|
|
|
|
}, function (reason) {
|
2015-08-09 04:41:33 +09:00
|
|
|
if (reason instanceof Error) {
|
|
|
|
// Serialize error to avoid "DataCloneError"
|
|
|
|
reason = reason + '';
|
|
|
|
}
|
2013-08-13 02:48:06 +09:00
|
|
|
comObj.postMessage({
|
2017-04-25 23:07:59 +09:00
|
|
|
sourceName,
|
|
|
|
targetName,
|
2013-08-13 02:48:06 +09:00
|
|
|
isReply: true,
|
|
|
|
callbackId: data.callbackId,
|
2014-05-08 08:15:25 +09:00
|
|
|
error: reason
|
2013-08-13 02:48:06 +09:00
|
|
|
});
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
action[0].call(action[1], data.data);
|
|
|
|
}
|
|
|
|
} else {
|
2014-05-08 08:15:25 +09:00
|
|
|
error('Unknown action from worker: ' + data.action);
|
2013-08-13 02:48:06 +09:00
|
|
|
}
|
2017-05-03 23:39:54 +09:00
|
|
|
};
|
2015-10-28 00:07:20 +09:00
|
|
|
comObj.addEventListener('message', this._onComObjOnMessage);
|
2013-08-13 02:48:06 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
MessageHandler.prototype = {
|
2017-04-25 23:07:59 +09:00
|
|
|
on(actionName, handler, scope) {
|
2013-08-13 02:48:06 +09:00
|
|
|
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.
|
2013-11-12 12:30:26 +09:00
|
|
|
* @param {Array} [transfers] Optional list of transfers/ArrayBuffers
|
2013-08-13 02:48:06 +09:00
|
|
|
*/
|
2017-04-25 23:07:59 +09:00
|
|
|
send(actionName, data, transfers) {
|
2013-08-13 02:48:06 +09:00
|
|
|
var message = {
|
2015-10-28 00:07:20 +09:00
|
|
|
sourceName: this.sourceName,
|
|
|
|
targetName: this.targetName,
|
2013-08-13 02:48:06 +09:00
|
|
|
action: actionName,
|
2017-04-25 23:07:59 +09:00
|
|
|
data,
|
2013-08-13 02:48:06 +09:00
|
|
|
};
|
2014-05-08 08:15:25 +09:00
|
|
|
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.
|
|
|
|
*/
|
2017-04-25 23:07:59 +09:00
|
|
|
sendWithPromise(actionName, data, transfers) {
|
2014-05-08 08:15:25 +09:00
|
|
|
var callbackId = this.callbackIndex++;
|
|
|
|
var message = {
|
2015-10-28 00:07:20 +09:00
|
|
|
sourceName: this.sourceName,
|
|
|
|
targetName: this.targetName,
|
2014-05-08 08:15:25 +09:00
|
|
|
action: actionName,
|
2017-04-25 23:07:59 +09:00
|
|
|
data,
|
|
|
|
callbackId,
|
2014-05-08 08:15:25 +09:00
|
|
|
};
|
|
|
|
var capability = createPromiseCapability();
|
|
|
|
this.callbacksCapabilities[callbackId] = capability;
|
|
|
|
try {
|
|
|
|
this.postMessage(message, transfers);
|
|
|
|
} catch (e) {
|
|
|
|
capability.reject(e);
|
2013-08-13 02:48:06 +09:00
|
|
|
}
|
2014-05-08 08:15:25 +09:00
|
|
|
return capability.promise;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Sends raw message to the comObj.
|
|
|
|
* @private
|
|
|
|
* @param message {Object} Raw message.
|
|
|
|
* @param transfers List of transfers/ArrayBuffers, or undefined.
|
|
|
|
*/
|
2017-04-25 23:07:59 +09:00
|
|
|
postMessage(message, transfers) {
|
2013-11-12 12:30:26 +09:00
|
|
|
if (transfers && this.postMessageTransfers) {
|
|
|
|
this.comObj.postMessage(message, transfers);
|
|
|
|
} else {
|
|
|
|
this.comObj.postMessage(message);
|
|
|
|
}
|
2015-10-28 00:07:20 +09:00
|
|
|
},
|
|
|
|
|
2017-04-25 23:07:59 +09:00
|
|
|
destroy() {
|
2015-10-28 00:07:20 +09:00
|
|
|
this.comObj.removeEventListener('message', this._onComObjOnMessage);
|
2013-08-13 02:48:06 +09:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-11-12 13:25:03 +09:00
|
|
|
function loadJpegStream(id, imageUrl, objs) {
|
2013-08-13 02:48:06 +09:00
|
|
|
var img = new Image();
|
|
|
|
img.onload = (function loadJpegStream_onloadClosure() {
|
|
|
|
objs.resolve(id, img);
|
|
|
|
});
|
2014-06-19 05:53:16 +09:00
|
|
|
img.onerror = (function loadJpegStream_onerrorClosure() {
|
|
|
|
objs.resolve(id, null);
|
|
|
|
warn('Error during JPEG image loading');
|
|
|
|
});
|
2013-11-12 13:25:03 +09:00
|
|
|
img.src = imageUrl;
|
2013-08-13 02:48:06 +09:00
|
|
|
}
|
2015-11-22 01:32:47 +09:00
|
|
|
|
|
|
|
exports.FONT_IDENTITY_MATRIX = FONT_IDENTITY_MATRIX;
|
|
|
|
exports.IDENTITY_MATRIX = IDENTITY_MATRIX;
|
|
|
|
exports.OPS = OPS;
|
2016-03-03 09:48:21 +09:00
|
|
|
exports.VERBOSITY_LEVELS = VERBOSITY_LEVELS;
|
2015-11-22 01:32:47 +09:00
|
|
|
exports.UNSUPPORTED_FEATURES = UNSUPPORTED_FEATURES;
|
|
|
|
exports.AnnotationBorderStyleType = AnnotationBorderStyleType;
|
2016-09-14 23:32:51 +09:00
|
|
|
exports.AnnotationFieldFlag = AnnotationFieldFlag;
|
2015-11-22 01:32:47 +09:00
|
|
|
exports.AnnotationFlag = AnnotationFlag;
|
|
|
|
exports.AnnotationType = AnnotationType;
|
|
|
|
exports.FontType = FontType;
|
|
|
|
exports.ImageKind = ImageKind;
|
2017-02-12 23:54:41 +09:00
|
|
|
exports.CMapCompressionType = CMapCompressionType;
|
2015-11-22 01:32:47 +09:00
|
|
|
exports.InvalidPDFException = InvalidPDFException;
|
|
|
|
exports.MessageHandler = MessageHandler;
|
|
|
|
exports.MissingDataException = MissingDataException;
|
|
|
|
exports.MissingPDFException = MissingPDFException;
|
|
|
|
exports.NotImplementedException = NotImplementedException;
|
2016-03-03 09:48:21 +09:00
|
|
|
exports.PageViewport = PageViewport;
|
2015-11-22 01:32:47 +09:00
|
|
|
exports.PasswordException = PasswordException;
|
|
|
|
exports.PasswordResponses = PasswordResponses;
|
|
|
|
exports.StatTimer = StatTimer;
|
|
|
|
exports.StreamType = StreamType;
|
|
|
|
exports.TextRenderingMode = TextRenderingMode;
|
|
|
|
exports.UnexpectedResponseException = UnexpectedResponseException;
|
|
|
|
exports.UnknownErrorException = UnknownErrorException;
|
|
|
|
exports.Util = Util;
|
|
|
|
exports.XRefParseException = XRefParseException;
|
2016-02-10 05:55:11 +09:00
|
|
|
exports.arrayByteLength = arrayByteLength;
|
|
|
|
exports.arraysToBytes = arraysToBytes;
|
2015-11-22 01:32:47 +09:00
|
|
|
exports.assert = assert;
|
|
|
|
exports.bytesToString = bytesToString;
|
2016-03-03 09:48:21 +09:00
|
|
|
exports.createBlob = createBlob;
|
2015-11-22 01:32:47 +09:00
|
|
|
exports.createPromiseCapability = createPromiseCapability;
|
2016-03-03 09:48:21 +09:00
|
|
|
exports.createObjectURL = createObjectURL;
|
2015-11-22 01:32:47 +09:00
|
|
|
exports.deprecated = deprecated;
|
|
|
|
exports.error = error;
|
2016-01-22 05:47:48 +09:00
|
|
|
exports.getLookupTableFactory = getLookupTableFactory;
|
2016-03-03 09:48:21 +09:00
|
|
|
exports.getVerbosityLevel = getVerbosityLevel;
|
|
|
|
exports.globalScope = globalScope;
|
2015-11-22 01:32:47 +09:00
|
|
|
exports.info = info;
|
|
|
|
exports.isArray = isArray;
|
|
|
|
exports.isArrayBuffer = isArrayBuffer;
|
|
|
|
exports.isBool = isBool;
|
|
|
|
exports.isEmptyObj = isEmptyObj;
|
|
|
|
exports.isInt = isInt;
|
|
|
|
exports.isNum = isNum;
|
|
|
|
exports.isString = isString;
|
2016-06-06 16:11:33 +09:00
|
|
|
exports.isSpace = isSpace;
|
2017-02-17 21:44:49 +09:00
|
|
|
exports.isNodeJS = isNodeJS;
|
2016-01-16 06:05:46 +09:00
|
|
|
exports.isSameOrigin = isSameOrigin;
|
2016-10-03 21:35:29 +09:00
|
|
|
exports.createValidAbsoluteUrl = createValidAbsoluteUrl;
|
2016-03-03 09:48:21 +09:00
|
|
|
exports.isLittleEndian = isLittleEndian;
|
2016-03-29 04:49:22 +09:00
|
|
|
exports.isEvalSupported = isEvalSupported;
|
2015-11-22 01:32:47 +09:00
|
|
|
exports.loadJpegStream = loadJpegStream;
|
|
|
|
exports.log2 = log2;
|
|
|
|
exports.readInt8 = readInt8;
|
|
|
|
exports.readUint16 = readUint16;
|
|
|
|
exports.readUint32 = readUint32;
|
2016-01-05 05:33:41 +09:00
|
|
|
exports.removeNullCharacters = removeNullCharacters;
|
2016-03-03 09:48:21 +09:00
|
|
|
exports.setVerbosityLevel = setVerbosityLevel;
|
2015-11-22 01:32:47 +09:00
|
|
|
exports.shadow = shadow;
|
|
|
|
exports.string32 = string32;
|
|
|
|
exports.stringToBytes = stringToBytes;
|
|
|
|
exports.stringToPDFString = stringToPDFString;
|
|
|
|
exports.stringToUTF8String = stringToUTF8String;
|
|
|
|
exports.utf8StringToString = utf8StringToString;
|
|
|
|
exports.warn = warn;
|
|
|
|
}));
|