2011-10-26 10:18:22 +09:00
|
|
|
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
|
|
|
|
|
|
|
'use strict';
|
|
|
|
|
2011-10-25 08:55:23 +09:00
|
|
|
function log(msg) {
|
|
|
|
if (console && console.log)
|
|
|
|
console.log(msg);
|
|
|
|
else if (print)
|
|
|
|
print(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
function warn(msg) {
|
|
|
|
if (verbosity >= WARNINGS)
|
|
|
|
log('Warning: ' + msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
function backtrace() {
|
|
|
|
try {
|
|
|
|
throw new Error();
|
|
|
|
} catch (e) {
|
2011-10-29 07:26:55 +09:00
|
|
|
return e.stack ? e.stack.split('\n').slice(2).join('\n') : '';
|
2011-10-25 08:55:23 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function error(msg) {
|
2011-10-29 07:26:55 +09:00
|
|
|
log('Error: ' + msg);
|
2011-10-25 08:55:23 +09:00
|
|
|
log(backtrace());
|
|
|
|
throw new Error(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
function TODO(what) {
|
|
|
|
if (verbosity >= TODOS)
|
|
|
|
log('TODO: ' + what);
|
|
|
|
}
|
|
|
|
|
|
|
|
function malformed(msg) {
|
|
|
|
error('Malformed PDF: ' + msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
function assert(cond, msg) {
|
|
|
|
if (!cond)
|
|
|
|
error(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
// In a well-formed PDF, |cond| holds. If it doesn't, subsequent
|
|
|
|
// behavior is undefined.
|
|
|
|
function assertWellFormed(cond, msg) {
|
|
|
|
if (!cond)
|
|
|
|
malformed(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
function shadow(obj, prop, value) {
|
|
|
|
Object.defineProperty(obj, prop, { value: value,
|
|
|
|
enumerable: true,
|
|
|
|
configurable: true,
|
|
|
|
writable: false });
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
function bytesToString(bytes) {
|
|
|
|
var str = '';
|
|
|
|
var length = bytes.length;
|
|
|
|
for (var n = 0; n < length; ++n)
|
|
|
|
str += String.fromCharCode(bytes[n]);
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
function stringToBytes(str) {
|
|
|
|
var length = str.length;
|
|
|
|
var bytes = new Uint8Array(length);
|
|
|
|
for (var n = 0; n < length; ++n)
|
|
|
|
bytes[n] = str.charCodeAt(n) & 0xFF;
|
|
|
|
return bytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
|
|
|
|
|
2011-12-09 07:18:43 +09:00
|
|
|
var Util = (function UtilClosure() {
|
|
|
|
function Util() {}
|
|
|
|
Util.makeCssRgb = function makergb(r, g, b) {
|
2011-10-25 08:55:23 +09:00
|
|
|
var ri = (255 * r) | 0, gi = (255 * g) | 0, bi = (255 * b) | 0;
|
|
|
|
return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
|
|
|
|
};
|
2011-12-09 07:18:43 +09:00
|
|
|
Util.makeCssCmyk = function makecmyk(c, m, y, k) {
|
2011-10-25 08:55:23 +09:00
|
|
|
c = (new DeviceCmykCS()).getRgb([c, m, y, k]);
|
|
|
|
var ri = (255 * c[0]) | 0, gi = (255 * c[1]) | 0, bi = (255 * c[2]) | 0;
|
|
|
|
return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
|
|
|
|
};
|
2011-12-09 07:18:43 +09:00
|
|
|
Util.applyTransform = function apply(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];
|
|
|
|
};
|
|
|
|
|
2011-12-09 07:18:43 +09:00
|
|
|
return Util;
|
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) {
|
|
|
|
var i, n = str.length, str2 = '';
|
|
|
|
if (str[0] === '\xFE' && str[1] === '\xFF') {
|
|
|
|
// UTF16BE BOM
|
|
|
|
for (i = 2; i < n; i += 2)
|
|
|
|
str2 += String.fromCharCode(
|
|
|
|
(str.charCodeAt(i) << 8) | str.charCodeAt(i + 1));
|
|
|
|
} else {
|
|
|
|
for (i = 0; i < n; ++i) {
|
|
|
|
var code = PDFStringTranslateTable[str.charCodeAt(i)];
|
|
|
|
str2 += code ? String.fromCharCode(code) : str.charAt(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return str2;
|
|
|
|
}
|
|
|
|
|
|
|
|
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 || v.cmd == cmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
function isDict(v, type) {
|
|
|
|
return v instanceof Dict && (!type || v.get('Type').name == type);
|
|
|
|
}
|
|
|
|
|
|
|
|
function isArray(v) {
|
|
|
|
return v instanceof Array;
|
|
|
|
}
|
|
|
|
|
|
|
|
function isStream(v) {
|
|
|
|
return typeof v == 'object' && v != null && ('getChar' in v);
|
|
|
|
}
|
|
|
|
|
|
|
|
function isArrayBuffer(v) {
|
|
|
|
return typeof v == 'object' && v != null && ('byteLength' in v);
|
|
|
|
}
|
|
|
|
|
|
|
|
function isRef(v) {
|
|
|
|
return v instanceof Ref;
|
|
|
|
}
|
|
|
|
|
|
|
|
function isPDFFunction(v) {
|
|
|
|
var fnDict;
|
|
|
|
if (typeof v != 'object')
|
|
|
|
return false;
|
|
|
|
else if (isDict(v))
|
|
|
|
fnDict = v;
|
|
|
|
else if (isStream(v))
|
|
|
|
fnDict = v.dict;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
return fnDict.has('FunctionType');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 'Promise' object.
|
|
|
|
* Each object that is stored in PDFObjects is based on a Promise object that
|
|
|
|
* contains the status of the object and the data. There migth be situations,
|
|
|
|
* where a function want to use the value of an object, but it isn't ready at
|
|
|
|
* that time. To get a notification, once the object is ready to be used, s.o.
|
|
|
|
* can add a callback using the `then` method on the promise that then calls
|
|
|
|
* the callback once the object gets resolved.
|
|
|
|
* A promise can get resolved only once and only once the data of the promise
|
|
|
|
* can be set. If any of these happens twice or the data is required before
|
|
|
|
* it was set, an exception is throw.
|
|
|
|
*/
|
2011-12-09 07:18:43 +09:00
|
|
|
var Promise = (function PromiseClosure() {
|
2011-10-25 08:55:23 +09:00
|
|
|
var EMPTY_PROMISE = {};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* If `data` is passed in this constructor, the promise is created resolved.
|
|
|
|
* If there isn't data, it isn't resolved at the beginning.
|
|
|
|
*/
|
|
|
|
function Promise(name, data) {
|
|
|
|
this.name = name;
|
|
|
|
// If you build a promise and pass in some data it's already resolved.
|
|
|
|
if (data != null) {
|
|
|
|
this.isResolved = true;
|
|
|
|
this._data = data;
|
|
|
|
this.hasData = true;
|
|
|
|
} else {
|
|
|
|
this.isResolved = false;
|
|
|
|
this._data = EMPTY_PROMISE;
|
|
|
|
}
|
|
|
|
this.callbacks = [];
|
|
|
|
};
|
2011-12-12 09:56:45 +09:00
|
|
|
/**
|
|
|
|
* Builds a promise that is resolved when all the passed in promises are
|
|
|
|
* resolved.
|
|
|
|
* @param Array promises
|
|
|
|
* @return Promise
|
|
|
|
*/
|
|
|
|
Promise.all = function(promises) {
|
|
|
|
var deferred = new Promise();
|
|
|
|
var unresolved = promises.length;
|
|
|
|
var results = [];
|
|
|
|
if (unresolved === 0) {
|
|
|
|
deferred.resolve(results);
|
|
|
|
return deferred;
|
|
|
|
}
|
|
|
|
for (var i = 0; i < unresolved; ++i) {
|
|
|
|
var promise = promises[i];
|
|
|
|
promise.then((function(i) {
|
|
|
|
return function(value) {
|
|
|
|
results[i] = value;
|
|
|
|
unresolved--;
|
|
|
|
if (unresolved === 0)
|
|
|
|
deferred.resolve(results);
|
|
|
|
};
|
|
|
|
})(i));
|
|
|
|
}
|
|
|
|
return deferred;
|
|
|
|
};
|
2011-10-25 08:55:23 +09:00
|
|
|
Promise.prototype = {
|
|
|
|
hasData: false,
|
|
|
|
|
2011-10-28 20:34:56 +09:00
|
|
|
set data(value) {
|
|
|
|
if (value === undefined) {
|
2011-10-25 08:55:23 +09:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (this._data !== EMPTY_PROMISE) {
|
|
|
|
throw 'Promise ' + this.name +
|
|
|
|
': Cannot set the data of a promise twice';
|
|
|
|
}
|
2011-10-28 20:34:56 +09:00
|
|
|
this._data = value;
|
2011-10-25 08:55:23 +09:00
|
|
|
this.hasData = true;
|
|
|
|
|
|
|
|
if (this.onDataCallback) {
|
2011-10-28 20:34:56 +09:00
|
|
|
this.onDataCallback(value);
|
2011-10-25 08:55:23 +09:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
get data() {
|
|
|
|
if (this._data === EMPTY_PROMISE) {
|
|
|
|
throw 'Promise ' + this.name + ': Cannot get data that isn\'t set';
|
|
|
|
}
|
|
|
|
return this._data;
|
|
|
|
},
|
|
|
|
|
2011-10-29 19:20:48 +09:00
|
|
|
onData: function promiseOnData(callback) {
|
2011-10-25 08:55:23 +09:00
|
|
|
if (this._data !== EMPTY_PROMISE) {
|
|
|
|
callback(this._data);
|
|
|
|
} else {
|
|
|
|
this.onDataCallback = callback;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2011-10-29 19:20:48 +09:00
|
|
|
resolve: function promiseResolve(data) {
|
2011-10-25 08:55:23 +09:00
|
|
|
if (this.isResolved) {
|
|
|
|
throw 'A Promise can be resolved only once ' + this.name;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.isResolved = true;
|
|
|
|
this.data = data;
|
|
|
|
var callbacks = this.callbacks;
|
|
|
|
|
2011-11-03 04:11:33 +09:00
|
|
|
for (var i = 0, ii = callbacks.length; i < ii; i++) {
|
2011-10-25 08:55:23 +09:00
|
|
|
callbacks[i].call(null, data);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2011-10-29 19:20:48 +09:00
|
|
|
then: function promiseThen(callback) {
|
2011-10-25 08:55:23 +09:00
|
|
|
if (!callback) {
|
|
|
|
throw 'Requiring callback' + this.name;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the promise is already resolved, call the callback directly.
|
|
|
|
if (this.isResolved) {
|
|
|
|
var data = this.data;
|
|
|
|
callback.call(null, data);
|
|
|
|
} else {
|
|
|
|
this.callbacks.push(callback);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2011-10-28 03:51:10 +09:00
|
|
|
|
2011-10-25 08:55:23 +09:00
|
|
|
return Promise;
|
|
|
|
})();
|
2011-10-28 03:51:10 +09:00
|
|
|
|