summaryrefslogtreecommitdiff
path: root/js/pdf.js
diff options
context:
space:
mode:
authorschneefux <schneefux+commit@schneefux.xyz>2014-06-10 15:24:45 +0200
committerschneefux <schneefux+commit@schneefux.xyz>2016-08-15 20:02:41 +0200
commit83b02062f91d616a01a5daa035fbca7d097adc05 (patch)
tree63008394cba75f43404066d25a63dd392585a227 /js/pdf.js
parent46cf469a0dfa9088aaf059b2d051ecf9951beea7 (diff)
downloadwvs-vplan-83b02062f91d616a01a5daa035fbca7d097adc05.tar.gz
wvs-vplan-83b02062f91d616a01a5daa035fbca7d097adc05.zip
aktualisiere PDF.js
Diffstat (limited to 'js/pdf.js')
-rw-r--r--js/pdf.js3914
1 files changed, 1418 insertions, 2496 deletions
diff --git a/js/pdf.js b/js/pdf.js
index 421c29a..6d7416f 100644
--- a/js/pdf.js
+++ b/js/pdf.js
@@ -21,8 +21,8 @@ if (typeof PDFJS === 'undefined') {
(typeof window !== 'undefined' ? window : this).PDFJS = {};
}
-PDFJS.version = '0.8.1239';
-PDFJS.build = '1a6e103';
+PDFJS.version = '1.0.276';
+PDFJS.build = 'a09aecb';
(function pdfjsWrapper() {
// Use strict in our context only - users might not want it
@@ -181,7 +181,9 @@ var OPS = PDFJS.OPS = {
paintInlineImageXObject: 86,
paintInlineImageXObjectGroup: 87,
paintImageXObjectRepeat: 88,
- paintImageMaskXObjectRepeat: 89
+ paintImageMaskXObjectRepeat: 89,
+ paintSolidColorImageMask: 90,
+ constructPath: 91
};
// A notice for devs. These are good for things that are helpful to devs, such
@@ -266,9 +268,10 @@ function combineUrl(baseUrl, url) {
if (/^[a-z][a-z0-9+\-.]*:/i.test(url)) {
return url;
}
+ var i;
if (url.charAt(0) == '/') {
// absolute path
- var i = baseUrl.indexOf('://');
+ i = baseUrl.indexOf('://');
if (url.charAt(1) === '/') {
++i;
} else {
@@ -277,7 +280,7 @@ function combineUrl(baseUrl, url) {
return baseUrl.substring(0, i) + url;
} else {
// relative path
- var pathLength = baseUrl.length, i;
+ var pathLength = baseUrl.length;
i = baseUrl.lastIndexOf('#');
pathLength = i >= 0 ? i : pathLength;
i = baseUrl.lastIndexOf('?', pathLength);
@@ -311,14 +314,6 @@ function isValidUrl(url, allowRelative) {
}
PDFJS.isValidUrl = isValidUrl;
-// In a well-formed PDF, |cond| holds. If it doesn't, subsequent
-// behavior is undefined.
-function assertWellFormed(cond, msg) {
- if (!cond) {
- error(msg);
- }
-}
-
function shadow(obj, prop, value) {
Object.defineProperty(obj, prop, { value: value,
enumerable: true,
@@ -422,23 +417,137 @@ var XRefParseException = (function XRefParseExceptionClosure() {
function bytesToString(bytes) {
- var strBuf = [];
var length = bytes.length;
- for (var n = 0; n < length; ++n) {
- strBuf.push(String.fromCharCode(bytes[n]));
+ 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 n = 0; n < length; ++n) {
- bytes[n] = str.charCodeAt(n) & 0xFF;
+ 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());
+ }
+});
+
+ // 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;
+})();
+
var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
var Util = PDFJS.Util = (function UtilClosure() {
@@ -448,11 +557,6 @@ var Util = PDFJS.Util = (function UtilClosure() {
return 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')';
};
- Util.makeCssCmyk = function Util_makeCssCmyk(cmyk) {
- var rgb = ColorSpace.singletons.cmyk.getRgb(cmyk, 0);
- return Util.makeCssRgb(rgb);
- };
-
// Concatenates two transformation matrices together and returns the result.
Util.transform = function Util_transform(m1, m2) {
return [
@@ -652,7 +756,22 @@ var Util = PDFJS.Util = (function UtilClosure() {
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;
@@ -716,7 +835,14 @@ var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
this.height = height;
this.fontScale = scale;
}
- PageViewport.prototype = {
+ 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;
@@ -724,15 +850,41 @@ var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
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);
}
@@ -837,40 +989,36 @@ 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 Capability object.
+ *
+ * @typedef {Object} PromiseCapability
+ * @property {Promise} promise - A promise object.
+ * @property {function} resolve - Fullfills the promise.
+ * @property {function} reject - Rejects the promise.
+ */
/**
- * Legacy support for PDFJS Promise implementation.
- * TODO remove eventually
+ * Creates a promise capability object.
+ * @alias PDFJS.createPromiseCapability
+ *
+ * @return {PromiseCapability} A capability object contains:
+ * - a Promise, resolve and reject methods.
*/
-var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
- return function LegacyPromise() {
- var resolve, reject;
- var promise = new Promise(function (resolve_, reject_) {
- resolve = resolve_;
- reject = reject_;
- });
- promise.resolve = resolve;
- promise.reject = reject;
- return promise;
- };
-})();
+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 implment the
+ * 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.
@@ -905,8 +1053,20 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
};
}
if (typeof globalScope.Promise.resolve !== 'function') {
- globalScope.Promise.resolve = function (x) {
- return new globalScope.Promise(function (resolve) { resolve(x); });
+ 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;
@@ -1031,7 +1191,11 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
function Promise(resolver) {
this._status = STATUS_PENDING;
this._handlers = [];
- resolver.call(this, this._resolve.bind(this), this._reject.bind(this));
+ 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
@@ -1083,18 +1247,28 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
/**
* Checks if the value is likely a promise (has a 'then' function).
- * @return {boolean} true if x is thenable
+ * @return {boolean} true if value is thenable
*/
Promise.isPromise = function Promise_isPromise(value) {
return value && typeof value.then === 'function';
};
+
/**
* Creates resolved promise
- * @param x resolve value
+ * @param value resolve value
* @returns {Promise}
*/
- Promise.resolve = function Promise_resolve(x) {
- return new Promise(function (resolve) { resolve(x); });
+ 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 = {
@@ -1148,6 +1322,10 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
});
HandlerManager.scheduleHandlers(this);
return nextPromise;
+ },
+
+ catch: function Promise_catch(onReject) {
+ return this.then(undefined, onReject);
}
};
@@ -1192,17 +1370,18 @@ var StatTimer = (function StatTimerClosure() {
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 (var i = 0, ii = times.length; i < ii; ++i) {
+ for (i = 0, ii = times.length; i < ii; ++i) {
var name = times[i]['name'];
if (name.length > longest) {
longest = name.length;
}
}
- for (var i = 0, ii = times.length; i < ii; ++i) {
+ 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';
@@ -1254,7 +1433,7 @@ function MessageHandler(name, comObj) {
this.comObj = comObj;
this.callbackIndex = 1;
this.postMessageTransfers = true;
- var callbacks = this.callbacks = {};
+ var callbacksCapabilities = this.callbacksCapabilities = {};
var ah = this.actionHandler = {};
ah['console_log'] = [function ahConsoleLog(data) {
@@ -1271,35 +1450,40 @@ function MessageHandler(name, comObj) {
var data = event.data;
if (data.isReply) {
var callbackId = data.callbackId;
- if (data.callbackId in callbacks) {
- var callback = callbacks[callbackId];
- delete callbacks[callbackId];
- callback(data.data);
+ 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) {
- var deferred = {};
- var promise = new Promise(function (resolve, reject) {
- deferred.resolve = resolve;
- deferred.reject = reject;
- });
- deferred.promise = promise;
- promise.then(function(resolvedData) {
+ 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,
- data: resolvedData
+ error: reason
});
});
- action[0].call(action[1], data.data, deferred);
} else {
action[0].call(action[1], data.data);
}
} else {
- error('Unkown action from worker: ' + data.action);
+ error('Unknown action from worker: ' + data.action);
}
};
}
@@ -1316,19 +1500,47 @@ MessageHandler.prototype = {
* 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 {function} [callback] Optional callback that will handle a reply.
* @param {Array} [transfers] Optional list of transfers/ArrayBuffers
*/
- send: function messageHandlerSend(actionName, data, callback, transfers) {
+ send: function messageHandlerSend(actionName, data, transfers) {
var message = {
action: actionName,
data: data
};
- if (callback) {
- var callbackId = this.callbackIndex++;
- this.callbacks[callbackId] = callback;
- message.callbackId = callbackId;
+ 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 {
@@ -1346,1635 +1558,7 @@ function loadJpegStream(id, imageUrl, objs) {
}
-var ColorSpace = (function ColorSpaceClosure() {
- // Constructor should define this.numComps, this.defaultColor, this.name
- function ColorSpace() {
- error('should not call ColorSpace constructor');
- }
-
- ColorSpace.prototype = {
- /**
- * Converts the color value to the RGB color. The color components are
- * located in the src array starting from the srcOffset. Returns the array
- * of the rgb components, each value ranging from [0,255].
- */
- getRgb: function ColorSpace_getRgb(src, srcOffset) {
- var rgb = new Uint8Array(3);
- this.getRgbItem(src, srcOffset, rgb, 0);
- return rgb;
- },
- /**
- * Converts the color value to the RGB color, similar to the getRgb method.
- * The result placed into the dest array starting from the destOffset.
- */
- getRgbItem: function ColorSpace_getRgbItem(src, srcOffset,
- dest, destOffset) {
- error('Should not call ColorSpace.getRgbItem');
- },
- /**
- * Converts the specified number of the color values to the RGB colors.
- * The colors are located in the src array starting from the srcOffset.
- * The result is placed into the dest array starting from the destOffset.
- * The src array items shall be in [0,2^bits) range, the dest array items
- * will be in [0,255] range. alpha01 indicates how many alpha components
- * there are in the dest array; it will be either 0 (RGB array) or 1 (RGBA
- * array).
- */
- getRgbBuffer: function ColorSpace_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- error('Should not call ColorSpace.getRgbBuffer');
- },
- /**
- * Determines the number of bytes required to store the result of the
- * conversion done by the getRgbBuffer method. As in getRgbBuffer,
- * |alpha01| is either 0 (RGB output) or 1 (RGBA output).
- */
- getOutputLength: function ColorSpace_getOutputLength(inputLength,
- alpha01) {
- error('Should not call ColorSpace.getOutputLength');
- },
- /**
- * Returns true if source data will be equal the result/output data.
- */
- isPassthrough: function ColorSpace_isPassthrough(bits) {
- return false;
- },
- /**
- * Fills in the RGB colors in the destination buffer. alpha01 indicates
- * how many alpha components there are in the dest array; it will be either
- * 0 (RGB array) or 1 (RGBA array).
- */
- fillRgb: function ColorSpace_fillRgb(dest, originalWidth,
- originalHeight, width, height,
- actualHeight, bpc, comps, alpha01) {
- var count = originalWidth * originalHeight;
- var rgbBuf = null;
- var numComponentColors = 1 << bpc;
- var needsResizing = originalHeight != height || originalWidth != width;
-
- if (this.isPassthrough(bpc)) {
- rgbBuf = comps;
-
- } else if (this.numComps === 1 && count > numComponentColors &&
- this.name !== 'DeviceGray' && this.name !== 'DeviceRGB') {
- // Optimization: create a color map when there is just one component and
- // we are converting more colors than the size of the color map. We
- // don't build the map if the colorspace is gray or rgb since those
- // methods are faster than building a map. This mainly offers big speed
- // ups for indexed and alternate colorspaces.
- //
- // TODO it may be worth while to cache the color map. While running
- // testing I never hit a cache so I will leave that out for now (perhaps
- // we are reparsing colorspaces too much?).
- var allColors = bpc <= 8 ? new Uint8Array(numComponentColors) :
- new Uint16Array(numComponentColors);
- for (var i = 0; i < numComponentColors; i++) {
- allColors[i] = i;
- }
- var colorMap = new Uint8Array(numComponentColors * 3);
- this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bpc,
- /* alpha01 = */ 0);
-
- if (!needsResizing) {
- // Fill in the RGB values directly into |dest|.
- var destPos = 0;
- for (var i = 0; i < count; ++i) {
- var key = comps[i] * 3;
- dest[destPos++] = colorMap[key];
- dest[destPos++] = colorMap[key + 1];
- dest[destPos++] = colorMap[key + 2];
- destPos += alpha01;
- }
- } else {
- rgbBuf = new Uint8Array(count * 3);
- var rgbPos = 0;
- for (var i = 0; i < count; ++i) {
- var key = comps[i] * 3;
- rgbBuf[rgbPos++] = colorMap[key];
- rgbBuf[rgbPos++] = colorMap[key + 1];
- rgbBuf[rgbPos++] = colorMap[key + 2];
- }
- }
- } else {
- if (!needsResizing) {
- // Fill in the RGB values directly into |dest|.
- this.getRgbBuffer(comps, 0, width * actualHeight, dest, 0, bpc,
- alpha01);
- } else {
- rgbBuf = new Uint8Array(count * 3);
- this.getRgbBuffer(comps, 0, count, rgbBuf, 0, bpc,
- /* alpha01 = */ 0);
- }
- }
-
- if (rgbBuf) {
- if (needsResizing) {
- rgbBuf = PDFImage.resize(rgbBuf, bpc, 3, originalWidth,
- originalHeight, width, height);
- }
- var rgbPos = 0;
- var destPos = 0;
- for (var i = 0, ii = width * actualHeight; i < ii; i++) {
- dest[destPos++] = rgbBuf[rgbPos++];
- dest[destPos++] = rgbBuf[rgbPos++];
- dest[destPos++] = rgbBuf[rgbPos++];
- destPos += alpha01;
- }
- }
- },
- /**
- * True if the colorspace has components in the default range of [0, 1].
- * This should be true for all colorspaces except for lab color spaces
- * which are [0,100], [-128, 127], [-128, 127].
- */
- usesZeroToOneRange: true
- };
-
- ColorSpace.parse = function ColorSpace_parse(cs, xref, res) {
- var IR = ColorSpace.parseToIR(cs, xref, res);
- if (IR instanceof AlternateCS) {
- return IR;
- }
- return ColorSpace.fromIR(IR);
- };
-
- ColorSpace.fromIR = function ColorSpace_fromIR(IR) {
- var name = isArray(IR) ? IR[0] : IR;
-
- switch (name) {
- case 'DeviceGrayCS':
- return this.singletons.gray;
- case 'DeviceRgbCS':
- return this.singletons.rgb;
- case 'DeviceCmykCS':
- return this.singletons.cmyk;
- case 'CalGrayCS':
- var whitePoint = IR[1].WhitePoint;
- var blackPoint = IR[1].BlackPoint;
- var gamma = IR[1].Gamma;
- return new CalGrayCS(whitePoint, blackPoint, gamma);
- case 'PatternCS':
- var basePatternCS = IR[1];
- if (basePatternCS) {
- basePatternCS = ColorSpace.fromIR(basePatternCS);
- }
- return new PatternCS(basePatternCS);
- case 'IndexedCS':
- var baseIndexedCS = IR[1];
- var hiVal = IR[2];
- var lookup = IR[3];
- return new IndexedCS(ColorSpace.fromIR(baseIndexedCS), hiVal, lookup);
- case 'AlternateCS':
- var numComps = IR[1];
- var alt = IR[2];
- var tintFnIR = IR[3];
-
- return new AlternateCS(numComps, ColorSpace.fromIR(alt),
- PDFFunction.fromIR(tintFnIR));
- case 'LabCS':
- var whitePoint = IR[1].WhitePoint;
- var blackPoint = IR[1].BlackPoint;
- var range = IR[1].Range;
- return new LabCS(whitePoint, blackPoint, range);
- default:
- error('Unkown name ' + name);
- }
- return null;
- };
-
- ColorSpace.parseToIR = function ColorSpace_parseToIR(cs, xref, res) {
- if (isName(cs)) {
- var colorSpaces = res.get('ColorSpace');
- if (isDict(colorSpaces)) {
- var refcs = colorSpaces.get(cs.name);
- if (refcs) {
- cs = refcs;
- }
- }
- }
-
- cs = xref.fetchIfRef(cs);
- var mode;
-
- if (isName(cs)) {
- mode = cs.name;
- this.mode = mode;
-
- switch (mode) {
- case 'DeviceGray':
- case 'G':
- return 'DeviceGrayCS';
- case 'DeviceRGB':
- case 'RGB':
- return 'DeviceRgbCS';
- case 'DeviceCMYK':
- case 'CMYK':
- return 'DeviceCmykCS';
- case 'Pattern':
- return ['PatternCS', null];
- default:
- error('unrecognized colorspace ' + mode);
- }
- } else if (isArray(cs)) {
- mode = cs[0].name;
- this.mode = mode;
-
- switch (mode) {
- case 'DeviceGray':
- case 'G':
- return 'DeviceGrayCS';
- case 'DeviceRGB':
- case 'RGB':
- return 'DeviceRgbCS';
- case 'DeviceCMYK':
- case 'CMYK':
- return 'DeviceCmykCS';
- case 'CalGray':
- var params = cs[1].getAll();
- return ['CalGrayCS', params];
- case 'CalRGB':
- return 'DeviceRgbCS';
- case 'ICCBased':
- var stream = xref.fetchIfRef(cs[1]);
- var dict = stream.dict;
- var numComps = dict.get('N');
- if (numComps == 1) {
- return 'DeviceGrayCS';
- } else if (numComps == 3) {
- return 'DeviceRgbCS';
- } else if (numComps == 4) {
- return 'DeviceCmykCS';
- }
- break;
- case 'Pattern':
- var basePatternCS = cs[1];
- if (basePatternCS) {
- basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res);
- }
- return ['PatternCS', basePatternCS];
- case 'Indexed':
- case 'I':
- var baseIndexedCS = ColorSpace.parseToIR(cs[1], xref, res);
- var hiVal = cs[2] + 1;
- var lookup = xref.fetchIfRef(cs[3]);
- if (isStream(lookup)) {
- lookup = lookup.getBytes();
- }
- return ['IndexedCS', baseIndexedCS, hiVal, lookup];
- case 'Separation':
- case 'DeviceN':
- var name = cs[1];
- var numComps = 1;
- if (isName(name)) {
- numComps = 1;
- } else if (isArray(name)) {
- numComps = name.length;
- }
- var alt = ColorSpace.parseToIR(cs[2], xref, res);
- var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3]));
- return ['AlternateCS', numComps, alt, tintFnIR];
- case 'Lab':
- var params = cs[1].getAll();
- return ['LabCS', params];
- default:
- error('unimplemented color space object "' + mode + '"');
- }
- } else {
- error('unrecognized color space object: "' + cs + '"');
- }
- return null;
- };
- /**
- * Checks if a decode map matches the default decode map for a color space.
- * This handles the general decode maps where there are two values per
- * component. e.g. [0, 1, 0, 1, 0, 1] for a RGB color.
- * This does not handle Lab, Indexed, or Pattern decode maps since they are
- * slightly different.
- * @param {Array} decode Decode map (usually from an image).
- * @param {Number} n Number of components the color space has.
- */
- ColorSpace.isDefaultDecode = function ColorSpace_isDefaultDecode(decode, n) {
- if (!decode) {
- return true;
- }
-
- if (n * 2 !== decode.length) {
- warn('The decode map is not the correct length');
- return true;
- }
- for (var i = 0, ii = decode.length; i < ii; i += 2) {
- if (decode[i] !== 0 || decode[i + 1] != 1) {
- return false;
- }
- }
- return true;
- };
-
- ColorSpace.singletons = {
- get gray() {
- return shadow(this, 'gray', new DeviceGrayCS());
- },
- get rgb() {
- return shadow(this, 'rgb', new DeviceRgbCS());
- },
- get cmyk() {
- return shadow(this, 'cmyk', new DeviceCmykCS());
- }
- };
-
- return ColorSpace;
-})();
-
-/**
- * Alternate color space handles both Separation and DeviceN color spaces. A
- * Separation color space is actually just a DeviceN with one color component.
- * Both color spaces use a tinting function to convert colors to a base color
- * space.
- */
-var AlternateCS = (function AlternateCSClosure() {
- function AlternateCS(numComps, base, tintFn) {
- this.name = 'Alternate';
- this.numComps = numComps;
- this.defaultColor = new Float32Array(numComps);
- for (var i = 0; i < numComps; ++i) {
- this.defaultColor[i] = 1;
- }
- this.base = base;
- this.tintFn = tintFn;
- }
-
- AlternateCS.prototype = {
- getRgb: ColorSpace.prototype.getRgb,
- getRgbItem: function AlternateCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- var baseNumComps = this.base.numComps;
- var input = 'subarray' in src ?
- src.subarray(srcOffset, srcOffset + this.numComps) :
- Array.prototype.slice.call(src, srcOffset, srcOffset + this.numComps);
- var tinted = this.tintFn(input);
- this.base.getRgbItem(tinted, 0, dest, destOffset);
- },
- getRgbBuffer: function AlternateCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- var tintFn = this.tintFn;
- var base = this.base;
- var scale = 1 / ((1 << bits) - 1);
- var baseNumComps = base.numComps;
- var usesZeroToOneRange = base.usesZeroToOneRange;
- var isPassthrough = (base.isPassthrough(8) || !usesZeroToOneRange) &&
- alpha01 === 0;
- var pos = isPassthrough ? destOffset : 0;
- var baseBuf = isPassthrough ? dest : new Uint8Array(baseNumComps * count);
- var numComps = this.numComps;
-
- var scaled = new Float32Array(numComps);
- for (var i = 0; i < count; i++) {
- for (var j = 0; j < numComps; j++) {
- scaled[j] = src[srcOffset++] * scale;
- }
- var tinted = tintFn(scaled);
- if (usesZeroToOneRange) {
- for (var j = 0; j < baseNumComps; j++) {
- baseBuf[pos++] = tinted[j] * 255;
- }
- } else {
- base.getRgbItem(tinted, 0, baseBuf, pos);
- pos += baseNumComps;
- }
- }
- if (!isPassthrough) {
- base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8, alpha01);
- }
- },
- getOutputLength: function AlternateCS_getOutputLength(inputLength,
- alpha01) {
- return this.base.getOutputLength(inputLength *
- this.base.numComps / this.numComps,
- alpha01);
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- fillRgb: ColorSpace.prototype.fillRgb,
- isDefaultDecode: function AlternateCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
-
- return AlternateCS;
-})();
-
-var PatternCS = (function PatternCSClosure() {
- function PatternCS(baseCS) {
- this.name = 'Pattern';
- this.base = baseCS;
- }
- PatternCS.prototype = {};
-
- return PatternCS;
-})();
-
-var IndexedCS = (function IndexedCSClosure() {
- function IndexedCS(base, highVal, lookup) {
- this.name = 'Indexed';
- this.numComps = 1;
- this.defaultColor = new Uint8Array([0]);
- this.base = base;
- this.highVal = highVal;
-
- var baseNumComps = base.numComps;
- var length = baseNumComps * highVal;
- var lookupArray;
-
- if (isStream(lookup)) {
- lookupArray = new Uint8Array(length);
- var bytes = lookup.getBytes(length);
- lookupArray.set(bytes);
- } else if (isString(lookup)) {
- lookupArray = new Uint8Array(length);
- for (var i = 0; i < length; ++i) {
- lookupArray[i] = lookup.charCodeAt(i);
- }
- } else if (lookup instanceof Uint8Array || lookup instanceof Array) {
- lookupArray = lookup;
- } else {
- error('Unrecognized lookup table: ' + lookup);
- }
- this.lookup = lookupArray;
- }
-
- IndexedCS.prototype = {
- getRgb: ColorSpace.prototype.getRgb,
- getRgbItem: function IndexedCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- var numComps = this.base.numComps;
- var start = src[srcOffset] * numComps;
- this.base.getRgbItem(this.lookup, start, dest, destOffset);
- },
- getRgbBuffer: function IndexedCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- var base = this.base;
- var numComps = base.numComps;
- var outputDelta = base.getOutputLength(numComps, alpha01);
- var lookup = this.lookup;
-
- for (var i = 0; i < count; ++i) {
- var lookupPos = src[srcOffset++] * numComps;
- base.getRgbBuffer(lookup, lookupPos, 1, dest, destOffset, 8, alpha01);
- destOffset += outputDelta;
- }
- },
- getOutputLength: function IndexedCS_getOutputLength(inputLength, alpha01) {
- return this.base.getOutputLength(inputLength * this.base.numComps,
- alpha01);
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- fillRgb: ColorSpace.prototype.fillRgb,
- isDefaultDecode: function IndexedCS_isDefaultDecode(decodeMap) {
- // indexed color maps shouldn't be changed
- return true;
- },
- usesZeroToOneRange: true
- };
- return IndexedCS;
-})();
-
-var DeviceGrayCS = (function DeviceGrayCSClosure() {
- function DeviceGrayCS() {
- this.name = 'DeviceGray';
- this.numComps = 1;
- this.defaultColor = new Float32Array([0]);
- }
-
- DeviceGrayCS.prototype = {
- getRgb: ColorSpace.prototype.getRgb,
- getRgbItem: function DeviceGrayCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- var c = (src[srcOffset] * 255) | 0;
- c = c < 0 ? 0 : c > 255 ? 255 : c;
- dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c;
- },
- getRgbBuffer: function DeviceGrayCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- var scale = 255 / ((1 << bits) - 1);
- var j = srcOffset, q = destOffset;
- for (var i = 0; i < count; ++i) {
- var c = (scale * src[j++]) | 0;
- dest[q++] = c;
- dest[q++] = c;
- dest[q++] = c;
- q += alpha01;
- }
- },
- getOutputLength: function DeviceGrayCS_getOutputLength(inputLength,
- alpha01) {
- return inputLength * (3 + alpha01);
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- fillRgb: ColorSpace.prototype.fillRgb,
- isDefaultDecode: function DeviceGrayCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
- return DeviceGrayCS;
-})();
-
-var DeviceRgbCS = (function DeviceRgbCSClosure() {
- function DeviceRgbCS() {
- this.name = 'DeviceRGB';
- this.numComps = 3;
- this.defaultColor = new Float32Array([0, 0, 0]);
- }
- DeviceRgbCS.prototype = {
- getRgb: ColorSpace.prototype.getRgb,
- getRgbItem: function DeviceRgbCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- var r = (src[srcOffset] * 255) | 0;
- var g = (src[srcOffset + 1] * 255) | 0;
- var b = (src[srcOffset + 2] * 255) | 0;
- dest[destOffset] = r < 0 ? 0 : r > 255 ? 255 : r;
- dest[destOffset + 1] = g < 0 ? 0 : g > 255 ? 255 : g;
- dest[destOffset + 2] = b < 0 ? 0 : b > 255 ? 255 : b;
- },
- getRgbBuffer: function DeviceRgbCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- if (bits === 8 && alpha01 === 0) {
- dest.set(src.subarray(srcOffset, srcOffset + count * 3), destOffset);
- return;
- }
- var scale = 255 / ((1 << bits) - 1);
- var j = srcOffset, q = destOffset;
- for (var i = 0; i < count; ++i) {
- dest[q++] = (scale * src[j++]) | 0;
- dest[q++] = (scale * src[j++]) | 0;
- dest[q++] = (scale * src[j++]) | 0;
- q += alpha01;
- }
- },
- getOutputLength: function DeviceRgbCS_getOutputLength(inputLength,
- alpha01) {
- return (inputLength * (3 + alpha01) / 3) | 0;
- },
- isPassthrough: function DeviceRgbCS_isPassthrough(bits) {
- return bits == 8;
- },
- fillRgb: ColorSpace.prototype.fillRgb,
- isDefaultDecode: function DeviceRgbCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
- return DeviceRgbCS;
-})();
-
-var DeviceCmykCS = (function DeviceCmykCSClosure() {
- // The coefficients below was found using numerical analysis: the method of
- // steepest descent for the sum((f_i - color_value_i)^2) for r/g/b colors,
- // where color_value is the tabular value from the table of sampled RGB colors
- // from CMYK US Web Coated (SWOP) colorspace, and f_i is the corresponding
- // CMYK color conversion using the estimation below:
- // f(A, B,.. N) = Acc+Bcm+Ccy+Dck+c+Fmm+Gmy+Hmk+Im+Jyy+Kyk+Ly+Mkk+Nk+255
- function convertToRgb(src, srcOffset, srcScale, dest, destOffset) {
- var c = src[srcOffset + 0] * srcScale;
- var m = src[srcOffset + 1] * srcScale;
- var y = src[srcOffset + 2] * srcScale;
- var k = src[srcOffset + 3] * srcScale;
-
- var r =
- c * (-4.387332384609988 * c + 54.48615194189176 * m +
- 18.82290502165302 * y + 212.25662451639585 * k +
- -285.2331026137004) +
- m * (1.7149763477362134 * m - 5.6096736904047315 * y +
- -17.873870861415444 * k - 5.497006427196366) +
- y * (-2.5217340131683033 * y - 21.248923337353073 * k +
- 17.5119270841813) +
- k * (-21.86122147463605 * k - 189.48180835922747) + 255;
- var g =
- c * (8.841041422036149 * c + 60.118027045597366 * m +
- 6.871425592049007 * y + 31.159100130055922 * k +
- -79.2970844816548) +
- m * (-15.310361306967817 * m + 17.575251261109482 * y +
- 131.35250912493976 * k - 190.9453302588951) +
- y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) +
- k * (-20.737325471181034 * k - 187.80453709719578) + 255;
- var b =
- c * (0.8842522430003296 * c + 8.078677503112928 * m +
- 30.89978309703729 * y - 0.23883238689178934 * k +
- -14.183576799673286) +
- m * (10.49593273432072 * m + 63.02378494754052 * y +
- 50.606957656360734 * k - 112.23884253719248) +
- y * (0.03296041114873217 * y + 115.60384449646641 * k +
- -193.58209356861505) +
- k * (-22.33816807309886 * k - 180.12613974708367) + 255;
-
- dest[destOffset] = r > 255 ? 255 : r < 0 ? 0 : r;
- dest[destOffset + 1] = g > 255 ? 255 : g < 0 ? 0 : g;
- dest[destOffset + 2] = b > 255 ? 255 : b < 0 ? 0 : b;
- }
-
- function DeviceCmykCS() {
- this.name = 'DeviceCMYK';
- this.numComps = 4;
- this.defaultColor = new Float32Array([0, 0, 0, 1]);
- }
- DeviceCmykCS.prototype = {
- getRgb: ColorSpace.prototype.getRgb,
- getRgbItem: function DeviceCmykCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- convertToRgb(src, srcOffset, 1, dest, destOffset);
- },
- getRgbBuffer: function DeviceCmykCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- var scale = 1 / ((1 << bits) - 1);
- for (var i = 0; i < count; i++) {
- convertToRgb(src, srcOffset, scale, dest, destOffset);
- srcOffset += 4;
- destOffset += 3 + alpha01;
- }
- },
- getOutputLength: function DeviceCmykCS_getOutputLength(inputLength,
- alpha01) {
- return (inputLength / 4 * (3 + alpha01)) | 0;
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- fillRgb: ColorSpace.prototype.fillRgb,
- isDefaultDecode: function DeviceCmykCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
-
- return DeviceCmykCS;
-})();
-
-//
-// CalGrayCS: Based on "PDF Reference, Sixth Ed", p.245
-//
-var CalGrayCS = (function CalGrayCSClosure() {
- function CalGrayCS(whitePoint, blackPoint, gamma) {
- this.name = 'CalGray';
- this.numComps = 1;
- this.defaultColor = new Float32Array([0]);
-
- if (!whitePoint) {
- error('WhitePoint missing - required for color space CalGray');
- }
- blackPoint = blackPoint || [0, 0, 0];
- gamma = gamma || 1;
-
- // Translate arguments to spec variables.
- this.XW = whitePoint[0];
- this.YW = whitePoint[1];
- this.ZW = whitePoint[2];
-
- this.XB = blackPoint[0];
- this.YB = blackPoint[1];
- this.ZB = blackPoint[2];
-
- this.G = gamma;
-
- // Validate variables as per spec.
- if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
- error('Invalid WhitePoint components for ' + this.name +
- ', no fallback available');
- }
-
- if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
- info('Invalid BlackPoint for ' + this.name + ', falling back to default');
- this.XB = this.YB = this.ZB = 0;
- }
-
- if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) {
- warn(this.name + ', BlackPoint: XB: ' + this.XB + ', YB: ' + this.YB +
- ', ZB: ' + this.ZB + ', only default values are supported.');
- }
-
- if (this.G < 1) {
- info('Invalid Gamma: ' + this.G + ' for ' + this.name +
- ', falling back to default');
- this.G = 1;
- }
- }
-
- function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) {
- // A represents a gray component of a calibrated gray space.
- // A <---> AG in the spec
- var A = src[srcOffset] * scale;
- var AG = Math.pow(A, cs.G);
-
- // Computes intermediate variables M, L, N as per spec.
- // Except if other than default BlackPoint values are used.
- var M = cs.XW * AG;
- var L = cs.YW * AG;
- var N = cs.ZW * AG;
-
- // Decode XYZ, as per spec.
- var X = M;
- var Y = L;
- var Z = N;
-
- // http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html, Ch 4.
- // This yields values in range [0, 100].
- var Lstar = Math.max(116 * Math.pow(Y, 1 / 3) - 16, 0);
-
- // Convert values to rgb range [0, 255].
- dest[destOffset] = Lstar * 255 / 100;
- dest[destOffset + 1] = Lstar * 255 / 100;
- dest[destOffset + 2] = Lstar * 255 / 100;
- }
-
- CalGrayCS.prototype = {
- getRgb: ColorSpace.prototype.getRgb,
- getRgbItem: function CalGrayCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- convertToRgb(this, src, srcOffset, dest, destOffset, 1);
- },
- getRgbBuffer: function CalGrayCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- var scale = 1 / ((1 << bits) - 1);
-
- for (var i = 0; i < count; ++i) {
- convertToRgb(this, src, srcOffset, dest, destOffset, scale);
- srcOffset += 1;
- destOffset += 3 + alpha01;
- }
- },
- getOutputLength: function CalGrayCS_getOutputLength(inputLength, alpha01) {
- return inputLength * (3 + alpha01);
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- fillRgb: ColorSpace.prototype.fillRgb,
- isDefaultDecode: function CalGrayCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
- return CalGrayCS;
-})();
-
-//
-// LabCS: Based on "PDF Reference, Sixth Ed", p.250
-//
-var LabCS = (function LabCSClosure() {
- function LabCS(whitePoint, blackPoint, range) {
- this.name = 'Lab';
- this.numComps = 3;
- this.defaultColor = new Float32Array([0, 0, 0]);
-
- if (!whitePoint) {
- error('WhitePoint missing - required for color space Lab');
- }
- blackPoint = blackPoint || [0, 0, 0];
- range = range || [-100, 100, -100, 100];
-
- // Translate args to spec variables
- this.XW = whitePoint[0];
- this.YW = whitePoint[1];
- this.ZW = whitePoint[2];
- this.amin = range[0];
- this.amax = range[1];
- this.bmin = range[2];
- this.bmax = range[3];
-
- // These are here just for completeness - the spec doesn't offer any
- // formulas that use BlackPoint in Lab
- this.XB = blackPoint[0];
- this.YB = blackPoint[1];
- this.ZB = blackPoint[2];
-
- // Validate vars as per spec
- if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
- error('Invalid WhitePoint components, no fallback available');
- }
-
- if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
- info('Invalid BlackPoint, falling back to default');
- this.XB = this.YB = this.ZB = 0;
- }
-
- if (this.amin > this.amax || this.bmin > this.bmax) {
- info('Invalid Range, falling back to defaults');
- this.amin = -100;
- this.amax = 100;
- this.bmin = -100;
- this.bmax = 100;
- }
- }
-
- // Function g(x) from spec
- function fn_g(x) {
- if (x >= 6 / 29) {
- return x * x * x;
- } else {
- return (108 / 841) * (x - 4 / 29);
- }
- }
-
- function decode(value, high1, low2, high2) {
- return low2 + (value) * (high2 - low2) / (high1);
- }
-
- // If decoding is needed maxVal should be 2^bits per component - 1.
- function convertToRgb(cs, src, srcOffset, maxVal, dest, destOffset) {
- // XXX: Lab input is in the range of [0, 100], [amin, amax], [bmin, bmax]
- // not the usual [0, 1]. If a command like setFillColor is used the src
- // values will already be within the correct range. However, if we are
- // converting an image we have to map the values to the correct range given
- // above.
- // Ls,as,bs <---> L*,a*,b* in the spec
- var Ls = src[srcOffset];
- var as = src[srcOffset + 1];
- var bs = src[srcOffset + 2];
- if (maxVal !== false) {
- Ls = decode(Ls, maxVal, 0, 100);
- as = decode(as, maxVal, cs.amin, cs.amax);
- bs = decode(bs, maxVal, cs.bmin, cs.bmax);
- }
-
- // Adjust limits of 'as' and 'bs'
- as = as > cs.amax ? cs.amax : as < cs.amin ? cs.amin : as;
- bs = bs > cs.bmax ? cs.bmax : bs < cs.bmin ? cs.bmin : bs;
-
- // Computes intermediate variables X,Y,Z as per spec
- var M = (Ls + 16) / 116;
- var L = M + (as / 500);
- var N = M - (bs / 200);
-
- var X = cs.XW * fn_g(L);
- var Y = cs.YW * fn_g(M);
- var Z = cs.ZW * fn_g(N);
-
- var r, g, b;
- // Using different conversions for D50 and D65 white points,
- // per http://www.color.org/srgb.pdf
- if (cs.ZW < 1) {
- // Assuming D50 (X=0.9642, Y=1.00, Z=0.8249)
- r = X * 3.1339 + Y * -1.6170 + Z * -0.4906;
- g = X * -0.9785 + Y * 1.9160 + Z * 0.0333;
- b = X * 0.0720 + Y * -0.2290 + Z * 1.4057;
- } else {
- // Assuming D65 (X=0.9505, Y=1.00, Z=1.0888)
- r = X * 3.2406 + Y * -1.5372 + Z * -0.4986;
- g = X * -0.9689 + Y * 1.8758 + Z * 0.0415;
- b = X * 0.0557 + Y * -0.2040 + Z * 1.0570;
- }
- // clamp color values to [0,1] range then convert to [0,255] range.
- dest[destOffset] = r <= 0 ? 0 : r >= 1 ? 255 : Math.sqrt(r) * 255 | 0;
- dest[destOffset + 1] = g <= 0 ? 0 : g >= 1 ? 255 : Math.sqrt(g) * 255 | 0;
- dest[destOffset + 2] = b <= 0 ? 0 : b >= 1 ? 255 : Math.sqrt(b) * 255 | 0;
- }
-
- LabCS.prototype = {
- getRgb: ColorSpace.prototype.getRgb,
- getRgbItem: function LabCS_getRgbItem(src, srcOffset, dest, destOffset) {
- convertToRgb(this, src, srcOffset, false, dest, destOffset);
- },
- getRgbBuffer: function LabCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits,
- alpha01) {
- var maxVal = (1 << bits) - 1;
- for (var i = 0; i < count; i++) {
- convertToRgb(this, src, srcOffset, maxVal, dest, destOffset);
- srcOffset += 3;
- destOffset += 3 + alpha01;
- }
- },
- getOutputLength: function LabCS_getOutputLength(inputLength, alpha01) {
- return (inputLength * (3 + alpha01) / 3) | 0;
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- isDefaultDecode: function LabCS_isDefaultDecode(decodeMap) {
- // XXX: Decoding is handled with the lab conversion because of the strange
- // ranges that are used.
- return true;
- },
- usesZeroToOneRange: false
- };
- return LabCS;
-})();
-
-
-
-var PDFFunction = (function PDFFunctionClosure() {
- var CONSTRUCT_SAMPLED = 0;
- var CONSTRUCT_INTERPOLATED = 2;
- var CONSTRUCT_STICHED = 3;
- var CONSTRUCT_POSTSCRIPT = 4;
-
- return {
- getSampleArray: function PDFFunction_getSampleArray(size, outputSize, bps,
- str) {
- var length = 1;
- for (var i = 0, ii = size.length; i < ii; i++) {
- length *= size[i];
- }
- length *= outputSize;
-
- var array = [];
- var codeSize = 0;
- var codeBuf = 0;
- // 32 is a valid bps so shifting won't work
- var sampleMul = 1.0 / (Math.pow(2.0, bps) - 1);
-
- var strBytes = str.getBytes((length * bps + 7) / 8);
- var strIdx = 0;
- for (var i = 0; i < length; i++) {
- while (codeSize < bps) {
- codeBuf <<= 8;
- codeBuf |= strBytes[strIdx++];
- codeSize += 8;
- }
- codeSize -= bps;
- array.push((codeBuf >> codeSize) * sampleMul);
- codeBuf &= (1 << codeSize) - 1;
- }
- return array;
- },
-
- getIR: function PDFFunction_getIR(xref, fn) {
- var dict = fn.dict;
- if (!dict) {
- dict = fn;
- }
-
- var types = [this.constructSampled,
- null,
- this.constructInterpolated,
- this.constructStiched,
- this.constructPostScript];
-
- var typeNum = dict.get('FunctionType');
- var typeFn = types[typeNum];
- if (!typeFn) {
- error('Unknown type of function');
- }
-
- return typeFn.call(this, fn, dict, xref);
- },
-
- fromIR: function PDFFunction_fromIR(IR) {
- var type = IR[0];
- switch (type) {
- case CONSTRUCT_SAMPLED:
- return this.constructSampledFromIR(IR);
- case CONSTRUCT_INTERPOLATED:
- return this.constructInterpolatedFromIR(IR);
- case CONSTRUCT_STICHED:
- return this.constructStichedFromIR(IR);
- //case CONSTRUCT_POSTSCRIPT:
- default:
- return this.constructPostScriptFromIR(IR);
- }
- },
-
- parse: function PDFFunction_parse(xref, fn) {
- var IR = this.getIR(xref, fn);
- return this.fromIR(IR);
- },
-
- constructSampled: function PDFFunction_constructSampled(str, dict) {
- function toMultiArray(arr) {
- var inputLength = arr.length;
- var outputLength = arr.length / 2;
- var out = [];
- var index = 0;
- for (var i = 0; i < inputLength; i += 2) {
- out[index] = [arr[i], arr[i + 1]];
- ++index;
- }
- return out;
- }
- var domain = dict.get('Domain');
- var range = dict.get('Range');
-
- if (!domain || !range) {
- error('No domain or range');
- }
-
- var inputSize = domain.length / 2;
- var outputSize = range.length / 2;
-
- domain = toMultiArray(domain);
- range = toMultiArray(range);
-
- var size = dict.get('Size');
- var bps = dict.get('BitsPerSample');
- var order = dict.get('Order') || 1;
- if (order !== 1) {
- // No description how cubic spline interpolation works in PDF32000:2008
- // As in poppler, ignoring order, linear interpolation may work as good
- info('No support for cubic spline interpolation: ' + order);
- }
-
- var encode = dict.get('Encode');
- if (!encode) {
- encode = [];
- for (var i = 0; i < inputSize; ++i) {
- encode.push(0);
- encode.push(size[i] - 1);
- }
- }
- encode = toMultiArray(encode);
-
- var decode = dict.get('Decode');
- if (!decode) {
- decode = range;
- } else {
- decode = toMultiArray(decode);
- }
-
- var samples = this.getSampleArray(size, outputSize, bps, str);
-
- return [
- CONSTRUCT_SAMPLED, inputSize, domain, encode, decode, samples, size,
- outputSize, Math.pow(2, bps) - 1, range
- ];
- },
-
- constructSampledFromIR: function PDFFunction_constructSampledFromIR(IR) {
- // See chapter 3, page 109 of the PDF reference
- function interpolate(x, xmin, xmax, ymin, ymax) {
- return ymin + ((x - xmin) * ((ymax - ymin) / (xmax - xmin)));
- }
-
- return function constructSampledFromIRResult(args) {
- // See chapter 3, page 110 of the PDF reference.
- var m = IR[1];
- var domain = IR[2];
- var encode = IR[3];
- var decode = IR[4];
- var samples = IR[5];
- var size = IR[6];
- var n = IR[7];
- var mask = IR[8];
- var range = IR[9];
-
- if (m != args.length) {
- error('Incorrect number of arguments: ' + m + ' != ' +
- args.length);
- }
-
- var x = args;
-
- // Building the cube vertices: its part and sample index
- // http://rjwagner49.com/Mathematics/Interpolation.pdf
- var cubeVertices = 1 << m;
- var cubeN = new Float64Array(cubeVertices);
- var cubeVertex = new Uint32Array(cubeVertices);
- for (var j = 0; j < cubeVertices; j++) {
- cubeN[j] = 1;
- }
-
- var k = n, pos = 1;
- // Map x_i to y_j for 0 <= i < m using the sampled function.
- for (var i = 0; i < m; ++i) {
- // x_i' = min(max(x_i, Domain_2i), Domain_2i+1)
- var domain_2i = domain[i][0];
- var domain_2i_1 = domain[i][1];
- var xi = Math.min(Math.max(x[i], domain_2i), domain_2i_1);
-
- // e_i = Interpolate(x_i', Domain_2i, Domain_2i+1,
- // Encode_2i, Encode_2i+1)
- var e = interpolate(xi, domain_2i, domain_2i_1,
- encode[i][0], encode[i][1]);
-
- // e_i' = min(max(e_i, 0), Size_i - 1)
- var size_i = size[i];
- e = Math.min(Math.max(e, 0), size_i - 1);
-
- // Adjusting the cube: N and vertex sample index
- var e0 = e < size_i - 1 ? Math.floor(e) : e - 1; // e1 = e0 + 1;
- var n0 = e0 + 1 - e; // (e1 - e) / (e1 - e0);
- var n1 = e - e0; // (e - e0) / (e1 - e0);
- var offset0 = e0 * k;
- var offset1 = offset0 + k; // e1 * k
- for (var j = 0; j < cubeVertices; j++) {
- if (j & pos) {
- cubeN[j] *= n1;
- cubeVertex[j] += offset1;
- } else {
- cubeN[j] *= n0;
- cubeVertex[j] += offset0;
- }
- }
-
- k *= size_i;
- pos <<= 1;
- }
-
- var y = new Float64Array(n);
- for (var j = 0; j < n; ++j) {
- // Sum all cube vertices' samples portions
- var rj = 0;
- for (var i = 0; i < cubeVertices; i++) {
- rj += samples[cubeVertex[i] + j] * cubeN[i];
- }
-
- // r_j' = Interpolate(r_j, 0, 2^BitsPerSample - 1,
- // Decode_2j, Decode_2j+1)
- rj = interpolate(rj, 0, 1, decode[j][0], decode[j][1]);
-
- // y_j = min(max(r_j, range_2j), range_2j+1)
- y[j] = Math.min(Math.max(rj, range[j][0]), range[j][1]);
- }
-
- return y;
- };
- },
-
- constructInterpolated: function PDFFunction_constructInterpolated(str,
- dict) {
- var c0 = dict.get('C0') || [0];
- var c1 = dict.get('C1') || [1];
- var n = dict.get('N');
-
- if (!isArray(c0) || !isArray(c1)) {
- error('Illegal dictionary for interpolated function');
- }
-
- var length = c0.length;
- var diff = [];
- for (var i = 0; i < length; ++i) {
- diff.push(c1[i] - c0[i]);
- }
-
- return [CONSTRUCT_INTERPOLATED, c0, diff, n];
- },
-
- constructInterpolatedFromIR:
- function PDFFunction_constructInterpolatedFromIR(IR) {
- var c0 = IR[1];
- var diff = IR[2];
- var n = IR[3];
-
- var length = diff.length;
-
- return function constructInterpolatedFromIRResult(args) {
- var x = n == 1 ? args[0] : Math.pow(args[0], n);
-
- var out = [];
- for (var j = 0; j < length; ++j) {
- out.push(c0[j] + (x * diff[j]));
- }
-
- return out;
-
- };
- },
-
- constructStiched: function PDFFunction_constructStiched(fn, dict, xref) {
- var domain = dict.get('Domain');
-
- if (!domain) {
- error('No domain');
- }
-
- var inputSize = domain.length / 2;
- if (inputSize != 1) {
- error('Bad domain for stiched function');
- }
-
- var fnRefs = dict.get('Functions');
- var fns = [];
- for (var i = 0, ii = fnRefs.length; i < ii; ++i) {
- fns.push(PDFFunction.getIR(xref, xref.fetchIfRef(fnRefs[i])));
- }
-
- var bounds = dict.get('Bounds');
- var encode = dict.get('Encode');
-
- return [CONSTRUCT_STICHED, domain, bounds, encode, fns];
- },
-
- constructStichedFromIR: function PDFFunction_constructStichedFromIR(IR) {
- var domain = IR[1];
- var bounds = IR[2];
- var encode = IR[3];
- var fnsIR = IR[4];
- var fns = [];
-
- for (var i = 0, ii = fnsIR.length; i < ii; i++) {
- fns.push(PDFFunction.fromIR(fnsIR[i]));
- }
-
- return function constructStichedFromIRResult(args) {
- var clip = function constructStichedFromIRClip(v, min, max) {
- if (v > max) {
- v = max;
- } else if (v < min) {
- v = min;
- }
- return v;
- };
-
- // clip to domain
- var v = clip(args[0], domain[0], domain[1]);
- // calulate which bound the value is in
- for (var i = 0, ii = bounds.length; i < ii; ++i) {
- if (v < bounds[i]) {
- break;
- }
- }
-
- // encode value into domain of function
- var dmin = domain[0];
- if (i > 0) {
- dmin = bounds[i - 1];
- }
- var dmax = domain[1];
- if (i < bounds.length) {
- dmax = bounds[i];
- }
-
- var rmin = encode[2 * i];
- var rmax = encode[2 * i + 1];
-
- var v2 = rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin);
-
- // call the appropriate function
- return fns[i]([v2]);
- };
- },
-
- constructPostScript: function PDFFunction_constructPostScript(fn, dict,
- xref) {
- var domain = dict.get('Domain');
- var range = dict.get('Range');
-
- if (!domain) {
- error('No domain.');
- }
-
- if (!range) {
- error('No range.');
- }
-
- var lexer = new PostScriptLexer(fn);
- var parser = new PostScriptParser(lexer);
- var code = parser.parse();
-
- return [CONSTRUCT_POSTSCRIPT, domain, range, code];
- },
-
- constructPostScriptFromIR: function PDFFunction_constructPostScriptFromIR(
- IR) {
- var domain = IR[1];
- var range = IR[2];
- var code = IR[3];
- var numOutputs = range.length / 2;
- var evaluator = new PostScriptEvaluator(code);
- // Cache the values for a big speed up, the cache size is limited though
- // since the number of possible values can be huge from a PS function.
- var cache = new FunctionCache();
- return function constructPostScriptFromIRResult(args) {
- var initialStack = [];
- for (var i = 0, ii = (domain.length / 2); i < ii; ++i) {
- initialStack.push(args[i]);
- }
-
- var key = initialStack.join('_');
- if (cache.has(key)) {
- return cache.get(key);
- }
-
- var stack = evaluator.execute(initialStack);
- var transformed = [];
- for (i = numOutputs - 1; i >= 0; --i) {
- var out = stack.pop();
- var rangeIndex = 2 * i;
- if (out < range[rangeIndex]) {
- out = range[rangeIndex];
- } else if (out > range[rangeIndex + 1]) {
- out = range[rangeIndex + 1];
- }
- transformed[i] = out;
- }
- cache.set(key, transformed);
- return transformed;
- };
- }
- };
-})();
-
-var FunctionCache = (function FunctionCacheClosure() {
- // Of 10 PDF's with type4 functions the maxium number of distinct values seen
- // was 256. This still may need some tweaking in the future though.
- var MAX_CACHE_SIZE = 1024;
- function FunctionCache() {
- this.cache = {};
- this.total = 0;
- }
- FunctionCache.prototype = {
- has: function FunctionCache_has(key) {
- return key in this.cache;
- },
- get: function FunctionCache_get(key) {
- return this.cache[key];
- },
- set: function FunctionCache_set(key, value) {
- if (this.total < MAX_CACHE_SIZE) {
- this.cache[key] = value;
- this.total++;
- }
- }
- };
- return FunctionCache;
-})();
-
-var PostScriptStack = (function PostScriptStackClosure() {
- var MAX_STACK_SIZE = 100;
- function PostScriptStack(initialStack) {
- this.stack = initialStack || [];
- }
-
- PostScriptStack.prototype = {
- push: function PostScriptStack_push(value) {
- if (this.stack.length >= MAX_STACK_SIZE) {
- error('PostScript function stack overflow.');
- }
- this.stack.push(value);
- },
- pop: function PostScriptStack_pop() {
- if (this.stack.length <= 0) {
- error('PostScript function stack underflow.');
- }
- return this.stack.pop();
- },
- copy: function PostScriptStack_copy(n) {
- if (this.stack.length + n >= MAX_STACK_SIZE) {
- error('PostScript function stack overflow.');
- }
- var stack = this.stack;
- for (var i = stack.length - n, j = n - 1; j >= 0; j--, i++) {
- stack.push(stack[i]);
- }
- },
- index: function PostScriptStack_index(n) {
- this.push(this.stack[this.stack.length - n - 1]);
- },
- // rotate the last n stack elements p times
- roll: function PostScriptStack_roll(n, p) {
- var stack = this.stack;
- var l = stack.length - n;
- var r = stack.length - 1, c = l + (p - Math.floor(p / n) * n), i, j, t;
- for (i = l, j = r; i < j; i++, j--) {
- t = stack[i]; stack[i] = stack[j]; stack[j] = t;
- }
- for (i = l, j = c - 1; i < j; i++, j--) {
- t = stack[i]; stack[i] = stack[j]; stack[j] = t;
- }
- for (i = c, j = r; i < j; i++, j--) {
- t = stack[i]; stack[i] = stack[j]; stack[j] = t;
- }
- }
- };
- return PostScriptStack;
-})();
-var PostScriptEvaluator = (function PostScriptEvaluatorClosure() {
- function PostScriptEvaluator(operators) {
- this.operators = operators;
- }
- PostScriptEvaluator.prototype = {
- execute: function PostScriptEvaluator_execute(initialStack) {
- var stack = new PostScriptStack(initialStack);
- var counter = 0;
- var operators = this.operators;
- var length = operators.length;
- var operator, a, b;
- while (counter < length) {
- operator = operators[counter++];
- if (typeof operator == 'number') {
- // Operator is really an operand and should be pushed to the stack.
- stack.push(operator);
- continue;
- }
- switch (operator) {
- // non standard ps operators
- case 'jz': // jump if false
- b = stack.pop();
- a = stack.pop();
- if (!a) {
- counter = b;
- }
- break;
- case 'j': // jump
- a = stack.pop();
- counter = a;
- break;
-
- // all ps operators in alphabetical order (excluding if/ifelse)
- case 'abs':
- a = stack.pop();
- stack.push(Math.abs(a));
- break;
- case 'add':
- b = stack.pop();
- a = stack.pop();
- stack.push(a + b);
- break;
- case 'and':
- b = stack.pop();
- a = stack.pop();
- if (isBool(a) && isBool(b)) {
- stack.push(a && b);
- } else {
- stack.push(a & b);
- }
- break;
- case 'atan':
- a = stack.pop();
- stack.push(Math.atan(a));
- break;
- case 'bitshift':
- b = stack.pop();
- a = stack.pop();
- if (a > 0) {
- stack.push(a << b);
- } else {
- stack.push(a >> b);
- }
- break;
- case 'ceiling':
- a = stack.pop();
- stack.push(Math.ceil(a));
- break;
- case 'copy':
- a = stack.pop();
- stack.copy(a);
- break;
- case 'cos':
- a = stack.pop();
- stack.push(Math.cos(a));
- break;
- case 'cvi':
- a = stack.pop() | 0;
- stack.push(a);
- break;
- case 'cvr':
- // noop
- break;
- case 'div':
- b = stack.pop();
- a = stack.pop();
- stack.push(a / b);
- break;
- case 'dup':
- stack.copy(1);
- break;
- case 'eq':
- b = stack.pop();
- a = stack.pop();
- stack.push(a == b);
- break;
- case 'exch':
- stack.roll(2, 1);
- break;
- case 'exp':
- b = stack.pop();
- a = stack.pop();
- stack.push(Math.pow(a, b));
- break;
- case 'false':
- stack.push(false);
- break;
- case 'floor':
- a = stack.pop();
- stack.push(Math.floor(a));
- break;
- case 'ge':
- b = stack.pop();
- a = stack.pop();
- stack.push(a >= b);
- break;
- case 'gt':
- b = stack.pop();
- a = stack.pop();
- stack.push(a > b);
- break;
- case 'idiv':
- b = stack.pop();
- a = stack.pop();
- stack.push((a / b) | 0);
- break;
- case 'index':
- a = stack.pop();
- stack.index(a);
- break;
- case 'le':
- b = stack.pop();
- a = stack.pop();
- stack.push(a <= b);
- break;
- case 'ln':
- a = stack.pop();
- stack.push(Math.log(a));
- break;
- case 'log':
- a = stack.pop();
- stack.push(Math.log(a) / Math.LN10);
- break;
- case 'lt':
- b = stack.pop();
- a = stack.pop();
- stack.push(a < b);
- break;
- case 'mod':
- b = stack.pop();
- a = stack.pop();
- stack.push(a % b);
- break;
- case 'mul':
- b = stack.pop();
- a = stack.pop();
- stack.push(a * b);
- break;
- case 'ne':
- b = stack.pop();
- a = stack.pop();
- stack.push(a != b);
- break;
- case 'neg':
- a = stack.pop();
- stack.push(-b);
- break;
- case 'not':
- a = stack.pop();
- if (isBool(a) && isBool(b)) {
- stack.push(a && b);
- } else {
- stack.push(a & b);
- }
- break;
- case 'or':
- b = stack.pop();
- a = stack.pop();
- if (isBool(a) && isBool(b)) {
- stack.push(a || b);
- } else {
- stack.push(a | b);
- }
- break;
- case 'pop':
- stack.pop();
- break;
- case 'roll':
- b = stack.pop();
- a = stack.pop();
- stack.roll(a, b);
- break;
- case 'round':
- a = stack.pop();
- stack.push(Math.round(a));
- break;
- case 'sin':
- a = stack.pop();
- stack.push(Math.sin(a));
- break;
- case 'sqrt':
- a = stack.pop();
- stack.push(Math.sqrt(a));
- break;
- case 'sub':
- b = stack.pop();
- a = stack.pop();
- stack.push(a - b);
- break;
- case 'true':
- stack.push(true);
- break;
- case 'truncate':
- a = stack.pop();
- a = a < 0 ? Math.ceil(a) : Math.floor(a);
- stack.push(a);
- break;
- case 'xor':
- b = stack.pop();
- a = stack.pop();
- if (isBool(a) && isBool(b)) {
- stack.push(a != b);
- } else {
- stack.push(a ^ b);
- }
- break;
- default:
- error('Unknown operator ' + operator);
- break;
- }
- }
- return stack.stack;
- }
- };
- return PostScriptEvaluator;
-})();
-
-
+var DEFAULT_ICON_SIZE = 22; // px
var HIGHLIGHT_OFFSET = 4; // px
var SUPPORTED_TYPES = ['Link', 'Text', 'Widget'];
@@ -3034,7 +1618,7 @@ var Annotation = (function AnnotationClosure() {
var data = this.data = {};
data.subtype = dict.get('Subtype').name;
- var rect = dict.get('Rect');
+ var rect = dict.get('Rect') || [0, 0, 0, 0];
data.rect = Util.normalizeRect(rect);
data.annotationFlags = dict.get('F');
@@ -3058,23 +1642,30 @@ var Annotation = (function AnnotationClosure() {
// TODO: implement proper support for annotations with line dash patterns.
var dashArray = borderArray[3];
- if (data.borderWidth > 0 && dashArray && isArray(dashArray)) {
- var dashArrayLength = dashArray.length;
- if (dashArrayLength > 0) {
- // According to the PDF specification: the elements in a dashArray
- // shall be numbers that are nonnegative and not all equal to zero.
- var isInvalid = false;
- var numPositive = 0;
- for (var i = 0; i < dashArrayLength; i++) {
- if (!(+dashArray[i] >= 0)) {
- isInvalid = true;
- break;
- } else if (dashArray[i] > 0) {
- numPositive++;
+ if (data.borderWidth > 0 && dashArray) {
+ if (!isArray(dashArray)) {
+ // Ignore the border if dashArray is not actually an array,
+ // this is consistent with the behaviour in Adobe Reader.
+ data.borderWidth = 0;
+ } else {
+ var dashArrayLength = dashArray.length;
+ if (dashArrayLength > 0) {
+ // According to the PDF specification: the elements in a dashArray
+ // shall be numbers that are nonnegative and not all equal to zero.
+ var isInvalid = false;
+ var numPositive = 0;
+ for (var i = 0; i < dashArrayLength; i++) {
+ var validNumber = (+dashArray[i] >= 0);
+ if (!validNumber) {
+ isInvalid = true;
+ break;
+ } else if (dashArray[i] > 0) {
+ numPositive++;
+ }
+ }
+ if (isInvalid || numPositive === 0) {
+ data.borderWidth = 0;
}
- }
- if (isInvalid || numPositive === 0) {
- data.borderWidth = 0;
}
}
}
@@ -3082,6 +1673,7 @@ var Annotation = (function AnnotationClosure() {
this.appearance = getDefaultAppearance(dict);
data.hasAppearance = !!this.appearance;
+ data.id = params.ref.num;
}
Annotation.prototype = {
@@ -3146,31 +1738,27 @@ var Annotation = (function AnnotationClosure() {
data.rect); // rectangle is nessessary
},
- loadResources: function(keys) {
- var promise = new LegacyPromise();
- this.appearance.dict.getAsync('Resources').then(function(resources) {
- if (!resources) {
- promise.resolve();
- return;
- }
- var objectLoader = new ObjectLoader(resources.map,
- keys,
- resources.xref);
- objectLoader.load().then(function() {
- promise.resolve(resources);
- });
+ loadResources: function Annotation_loadResources(keys) {
+ return new Promise(function (resolve, reject) {
+ this.appearance.dict.getAsync('Resources').then(function (resources) {
+ if (!resources) {
+ resolve();
+ return;
+ }
+ var objectLoader = new ObjectLoader(resources.map,
+ keys,
+ resources.xref);
+ objectLoader.load().then(function() {
+ resolve(resources);
+ }, reject);
+ }, reject);
}.bind(this));
-
- return promise;
},
getOperatorList: function Annotation_getOperatorList(evaluator) {
- var promise = new LegacyPromise();
-
if (!this.appearance) {
- promise.resolve(new OperatorList());
- return promise;
+ return Promise.resolve(new OperatorList());
}
var data = this.data;
@@ -3189,20 +1777,18 @@ var Annotation = (function AnnotationClosure() {
var bbox = appearanceDict.get('BBox') || [0, 0, 1, 1];
var matrix = appearanceDict.get('Matrix') || [1, 0, 0, 1, 0 ,0];
var transform = getTransformMatrix(data.rect, bbox, matrix);
+ var self = this;
- var border = data.border;
-
- resourcesPromise.then(function(resources) {
- var opList = new OperatorList();
- opList.addOp(OPS.beginAnnotation, [data.rect, transform, matrix]);
- evaluator.getOperatorList(this.appearance, resources, opList);
- opList.addOp(OPS.endAnnotation, []);
- promise.resolve(opList);
-
- this.appearance.reset();
- }.bind(this));
-
- return promise;
+ return resourcesPromise.then(function(resources) {
+ var opList = new OperatorList();
+ opList.addOp(OPS.beginAnnotation, [data.rect, transform, matrix]);
+ return evaluator.getOperatorList(self.appearance, resources, opList).
+ then(function () {
+ opList.addOp(OPS.endAnnotation, []);
+ self.appearance.reset();
+ return opList;
+ });
+ });
}
};
@@ -3282,10 +1868,10 @@ var Annotation = (function AnnotationClosure() {
annotations, opList, pdfManager, partialEvaluator, intent) {
function reject(e) {
- annotationsReadyPromise.reject(e);
+ annotationsReadyCapability.reject(e);
}
- var annotationsReadyPromise = new LegacyPromise();
+ var annotationsReadyCapability = createPromiseCapability();
var annotationPromises = [];
for (var i = 0, n = annotations.length; i < n; ++i) {
@@ -3302,10 +1888,10 @@ var Annotation = (function AnnotationClosure() {
opList.addOpList(annotOpList);
}
opList.addOp(OPS.endAnnotations, []);
- annotationsReadyPromise.resolve();
+ annotationsReadyCapability.resolve();
}, reject);
- return annotationsReadyPromise;
+ return annotationsReadyCapability.promise;
};
return Annotation;
@@ -3332,7 +1918,7 @@ var WidgetAnnotation = (function WidgetAnnotationClosure() {
var fieldType = Util.getInheritableProperty(dict, 'FT');
data.fieldType = isName(fieldType) ? fieldType.name : '';
data.fieldFlags = Util.getInheritableProperty(dict, 'Ff') || 0;
- this.fieldResources = Util.getInheritableProperty(dict, 'DR') || new Dict();
+ this.fieldResources = Util.getInheritableProperty(dict, 'DR') || Dict.empty;
// Building the full field name by collecting the field and
// its ancestors 'T' data and joining them using '.'.
@@ -3417,7 +2003,6 @@ var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
}
- var parent = WidgetAnnotation.prototype;
Util.inherit(TextWidgetAnnotation, WidgetAnnotation, {
hasHtml: function TextWidgetAnnotation_hasHtml() {
return !this.data.hasAppearance && !!this.data.fieldValue;
@@ -3440,7 +2025,7 @@ var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
var fontObj = item.fontRefName ?
commonObjs.getData(item.fontRefName) : null;
- var cssRules = setTextStyles(content, item, fontObj);
+ setTextStyles(content, item, fontObj);
element.appendChild(content);
@@ -3452,54 +2037,20 @@ var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
return Annotation.prototype.getOperatorList.call(this, evaluator);
}
- var promise = new LegacyPromise();
var opList = new OperatorList();
var data = this.data;
// Even if there is an appearance stream, ignore it. This is the
// behaviour used by Adobe Reader.
-
- var defaultAppearance = data.defaultAppearance;
- if (!defaultAppearance) {
- promise.resolve(opList);
- return promise;
+ if (!data.defaultAppearance) {
+ return Promise.resolve(opList);
}
- // Include any font resources found in the default appearance
-
- var stream = new Stream(stringToBytes(defaultAppearance));
- evaluator.getOperatorList(stream, this.fieldResources, opList);
- var appearanceFnArray = opList.fnArray;
- var appearanceArgsArray = opList.argsArray;
- var fnArray = [];
- var argsArray = [];
-
- // TODO(mack): Add support for stroke color
- data.rgb = [0, 0, 0];
- // TODO THIS DOESN'T MAKE ANY SENSE SINCE THE fnArray IS EMPTY!
- for (var i = 0, n = fnArray.length; i < n; ++i) {
- var fnId = appearanceFnArray[i];
- var args = appearanceArgsArray[i];
-
- if (fnId === OPS.setFont) {
- data.fontRefName = args[0];
- var size = args[1];
- if (size < 0) {
- data.fontDirection = -1;
- data.fontSize = -size;
- } else {
- data.fontDirection = 1;
- data.fontSize = size;
- }
- } else if (fnId === OPS.setFillRGBColor) {
- data.rgb = args;
- } else if (fnId === OPS.setFillGray) {
- var rgbValue = args[0] * 255;
- data.rgb = [rgbValue, rgbValue, rgbValue];
- }
- }
- promise.resolve(opList);
- return promise;
+ var stream = new Stream(stringToBytes(data.defaultAppearance));
+ return evaluator.getOperatorList(stream, this.fieldResources, opList).
+ then(function () {
+ return opList;
+ });
}
});
@@ -3580,6 +2131,8 @@ var TextAnnotation = (function TextAnnotationClosure() {
if (data.hasAppearance) {
data.name = 'NoIcon';
} else {
+ data.rect[1] = data.rect[3] - DEFAULT_ICON_SIZE;
+ data.rect[2] = data.rect[0] + DEFAULT_ICON_SIZE;
data.name = dict.has('Name') ? dict.get('Name').name : 'Note';
}
@@ -3627,10 +2180,12 @@ var TextAnnotation = (function TextAnnotationClosure() {
var content = document.createElement('div');
content.className = 'annotTextContent';
content.setAttribute('hidden', true);
+
+ var i, ii;
if (item.hasBgColor) {
var color = item.color;
var rgb = [];
- for (var i = 0; i < 3; ++i) {
+ for (i = 0; i < 3; ++i) {
// Enlighten the color (70%)
var c = Math.round(color[i] * 255);
rgb[i] = Math.round((255 - c) * 0.7) + c;
@@ -3647,7 +2202,7 @@ var TextAnnotation = (function TextAnnotationClosure() {
} else {
var e = document.createElement('span');
var lines = item.content.split(/(?:\r\n?|\n)/);
- for (var i = 0, ii = lines.length; i < ii; ++i) {
+ for (i = 0, ii = lines.length; i < ii; ++i) {
var line = lines[i];
e.appendChild(document.createTextNode(line));
if (i < (ii - 1)) {
@@ -3686,7 +2241,6 @@ var TextAnnotation = (function TextAnnotationClosure() {
}
};
- var self = this;
image.addEventListener('click', function image_clickHandler() {
toggleAnnotation();
}, false);
@@ -3791,7 +2345,6 @@ var LinkAnnotation = (function LinkAnnotationClosure() {
container.className = 'annotLink';
var item = this.data;
- var rect = item.rect;
container.style.borderColor = item.colorCssRgb;
container.style.borderStyle = 'solid';
@@ -3824,6 +2377,12 @@ PDFJS.maxImageSize = (PDFJS.maxImageSize === undefined ?
*/
PDFJS.cMapUrl = (PDFJS.cMapUrl === undefined ? null : PDFJS.cMapUrl);
+/**
+ * Specifies if CMaps are binary packed.
+ * @var {boolean}
+ */
+PDFJS.cMapPacked = PDFJS.cMapPacked === undefined ? false : PDFJS.cMapPacked;
+
/*
* By default fonts are converted to OpenType fonts and loaded via font face
* rules. If disabled, the font will be rendered using a built in font renderer
@@ -3897,6 +2456,13 @@ PDFJS.disableCreateObjectURL = (PDFJS.disableCreateObjectURL === undefined ?
false : PDFJS.disableCreateObjectURL);
/**
+ * Disables WebGL usage.
+ * @var {boolean}
+ */
+PDFJS.disableWebGL = (PDFJS.disableWebGL === undefined ?
+ true : PDFJS.disableWebGL);
+
+/**
* Controls the logging level.
* The constants from PDFJS.VERBOSITY_LEVELS should be used:
* - errors
@@ -3949,7 +2515,7 @@ PDFJS.getDocument = function getDocument(source,
pdfDataRangeTransport,
passwordCallback,
progressCallback) {
- var workerInitializedPromise, workerReadyPromise, transport;
+ var workerInitializedCapability, workerReadyCapability, transport;
if (typeof source === 'string') {
source = { url: source };
@@ -3974,15 +2540,16 @@ PDFJS.getDocument = function getDocument(source,
params[key] = source[key];
}
- workerInitializedPromise = new PDFJS.LegacyPromise();
- workerReadyPromise = new PDFJS.LegacyPromise();
- transport = new WorkerTransport(workerInitializedPromise, workerReadyPromise,
- pdfDataRangeTransport, progressCallback);
- workerInitializedPromise.then(function transportInitialized() {
+ workerInitializedCapability = createPromiseCapability();
+ workerReadyCapability = createPromiseCapability();
+ transport = new WorkerTransport(workerInitializedCapability,
+ workerReadyCapability, pdfDataRangeTransport,
+ progressCallback);
+ workerInitializedCapability.promise.then(function transportInitialized() {
transport.passwordCallback = passwordCallback;
transport.fetchDocument(params);
});
- return workerReadyPromise;
+ return workerReadyCapability.promise;
};
/**
@@ -4034,14 +2601,18 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
return this.transport.getDestinations();
},
/**
+ * @return {Promise} A promise that is resolved with a lookup table for
+ * mapping named attachments to their content.
+ */
+ getAttachments: function PDFDocumentProxy_getAttachments() {
+ return this.transport.getAttachments();
+ },
+ /**
* @return {Promise} A promise that is resolved with an array of all the
* JavaScript strings in the name tree.
*/
getJavaScript: function PDFDocumentProxy_getJavaScript() {
- var promise = new PDFJS.LegacyPromise();
- var js = this.pdfInfo.javaScript;
- promise.resolve(js);
- return promise;
+ return this.transport.getJavaScript();
},
/**
* @return {Promise} A promise that is resolved with an {Array} that is a
@@ -4059,10 +2630,7 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
* ].
*/
getOutline: function PDFDocumentProxy_getOutline() {
- var promise = new PDFJS.LegacyPromise();
- var outline = this.pdfInfo.outline;
- promise.resolve(outline);
- return promise;
+ return this.transport.getOutline();
},
/**
* @return {Promise} A promise that is resolved with an {Object} that has
@@ -4071,23 +2639,14 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
* {Metadata} object with information from the metadata section of the PDF.
*/
getMetadata: function PDFDocumentProxy_getMetadata() {
- var promise = new PDFJS.LegacyPromise();
- var info = this.pdfInfo.info;
- var metadata = this.pdfInfo.metadata;
- promise.resolve({
- info: info,
- metadata: (metadata ? new PDFJS.Metadata(metadata) : null)
- });
- return promise;
+ return this.transport.getMetadata();
},
/**
* @return {Promise} A promise that is resolved with a TypedArray that has
* the raw data from the PDF.
*/
getData: function PDFDocumentProxy_getData() {
- var promise = new PDFJS.LegacyPromise();
- this.transport.getData(promise);
- return promise;
+ return this.transport.getData();
},
/**
* @return {Promise} A promise that is resolved when the document's data
@@ -4095,7 +2654,7 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
* property that indicates size of the PDF data in bytes.
*/
getDownloadInfo: function PDFDocumentProxy_getDownloadInfo() {
- return this.transport.downloadInfoPromise;
+ return this.transport.downloadInfoCapability.promise;
},
/**
* Cleans up resources allocated by the document, e.g. created @font-face.
@@ -4114,15 +2673,51 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
})();
/**
+ * Page text content.
+ *
+ * @typedef {Object} TextContent
+ * @property {array} items - array of {@link TextItem}
+ * @property {Object} styles - {@link TextStyles} objects, indexed by font
+ * name.
+ */
+
+/**
* Page text content part.
*
- * @typedef {Object} BidiText
+ * @typedef {Object} TextItem
* @property {string} str - text content.
* @property {string} dir - text direction: 'ttb', 'ltr' or 'rtl'.
- * @property {number} x - x position of the text on the page.
- * @property {number} y - y position of the text on the page.
- * @property {number} angle - text rotation.
- * @property {number} size - font size.
+ * @property {array} transform - transformation matrix.
+ * @property {number} width - width in device space.
+ * @property {number} height - height in device space.
+ * @property {string} fontName - font name used by pdf.js for converted font.
+ */
+
+/**
+ * Text style.
+ *
+ * @typedef {Object} TextStyle
+ * @property {number} ascent - font ascent.
+ * @property {number} descent - font descent.
+ * @property {boolean} vertical - text is in vertical mode.
+ * @property {string} fontFamily - possible font family
+ */
+
+/**
+ * Page render parameters.
+ *
+ * @typedef {Object} RenderParameters
+ * @property {Object} canvasContext - A 2D context of a DOM Canvas object.
+ * @property {PDFJS.PageViewport} viewport - Rendering viewport obtained by
+ * calling of PDFPage.getViewport method.
+ * @property {string} intent - Rendering intent, can be 'display' or 'print'
+ * (default value is 'display').
+ * @property {Object} imageLayer - (optional) An object that has beginLayout,
+ * endLayout and appendImage functions.
+ * @property {function} continueCallback - (optional) A function that will be
+ * called each time the rendering is paused. To continue
+ * rendering call the function that is the first argument
+ * to the callback.
*/
/**
@@ -4130,7 +2725,8 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
* @class
*/
var PDFPageProxy = (function PDFPageProxyClosure() {
- function PDFPageProxy(pageInfo, transport) {
+ function PDFPageProxy(pageIndex, pageInfo, transport) {
+ this.pageIndex = pageIndex;
this.pageInfo = pageInfo;
this.transport = transport;
this.stats = new StatTimer();
@@ -4146,7 +2742,7 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
* @return {number} Page number of the page. First page is 1.
*/
get pageNumber() {
- return this.pageInfo.pageIndex + 1;
+ return this.pageIndex + 1;
},
/**
* @return {number} The number of degrees the page is rotated clockwise.
@@ -4172,8 +2768,8 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
* @param {number} scale The desired scale of the viewport.
* @param {number} rotate Degrees to rotate the viewport. If omitted this
* defaults to the page rotation.
- * @return {PageViewport} Contains 'width' and 'height' properties along
- * with transforms required for rendering.
+ * @return {PDFJS.PageViewport} Contains 'width' and 'height' properties
+ * along with transforms required for rendering.
*/
getViewport: function PDFPageProxy_getViewport(scale, rotate) {
if (arguments.length < 2) {
@@ -4190,27 +2786,15 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
return this.annotationsPromise;
}
- var promise = new PDFJS.LegacyPromise();
+ var promise = this.transport.getAnnotations(this.pageIndex);
this.annotationsPromise = promise;
- this.transport.getAnnotations(this.pageInfo.pageIndex);
return promise;
},
/**
* Begins the process of rendering a page to the desired context.
- * @param {Object} params A parameter object that supports:
- * {
- * canvasContext(required): A 2D context of a DOM Canvas object.,
- * textLayer(optional): An object that has beginLayout, endLayout, and
- * appendText functions.,
- * imageLayer(optional): An object that has beginLayout, endLayout and
- * appendImage functions.,
- * continueCallback(optional): A function that will be called each time
- * the rendering is paused. To continue
- * rendering call the function that is the
- * first argument to the callback.
- * }.
- * @return {RenderTask} An extended promise that is resolved when the page
- * finishes rendering (see RenderTask).
+ * @param {RenderParameters} params Page render parameters.
+ * @return {RenderTask} An object that contains the promise, which
+ * is resolved when the page finishes rendering.
*/
render: function PDFPageProxy_render(params) {
var stats = this.stats;
@@ -4228,11 +2812,11 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
}
var intentState = this.intentStates[renderingIntent];
- // If there is no displayReadyPromise yet, then the operatorList was never
- // requested before. Make the request and create the promise.
- if (!intentState.displayReadyPromise) {
+ // If there's no displayReadyCapability yet, then the operatorList
+ // was never requested before. Make the request and create the promise.
+ if (!intentState.displayReadyCapability) {
intentState.receivingOperatorList = true;
- intentState.displayReadyPromise = new LegacyPromise();
+ intentState.displayReadyCapability = createPromiseCapability();
intentState.operatorList = {
fnArray: [],
argsArray: [],
@@ -4258,7 +2842,7 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
var renderTask = new RenderTask(internalRenderTask);
var self = this;
- intentState.displayReadyPromise.then(
+ intentState.displayReadyCapability.promise.then(
function pageDisplayReadyPromise(transparency) {
if (self.pendingDestroy) {
complete();
@@ -4285,9 +2869,9 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
self._tryDestroy();
if (error) {
- renderTask.promise.reject(error);
+ internalRenderTask.capability.reject(error);
} else {
- renderTask.promise.resolve();
+ internalRenderTask.capability.resolve();
}
stats.timeEnd('Rendering');
stats.timeEnd('Overall');
@@ -4296,19 +2880,13 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
return renderTask;
},
/**
- * @return {Promise} That is resolved with the array of {@link BidiText}
- * objects that represent the page text content.
+ * @return {Promise} That is resolved a {@link TextContent}
+ * object that represent the page text content.
*/
getTextContent: function PDFPageProxy_getTextContent() {
- var promise = new PDFJS.LegacyPromise();
- this.transport.messageHandler.send('GetTextContent', {
- pageIndex: this.pageNumber - 1
- },
- function textContentCallback(textContent) {
- promise.resolve(textContent);
- }
- );
- return promise;
+ return this.transport.messageHandler.sendWithPromise('GetTextContent', {
+ pageIndex: this.pageNumber - 1
+ });
},
/**
* Destroys resources allocated by the page.
@@ -4336,6 +2914,7 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
delete this.intentStates[intent];
}, this);
this.objs.clear();
+ this.annotationsPromise = null;
this.pendingDestroy = false;
},
/**
@@ -4345,7 +2924,7 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
_startRenderPage: function PDFPageProxy_startRenderPage(transparency,
intent) {
var intentState = this.intentStates[intent];
- intentState.displayReadyPromise.resolve(transparency);
+ intentState.displayReadyCapability.resolve(transparency);
},
/**
* For internal use only.
@@ -4354,8 +2933,9 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
_renderPageChunk: function PDFPageProxy_renderPageChunk(operatorListChunk,
intent) {
var intentState = this.intentStates[intent];
+ var i, ii;
// Add the new chunk to the current operator list.
- for (var i = 0, ii = operatorListChunk.length; i < ii; i++) {
+ for (i = 0, ii = operatorListChunk.length; i < ii; i++) {
intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]);
intentState.operatorList.argsArray.push(
operatorListChunk.argsArray[i]);
@@ -4363,7 +2943,7 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
intentState.operatorList.lastChunk = operatorListChunk.lastChunk;
// Notify all the rendering tasks there are more operators to be consumed.
- for (var i = 0; i < intentState.renderTasks.length; i++) {
+ for (i = 0; i < intentState.renderTasks.length; i++) {
intentState.renderTasks[i].operatorListChanged();
}
@@ -4381,17 +2961,17 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
* @ignore
*/
var WorkerTransport = (function WorkerTransportClosure() {
- function WorkerTransport(workerInitializedPromise, workerReadyPromise,
+ function WorkerTransport(workerInitializedCapability, workerReadyCapability,
pdfDataRangeTransport, progressCallback) {
this.pdfDataRangeTransport = pdfDataRangeTransport;
- this.workerReadyPromise = workerReadyPromise;
+ this.workerReadyCapability = workerReadyCapability;
this.progressCallback = progressCallback;
this.commonObjs = new PDFObjects();
this.pageCache = [];
this.pagePromises = [];
- this.downloadInfoPromise = new PDFJS.LegacyPromise();
+ this.downloadInfoCapability = createPromiseCapability();
this.passwordCallback = null;
// If worker support isn't disabled explicit and the browser has worker
@@ -4420,12 +3000,12 @@ var WorkerTransport = (function WorkerTransportClosure() {
PDFJS.postMessageTransfers = false;
}
this.setupMessageHandler(messageHandler);
- workerInitializedPromise.resolve();
+ workerInitializedCapability.resolve();
} else {
globalScope.PDFJS.disableWorker = true;
this.loadFakeWorkerFiles().then(function() {
this.setupFakeWorker();
- workerInitializedPromise.resolve();
+ workerInitializedCapability.resolve();
}.bind(this));
}
}.bind(this));
@@ -4434,7 +3014,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
// Some versions of Opera throw a DATA_CLONE_ERR on serializing the
// typed array. Also, checking if we can use transfers.
try {
- messageHandler.send('test', testObj, null, [testObj.buffer]);
+ messageHandler.send('test', testObj, [testObj.buffer]);
} catch (ex) {
info('Cannot use postMessage transfers');
testObj[0] = 0;
@@ -4450,7 +3030,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
globalScope.PDFJS.disableWorker = true;
this.loadFakeWorkerFiles().then(function() {
this.setupFakeWorker();
- workerInitializedPromise.resolve();
+ workerInitializedCapability.resolve();
}.bind(this));
}
WorkerTransport.prototype = {
@@ -4458,7 +3038,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
this.pageCache = [];
this.pagePromises = [];
var self = this;
- this.messageHandler.send('Terminate', null, function () {
+ this.messageHandler.sendWithPromise('Terminate', null).then(function () {
FontLoader.clear();
if (self.worker) {
self.worker.terminate();
@@ -4467,16 +3047,16 @@ var WorkerTransport = (function WorkerTransportClosure() {
},
loadFakeWorkerFiles: function WorkerTransport_loadFakeWorkerFiles() {
- if (!PDFJS.fakeWorkerFilesLoadedPromise) {
- PDFJS.fakeWorkerFilesLoadedPromise = new LegacyPromise();
+ if (!PDFJS.fakeWorkerFilesLoadedCapability) {
+ PDFJS.fakeWorkerFilesLoadedCapability = createPromiseCapability();
// In the developer build load worker_loader which in turn loads all the
// other files and resolves the promise. In production only the
// pdf.worker.js file is needed.
Util.loadScript(PDFJS.workerSrc, function() {
- PDFJS.fakeWorkerFilesLoadedPromise.resolve();
+ PDFJS.fakeWorkerFilesLoadedCapability.resolve();
});
}
- return PDFJS.fakeWorkerFilesLoadedPromise;
+ return PDFJS.fakeWorkerFilesLoadedCapability.promise;
},
setupFakeWorker: function WorkerTransport_setupFakeWorker() {
@@ -4531,7 +3111,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
this.numPages = data.pdfInfo.numPages;
var pdfDocument = new PDFDocumentProxy(pdfInfo, this);
this.pdfDocument = pdfDocument;
- this.workerReadyPromise.resolve(pdfDocument);
+ this.workerReadyCapability.resolve(pdfDocument);
}, this);
messageHandler.on('NeedPassword', function transportPassword(data) {
@@ -4539,7 +3119,8 @@ var WorkerTransport = (function WorkerTransportClosure() {
return this.passwordCallback(updatePassword,
PasswordResponses.NEED_PASSWORD);
}
- this.workerReadyPromise.reject(data.exception.message, data.exception);
+ this.workerReadyCapability.reject(data.exception.message,
+ data.exception);
}, this);
messageHandler.on('IncorrectPassword', function transportBadPass(data) {
@@ -4547,37 +3128,26 @@ var WorkerTransport = (function WorkerTransportClosure() {
return this.passwordCallback(updatePassword,
PasswordResponses.INCORRECT_PASSWORD);
}
- this.workerReadyPromise.reject(data.exception.message, data.exception);
+ this.workerReadyCapability.reject(data.exception.message,
+ data.exception);
}, this);
messageHandler.on('InvalidPDF', function transportInvalidPDF(data) {
- this.workerReadyPromise.reject(data.exception.name, data.exception);
+ this.workerReadyCapability.reject(data.exception.name, data.exception);
}, this);
messageHandler.on('MissingPDF', function transportMissingPDF(data) {
- this.workerReadyPromise.reject(data.exception.message, data.exception);
+ this.workerReadyCapability.reject(data.exception.message,
+ data.exception);
}, this);
messageHandler.on('UnknownError', function transportUnknownError(data) {
- this.workerReadyPromise.reject(data.exception.message, data.exception);
+ this.workerReadyCapability.reject(data.exception.message,
+ data.exception);
}, this);
messageHandler.on('DataLoaded', function transportPage(data) {
- this.downloadInfoPromise.resolve(data);
- }, this);
-
- messageHandler.on('GetPage', function transportPage(data) {
- var pageInfo = data.pageInfo;
- var page = new PDFPageProxy(pageInfo, this);
- this.pageCache[pageInfo.pageIndex] = page;
- var promise = this.pagePromises[pageInfo.pageIndex];
- promise.resolve(page);
- }, this);
-
- messageHandler.on('GetAnnotations', function transportAnnotations(data) {
- var annotations = data.annotations;
- var promise = this.pageCache[data.pageIndex].annotationsPromise;
- promise.resolve(annotations);
+ this.downloadInfoCapability.resolve(data);
}, this);
messageHandler.on('StartRenderPage', function transportRender(data) {
@@ -4634,22 +3204,23 @@ var WorkerTransport = (function WorkerTransportClosure() {
var pageIndex = data[1];
var type = data[2];
var pageProxy = this.pageCache[pageIndex];
+ var imageData;
if (pageProxy.objs.hasData(id)) {
return;
}
switch (type) {
case 'JpegStream':
- var imageData = data[3];
+ imageData = data[3];
loadJpegStream(id, imageData, pageProxy.objs);
break;
case 'Image':
- var imageData = data[3];
+ imageData = data[3];
pageProxy.objs.resolve(id, imageData);
// heuristics that will allow not to store large data
var MAX_IMAGE_SIZE_TO_STORE = 8000000;
- if ('data' in imageData &&
+ if (imageData && 'data' in imageData &&
imageData.data.length > MAX_IMAGE_SIZE_TO_STORE) {
pageProxy.cleanupAfterRender = true;
}
@@ -4669,52 +3240,59 @@ var WorkerTransport = (function WorkerTransportClosure() {
}, this);
messageHandler.on('DocError', function transportDocError(data) {
- this.workerReadyPromise.reject(data);
+ this.workerReadyCapability.reject(data);
}, this);
- messageHandler.on('PageError', function transportError(data, intent) {
+ messageHandler.on('PageError', function transportError(data) {
var page = this.pageCache[data.pageNum - 1];
- var intentState = page.intentStates[intent];
- if (intentState.displayReadyPromise) {
- intentState.displayReadyPromise.reject(data.error);
+ var intentState = page.intentStates[data.intent];
+ if (intentState.displayReadyCapability.promise) {
+ intentState.displayReadyCapability.reject(data.error);
} else {
error(data.error);
}
}, this);
- messageHandler.on('JpegDecode', function(data, deferred) {
+ messageHandler.on('JpegDecode', function(data) {
var imageUrl = data[0];
var components = data[1];
if (components != 3 && components != 1) {
- error('Only 3 component or 1 component can be returned');
+ return Promise.reject(
+ new Error('Only 3 components or 1 component can be returned'));
}
- var img = new Image();
- img.onload = (function messageHandler_onloadClosure() {
- var width = img.width;
- var height = img.height;
- var size = width * height;
- var rgbaLength = size * 4;
- var buf = new Uint8Array(size * components);
- var tmpCanvas = createScratchCanvas(width, height);
- var tmpCtx = tmpCanvas.getContext('2d');
- tmpCtx.drawImage(img, 0, 0);
- var data = tmpCtx.getImageData(0, 0, width, height).data;
+ return new Promise(function (resolve, reject) {
+ var img = new Image();
+ img.onload = function () {
+ var width = img.width;
+ var height = img.height;
+ var size = width * height;
+ var rgbaLength = size * 4;
+ var buf = new Uint8Array(size * components);
+ var tmpCanvas = createScratchCanvas(width, height);
+ var tmpCtx = tmpCanvas.getContext('2d');
+ tmpCtx.drawImage(img, 0, 0);
+ var data = tmpCtx.getImageData(0, 0, width, height).data;
+ var i, j;
- if (components == 3) {
- for (var i = 0, j = 0; i < rgbaLength; i += 4, j += 3) {
- buf[j] = data[i];
- buf[j + 1] = data[i + 1];
- buf[j + 2] = data[i + 2];
- }
- } else if (components == 1) {
- for (var i = 0, j = 0; i < rgbaLength; i += 4, j++) {
- buf[j] = data[i];
+ if (components == 3) {
+ for (i = 0, j = 0; i < rgbaLength; i += 4, j += 3) {
+ buf[j] = data[i];
+ buf[j + 1] = data[i + 1];
+ buf[j + 2] = data[i + 2];
+ }
+ } else if (components == 1) {
+ for (i = 0, j = 0; i < rgbaLength; i += 4, j++) {
+ buf[j] = data[i];
+ }
}
- }
- deferred.resolve({ data: buf, width: width, height: height});
- }).bind(this);
- img.src = imageUrl;
+ resolve({ data: buf, width: width, height: height});
+ };
+ img.onerror = function () {
+ reject(new Error('JpegDecode failed to load image'));
+ };
+ img.src = imageUrl;
+ });
});
},
@@ -4726,74 +3304,85 @@ var WorkerTransport = (function WorkerTransportClosure() {
disableRange: PDFJS.disableRange,
maxImageSize: PDFJS.maxImageSize,
cMapUrl: PDFJS.cMapUrl,
+ cMapPacked: PDFJS.cMapPacked,
disableFontFace: PDFJS.disableFontFace,
disableCreateObjectURL: PDFJS.disableCreateObjectURL,
verbosity: PDFJS.verbosity
});
},
- getData: function WorkerTransport_getData(promise) {
- this.messageHandler.send('GetData', null, function(data) {
- promise.resolve(data);
- });
+ getData: function WorkerTransport_getData() {
+ return this.messageHandler.sendWithPromise('GetData', null);
},
- getPage: function WorkerTransport_getPage(pageNumber, promise) {
+ getPage: function WorkerTransport_getPage(pageNumber, capability) {
if (pageNumber <= 0 || pageNumber > this.numPages ||
(pageNumber|0) !== pageNumber) {
- var pagePromise = new PDFJS.LegacyPromise();
- pagePromise.reject(new Error('Invalid page request'));
- return pagePromise;
+ return Promise.reject(new Error('Invalid page request'));
}
var pageIndex = pageNumber - 1;
if (pageIndex in this.pagePromises) {
return this.pagePromises[pageIndex];
}
- var promise = new PDFJS.LegacyPromise();
+ var promise = this.messageHandler.sendWithPromise('GetPage', {
+ pageIndex: pageIndex
+ }).then(function (pageInfo) {
+ var page = new PDFPageProxy(pageIndex, pageInfo, this);
+ this.pageCache[pageIndex] = page;
+ return page;
+ }.bind(this));
this.pagePromises[pageIndex] = promise;
- this.messageHandler.send('GetPageRequest', { pageIndex: pageIndex });
return promise;
},
getPageIndex: function WorkerTransport_getPageIndexByRef(ref) {
- var promise = new PDFJS.LegacyPromise();
- this.messageHandler.send('GetPageIndex', { ref: ref },
- function (pageIndex) {
- promise.resolve(pageIndex);
- }
- );
- return promise;
+ return this.messageHandler.sendWithPromise('GetPageIndex', { ref: ref });
},
getAnnotations: function WorkerTransport_getAnnotations(pageIndex) {
- this.messageHandler.send('GetAnnotationsRequest',
+ return this.messageHandler.sendWithPromise('GetAnnotations',
{ pageIndex: pageIndex });
},
getDestinations: function WorkerTransport_getDestinations() {
- var promise = new PDFJS.LegacyPromise();
- this.messageHandler.send('GetDestinations', null,
- function transportDestinations(destinations) {
- promise.resolve(destinations);
- }
- );
- return promise;
+ return this.messageHandler.sendWithPromise('GetDestinations', null);
+ },
+
+ getAttachments: function WorkerTransport_getAttachments() {
+ return this.messageHandler.sendWithPromise('GetAttachments', null);
+ },
+
+ getJavaScript: function WorkerTransport_getJavaScript() {
+ return this.messageHandler.sendWithPromise('GetJavaScript', null);
+ },
+
+ getOutline: function WorkerTransport_getOutline() {
+ return this.messageHandler.sendWithPromise('GetOutline', null);
+ },
+
+ getMetadata: function WorkerTransport_getMetadata() {
+ return this.messageHandler.sendWithPromise('GetMetadata', null).
+ then(function transportMetadata(results) {
+ return {
+ info: results[0],
+ metadata: (results[1] ? new PDFJS.Metadata(results[1]) : null)
+ };
+ });
},
startCleanup: function WorkerTransport_startCleanup() {
- this.messageHandler.send('Cleanup', null,
- function endCleanup() {
- for (var i = 0, ii = this.pageCache.length; i < ii; i++) {
- var page = this.pageCache[i];
- if (page) {
- page.destroy();
- }
+ this.messageHandler.sendWithPromise('Cleanup', null).
+ then(function endCleanup() {
+ for (var i = 0, ii = this.pageCache.length; i < ii; i++) {
+ var page = this.pageCache[i];
+ if (page) {
+ page.destroy();
}
- this.commonObjs.clear();
- FontLoader.clear();
- }.bind(this)
- );
+ }
+ this.commonObjs.clear();
+ FontLoader.clear();
+ }.bind(this));
}
};
return WorkerTransport;
@@ -4823,7 +3412,7 @@ var PDFObjects = (function PDFObjectsClosure() {
}
var obj = {
- promise: new LegacyPromise(),
+ capability: createPromiseCapability(),
data: null,
resolved: false
};
@@ -4845,7 +3434,7 @@ var PDFObjects = (function PDFObjectsClosure() {
// If there is a callback, then the get can be async and the object is
// not required to be resolved right now
if (callback) {
- this.ensureObj(objId).promise.then(callback);
+ this.ensureObj(objId).capability.promise.then(callback);
return null;
}
@@ -4870,7 +3459,7 @@ var PDFObjects = (function PDFObjectsClosure() {
obj.resolved = true;
obj.data = data;
- obj.promise.resolve(data);
+ obj.capability.resolve(data);
},
isResolved: function PDFObjects_isResolved(objId) {
@@ -4917,7 +3506,7 @@ var RenderTask = (function RenderTaskClosure() {
* Promise for rendering task completion.
* @type {Promise}
*/
- this.promise = new PDFJS.LegacyPromise();
+ this.promise = this.internalRenderTask.capability.promise;
}
RenderTask.prototype = /** @lends RenderTask.prototype */ {
@@ -4928,7 +3517,18 @@ var RenderTask = (function RenderTaskClosure() {
*/
cancel: function RenderTask_cancel() {
this.internalRenderTask.cancel();
- this.promise.reject(new Error('Rendering is cancelled'));
+ },
+
+ /**
+ * Registers callback to indicate the rendering task completion.
+ *
+ * @param {function} onFulfilled The callback for the rendering completion.
+ * @param {function} onRejected The callback for the rendering failure.
+ * @return {Promise} A promise that is resolved after the onFulfilled or
+ * onRejected callback.
+ */
+ then: function RenderTask_then(onFulfilled, onRejected) {
+ return this.promise.then(onFulfilled, onRejected);
}
};
@@ -4954,6 +3554,11 @@ var InternalRenderTask = (function InternalRenderTaskClosure() {
this.graphicsReadyCallback = null;
this.graphicsReady = false;
this.cancelled = false;
+ this.capability = createPromiseCapability();
+ // caching this-bound methods
+ this._continueBound = this._continue.bind(this);
+ this._scheduleNextBound = this._scheduleNext.bind(this);
+ this._nextBound = this._next.bind(this);
}
InternalRenderTask.prototype = {
@@ -4973,8 +3578,7 @@ var InternalRenderTask = (function InternalRenderTaskClosure() {
var params = this.params;
this.gfx = new CanvasGraphics(params.canvasContext, this.commonObjs,
- this.objs, params.textLayer,
- params.imageLayer);
+ this.objs, params.imageLayer);
this.gfx.beginDrawing(params.viewport, transparency);
this.operatorListIdx = 0;
@@ -4993,7 +3597,7 @@ var InternalRenderTask = (function InternalRenderTaskClosure() {
operatorListChanged: function InternalRenderTask_operatorListChanged() {
if (!this.graphicsReady) {
if (!this.graphicsReadyCallback) {
- this.graphicsReadyCallback = this._continue.bind(this);
+ this.graphicsReadyCallback = this._continueBound;
}
return;
}
@@ -5014,19 +3618,23 @@ var InternalRenderTask = (function InternalRenderTaskClosure() {
return;
}
if (this.params.continueCallback) {
- this.params.continueCallback(this._next.bind(this));
+ this.params.continueCallback(this._scheduleNextBound);
} else {
- this._next();
+ this._scheduleNext();
}
},
+ _scheduleNext: function InternalRenderTask__scheduleNext() {
+ window.requestAnimationFrame(this._nextBound);
+ },
+
_next: function InternalRenderTask__next() {
if (this.cancelled) {
return;
}
this.operatorListIdx = this.gfx.executeOperatorList(this.operatorList,
this.operatorListIdx,
- this._continue.bind(this),
+ this._continueBound,
this.stepper);
if (this.operatorListIdx === this.operatorList.argsArray.length) {
this.running = false;
@@ -5129,6 +3737,7 @@ var Metadata = PDFJS.Metadata = (function MetadataClosure() {
// Minimal font size that would be used during canvas fillText operations.
var MIN_FONT_SIZE = 16;
+var MAX_GROUP_SIZE = 4096;
var COMPILE_TYPE3_GLYPHS = true;
@@ -5453,6 +4062,7 @@ var CanvasExtraState = (function CanvasExtraStateClosure() {
this.fontSize = 0;
this.fontSizeScale = 1;
this.textMatrix = IDENTITY_MATRIX;
+ this.textMatrixScale = 1;
this.fontMatrix = FONT_IDENTITY_MATRIX;
this.leading = 0;
// Current point (in user coordinates)
@@ -5467,13 +4077,6 @@ var CanvasExtraState = (function CanvasExtraStateClosure() {
this.textHScale = 1;
this.textRenderingMode = TextRenderingMode.FILL;
this.textRise = 0;
- // Color spaces
- this.fillColorSpace = ColorSpace.singletons.gray;
- this.fillColorSpaceObj = null;
- this.strokeColorSpace = ColorSpace.singletons.gray;
- this.strokeColorSpaceObj = null;
- this.fillColorObj = null;
- this.strokeColorObj = null;
// Default fore and background colors
this.fillColor = '#000000';
this.strokeColor = '#000000';
@@ -5503,7 +4106,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
// before it stops and shedules a continue of execution.
var EXECUTION_TIME = 15;
- function CanvasGraphics(canvasCtx, commonObjs, objs, textLayer, imageLayer) {
+ function CanvasGraphics(canvasCtx, commonObjs, objs, imageLayer) {
this.ctx = canvasCtx;
this.current = new CanvasExtraState();
this.stateStack = [];
@@ -5513,7 +4116,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.xobjs = null;
this.commonObjs = commonObjs;
this.objs = objs;
- this.textLayer = textLayer;
this.imageLayer = imageLayer;
this.groupStack = [];
this.processingType3 = null;
@@ -5555,83 +4157,92 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
var partialChunkHeight = height - fullChunks * fullChunkHeight;
var chunkImgData = ctx.createImageData(width, fullChunkHeight);
- var srcPos = 0;
+ var srcPos = 0, destPos;
var src = imgData.data;
var dest = chunkImgData.data;
+ var i, j, thisChunkHeight, elemsInThisChunk;
// There are multiple forms in which the pixel data can be passed, and
// imgData.kind tells us which one this is.
-
if (imgData.kind === ImageKind.GRAYSCALE_1BPP) {
// Grayscale, 1 bit per pixel (i.e. black-and-white).
- var destDataLength = dest.length;
var srcLength = src.byteLength;
- for (var i = 3; i < destDataLength; i += 4) {
- dest[i] = 255;
- }
- for (var i = 0; i < totalChunks; i++) {
- var thisChunkHeight =
+ var dest32 = PDFJS.hasCanvasTypedArrays ? new Uint32Array(dest.buffer) :
+ new Uint32ArrayView(dest);
+ var dest32DataLength = dest32.length;
+ var fullSrcDiff = (width + 7) >> 3;
+ var white = 0xFFFFFFFF;
+ var black = (PDFJS.isLittleEndian || !PDFJS.hasCanvasTypedArrays) ?
+ 0xFF000000 : 0x000000FF;
+ for (i = 0; i < totalChunks; i++) {
+ thisChunkHeight =
(i < fullChunks) ? fullChunkHeight : partialChunkHeight;
- var destPos = 0;
- for (var j = 0; j < thisChunkHeight; j++) {
+ destPos = 0;
+ for (j = 0; j < thisChunkHeight; j++) {
+ var srcDiff = srcLength - srcPos;
+ var k = 0;
+ var kEnd = (srcDiff > fullSrcDiff) ? width : srcDiff * 8 - 7;
+ var kEndUnrolled = kEnd & ~7;
var mask = 0;
var srcByte = 0;
- for (var k = 0; k < width; k++, destPos += 4) {
- if (mask === 0) {
- if (srcPos >= srcLength) {
- break;
- }
- srcByte = src[srcPos++];
- mask = 128;
- }
-
- if ((srcByte & mask)) {
- dest[destPos] = 255;
- dest[destPos + 1] = 255;
- dest[destPos + 2] = 255;
- } else {
- dest[destPos] = 0;
- dest[destPos + 1] = 0;
- dest[destPos + 2] = 0;
- }
+ for (; k < kEndUnrolled; k += 8) {
+ srcByte = src[srcPos++];
+ dest32[destPos++] = (srcByte & 128) ? white : black;
+ dest32[destPos++] = (srcByte & 64) ? white : black;
+ dest32[destPos++] = (srcByte & 32) ? white : black;
+ dest32[destPos++] = (srcByte & 16) ? white : black;
+ dest32[destPos++] = (srcByte & 8) ? white : black;
+ dest32[destPos++] = (srcByte & 4) ? white : black;
+ dest32[destPos++] = (srcByte & 2) ? white : black;
+ dest32[destPos++] = (srcByte & 1) ? white : black;
+ }
+ for (; k < kEnd; k++) {
+ if (mask === 0) {
+ srcByte = src[srcPos++];
+ mask = 128;
+ }
+ dest32[destPos++] = (srcByte & mask) ? white : black;
mask >>= 1;
}
}
- if (destPos < destDataLength) {
- // We ran out of input. Make all remaining pixels transparent.
- destPos += 3;
- do {
- dest[destPos] = 0;
- destPos += 4;
- } while (destPos < destDataLength);
+ // We ran out of input. Make all remaining pixels transparent.
+ while (destPos < dest32DataLength) {
+ dest32[destPos++] = 0;
}
ctx.putImageData(chunkImgData, 0, i * fullChunkHeight);
}
-
} else if (imgData.kind === ImageKind.RGBA_32BPP) {
// RGBA, 32-bits per pixel.
- for (var i = 0; i < totalChunks; i++) {
- var thisChunkHeight =
- (i < fullChunks) ? fullChunkHeight : partialChunkHeight;
- var elemsInThisChunk = imgData.width * thisChunkHeight * 4;
-
+ j = 0;
+ elemsInThisChunk = width * fullChunkHeight * 4;
+ for (i = 0; i < fullChunks; i++) {
dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
srcPos += elemsInThisChunk;
- ctx.putImageData(chunkImgData, 0, i * fullChunkHeight);
+ ctx.putImageData(chunkImgData, 0, j);
+ j += fullChunkHeight;
+ }
+ if (i < totalChunks) {
+ elemsInThisChunk = width * partialChunkHeight * 4;
+ dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
+ ctx.putImageData(chunkImgData, 0, j);
}
} else if (imgData.kind === ImageKind.RGB_24BPP) {
// RGB, 24-bits per pixel.
- for (var i = 0; i < totalChunks; i++) {
- var thisChunkHeight =
- (i < fullChunks) ? fullChunkHeight : partialChunkHeight;
- var elemsInThisChunk = imgData.width * thisChunkHeight * 3;
- var destPos = 0;
- for (var j = 0; j < elemsInThisChunk; j += 3) {
+ thisChunkHeight = fullChunkHeight;
+ elemsInThisChunk = width * thisChunkHeight;
+ for (i = 0; i < totalChunks; i++) {
+ if (i >= fullChunks) {
+ thisChunkHeight =partialChunkHeight;
+ elemsInThisChunk = width * thisChunkHeight;
+ }
+
+ destPos = 0;
+ for (j = elemsInThisChunk; j--;) {
dest[destPos++] = src[srcPos++];
dest[destPos++] = src[srcPos++];
dest[destPos++] = src[srcPos++];
@@ -5639,9 +4250,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
ctx.putImageData(chunkImgData, 0, i * fullChunkHeight);
}
-
} else {
- error('bad image kind: ' + imgData.kind);
+ error('bad image kind: ' + imgData.kind);
}
}
@@ -5700,15 +4310,10 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
}
- function composeSMask(ctx, smask, layerCtx) {
- var mask = smask.canvas;
- var maskCtx = smask.context;
- var width = mask.width, height = mask.height;
-
+ function genericComposeSMask(maskCtx, layerCtx, width, height,
+ subtype, backdrop) {
var addBackdropFn;
- if (smask.backdrop) {
- var cs = smask.colorSpace || ColorSpace.singletons.rgb;
- var backdrop = cs.getRgb(smask.backdrop, 0);
+ if (backdrop) {
addBackdropFn = function (r0, g0, b0, bytes) {
var length = bytes.length;
for (var i = 3; i < length; i += 4) {
@@ -5730,7 +4335,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
var composeFn;
- if (smask.subtype === 'Luminosity') {
+ if (subtype === 'Luminosity') {
composeFn = function (maskDataBytes, layerDataBytes) {
var length = maskDataBytes.length;
for (var i = 3; i < length; i += 4) {
@@ -5751,7 +4356,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
// processing image in chunks to save memory
- var chunkSize = 16;
+ var PIXELS_TO_PROCESS = 65536;
+ var chunkSize = Math.min(height, Math.ceil(PIXELS_TO_PROCESS / width));
for (var row = 0; row < height; row += chunkSize) {
var chunkHeight = Math.min(chunkSize, height - row);
var maskData = maskCtx.getImageData(0, row, width, chunkHeight);
@@ -5762,9 +4368,26 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
maskCtx.putImageData(layerData, 0, row);
}
+ }
- ctx.setTransform(1, 0, 0, 1, 0, 0);
- ctx.drawImage(mask, smask.offsetX, smask.offsetY);
+ function composeSMask(ctx, smask, layerCtx) {
+ var mask = smask.canvas;
+ var maskCtx = smask.context;
+
+ ctx.setTransform(smask.scaleX, 0, 0, smask.scaleY,
+ smask.offsetX, smask.offsetY);
+
+ var backdrop = smask.backdrop || null;
+ if (WebGLUtils.isEnabled) {
+ var composed = WebGLUtils.composeSMask(layerCtx.canvas, mask,
+ {subtype: smask.subtype, backdrop: backdrop});
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
+ ctx.drawImage(composed, smask.offsetX, smask.offsetY);
+ return;
+ }
+ genericComposeSMask(maskCtx, layerCtx, mask.width, mask.height,
+ smask.subtype, backdrop);
+ ctx.drawImage(mask, 0, 0);
}
var LINE_CAP_STYLES = ['butt', 'round', 'square'];
@@ -5799,9 +4422,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.baseTransform = this.ctx.mozCurrentTransform.slice();
- if (this.textLayer) {
- this.textLayer.beginLayout();
- }
if (this.imageLayer) {
this.imageLayer.beginLayout();
}
@@ -5821,13 +4441,11 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
return i;
}
- var executionEndIdx;
var endTime = Date.now() + EXECUTION_TIME;
var commonObjs = this.commonObjs;
var objs = this.objs;
var fnId;
- var deferred = Promise.resolve();
while (true) {
if (stepper && i === stepper.nextBreakPoint) {
@@ -5865,11 +4483,10 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
return i;
}
- // If the execution took longer then a certain amount of time, schedule
- // to continue exeution after a short delay.
- // However, this is only possible if a 'continueCallback' is passed in.
+ // If the execution took longer then a certain amount of time and
+ // `continueCallback` is specified, interrupt the execution.
if (continueCallback && Date.now() > endTime) {
- deferred.then(continueCallback);
+ continueCallback();
return i;
}
@@ -5881,10 +4498,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
endDrawing: function CanvasGraphics_endDrawing() {
this.ctx.restore();
CachedCanvases.clear();
+ WebGLUtils.clear();
- if (this.textLayer) {
- this.textLayer.endLayout();
- }
if (this.imageLayer) {
this.imageLayer.endLayout();
}
@@ -6004,6 +4619,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.ctx.save();
var groupCtx = scratchCanvas.context;
+ groupCtx.scale(1 / activeSMask.scaleX, 1 / activeSMask.scaleY);
groupCtx.translate(-activeSMask.offsetX, -activeSMask.offsetY);
groupCtx.transform.apply(groupCtx, currentTransform);
@@ -6050,31 +4666,60 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
},
// Path
- moveTo: function CanvasGraphics_moveTo(x, y) {
- this.ctx.moveTo(x, y);
- this.current.setCurrentPoint(x, y);
- },
- lineTo: function CanvasGraphics_lineTo(x, y) {
- this.ctx.lineTo(x, y);
- this.current.setCurrentPoint(x, y);
- },
- curveTo: function CanvasGraphics_curveTo(x1, y1, x2, y2, x3, y3) {
- this.ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);
- this.current.setCurrentPoint(x3, y3);
- },
- curveTo2: function CanvasGraphics_curveTo2(x2, y2, x3, y3) {
+ constructPath: function CanvasGraphics_constructPath(ops, args) {
+ var ctx = this.ctx;
var current = this.current;
- this.ctx.bezierCurveTo(current.x, current.y, x2, y2, x3, y3);
- current.setCurrentPoint(x3, y3);
- },
- curveTo3: function CanvasGraphics_curveTo3(x1, y1, x3, y3) {
- this.curveTo(x1, y1, x3, y3, x3, y3);
- this.current.setCurrentPoint(x3, y3);
+ var x = current.x, y = current.y;
+ for (var i = 0, j = 0, ii = ops.length; i < ii; i++) {
+ switch (ops[i] | 0) {
+ case OPS.moveTo:
+ x = args[j++];
+ y = args[j++];
+ ctx.moveTo(x, y);
+ break;
+ case OPS.lineTo:
+ x = args[j++];
+ y = args[j++];
+ ctx.lineTo(x, y);
+ break;
+ case OPS.curveTo:
+ x = args[j + 4];
+ y = args[j + 5];
+ ctx.bezierCurveTo(args[j], args[j + 1], args[j + 2], args[j + 3],
+ x, y);
+ j += 6;
+ break;
+ case OPS.curveTo2:
+ ctx.bezierCurveTo(x, y, args[j], args[j + 1],
+ args[j + 2], args[j + 3]);
+ x = args[j + 2];
+ y = args[j + 3];
+ j += 4;
+ break;
+ case OPS.curveTo3:
+ x = args[j + 2];
+ y = args[j + 3];
+ ctx.bezierCurveTo(args[j], args[j + 1], x, y, x, y);
+ j += 4;
+ break;
+ case OPS.closePath:
+ ctx.closePath();
+ break;
+ }
+ }
+ current.setCurrentPoint(x, y);
},
closePath: function CanvasGraphics_closePath() {
this.ctx.closePath();
},
rectangle: function CanvasGraphics_rectangle(x, y, width, height) {
+ if (width === 0) {
+ width = this.getSinglePixelWidth();
+ }
+ if (height === 0) {
+ height = this.getSinglePixelWidth();
+ }
+
this.ctx.rect(x, y, width, height);
},
stroke: function CanvasGraphics_stroke(consumePath) {
@@ -6122,21 +4767,21 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
if (this.pendingEOFill) {
- if ('mozFillRule' in this.ctx) {
- this.ctx.mozFillRule = 'evenodd';
- this.ctx.fill();
- this.ctx.mozFillRule = 'nonzero';
+ if (ctx.mozFillRule !== undefined) {
+ ctx.mozFillRule = 'evenodd';
+ ctx.fill();
+ ctx.mozFillRule = 'nonzero';
} else {
try {
- this.ctx.fill('evenodd');
+ ctx.fill('evenodd');
} catch (ex) {
// shouldn't really happen, but browsers might think differently
- this.ctx.fill();
+ ctx.fill();
}
}
this.pendingEOFill = false;
} else {
- this.ctx.fill();
+ ctx.fill();
}
if (needRestore) {
@@ -6184,16 +4829,17 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
// Text
beginText: function CanvasGraphics_beginText() {
this.current.textMatrix = IDENTITY_MATRIX;
+ this.current.textMatrixScale = 1;
this.current.x = this.current.lineX = 0;
this.current.y = this.current.lineY = 0;
},
endText: function CanvasGraphics_endText() {
- if (!('pendingTextPaths' in this)) {
- this.ctx.beginPath();
- return;
- }
var paths = this.pendingTextPaths;
var ctx = this.ctx;
+ if (paths === undefined) {
+ ctx.beginPath();
+ return;
+ }
ctx.save();
ctx.beginPath();
@@ -6250,7 +4896,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.current.font = fontObj;
this.current.fontSize = size;
- if (fontObj.coded) {
+ if (fontObj.isType3Font) {
return; // we don't need ctx.font for Type3 fonts
}
@@ -6288,6 +4934,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
},
setTextMatrix: function CanvasGraphics_setTextMatrix(a, b, c, d, e, f) {
this.current.textMatrix = [a, b, c, d, e, f];
+ this.current.textMatrixScale = Math.sqrt(a * a + b * b);
this.current.x = this.current.lineX = 0;
this.current.y = this.current.lineY = 0;
@@ -6295,51 +4942,13 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
nextLine: function CanvasGraphics_nextLine() {
this.moveText(0, this.current.leading);
},
- applyTextTransforms: function CanvasGraphics_applyTextTransforms() {
- var ctx = this.ctx;
- var current = this.current;
- ctx.transform.apply(ctx, current.textMatrix);
- ctx.translate(current.x, current.y + current.textRise);
- if (current.fontDirection > 0) {
- ctx.scale(current.textHScale, -1);
- } else {
- ctx.scale(-current.textHScale, 1);
- }
- },
- createTextGeometry: function CanvasGraphics_createTextGeometry() {
- var geometry = {};
- var ctx = this.ctx;
- var font = this.current.font;
- var ctxMatrix = ctx.mozCurrentTransform;
- var a = ctxMatrix[0], b = ctxMatrix[1], c = ctxMatrix[2];
- var d = ctxMatrix[3], e = ctxMatrix[4], f = ctxMatrix[5];
- var sx = (a >= 0) ?
- Math.sqrt((a * a) + (b * b)) : -Math.sqrt((a * a) + (b * b));
- var sy = (d >= 0) ?
- Math.sqrt((c * c) + (d * d)) : -Math.sqrt((c * c) + (d * d));
- var angle = Math.atan2(b, a);
- var x = e;
- var y = f;
- geometry.x = x;
- geometry.y = y;
- geometry.hScale = sx;
- geometry.vScale = sy;
- geometry.angle = angle;
- geometry.spaceWidth = font.spaceWidth;
- geometry.fontName = font.loadedName;
- geometry.fontFamily = font.fallbackName;
- geometry.fontSize = this.current.fontSize;
- geometry.ascent = font.ascent;
- geometry.descent = font.descent;
- return geometry;
- },
- paintChar: function (character, x, y) {
+ paintChar: function CanvasGraphics_paintChar(character, x, y) {
var ctx = this.ctx;
var current = this.current;
var font = current.font;
- var fontSize = current.fontSize / current.fontSizeScale;
var textRenderingMode = current.textRenderingMode;
+ var fontSize = current.fontSize / current.fontSizeScale;
var fillStrokeMode = textRenderingMode &
TextRenderingMode.FILL_STROKE_MASK;
var isAddToPathSet = !!(textRenderingMode &
@@ -6404,236 +5013,183 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
return shadow(this, 'isFontSubpixelAAEnabled', enabled);
},
- showText: function CanvasGraphics_showText(glyphs, skipTextSelection) {
- var ctx = this.ctx;
+ showText: function CanvasGraphics_showText(glyphs) {
var current = this.current;
var font = current.font;
+ if (font.isType3Font) {
+ return this.showType3Text(glyphs);
+ }
+
var fontSize = current.fontSize;
+ if (fontSize === 0) {
+ return;
+ }
+
+ var ctx = this.ctx;
var fontSizeScale = current.fontSizeScale;
var charSpacing = current.charSpacing;
var wordSpacing = current.wordSpacing;
- var textHScale = current.textHScale * current.fontDirection;
- var fontMatrix = current.fontMatrix || FONT_IDENTITY_MATRIX;
+ var fontDirection = current.fontDirection;
+ var textHScale = current.textHScale * fontDirection;
var glyphsLength = glyphs.length;
- var textLayer = this.textLayer;
- var geom;
- var textSelection = textLayer && !skipTextSelection ? true : false;
- var canvasWidth = 0.0;
var vertical = font.vertical;
var defaultVMetrics = font.defaultVMetrics;
+ var widthAdvanceScale = fontSize * current.fontMatrix[0];
- // Type3 fonts - each glyph is a "mini-PDF"
- if (font.coded) {
- ctx.save();
- ctx.transform.apply(ctx, current.textMatrix);
- ctx.translate(current.x, current.y);
-
- ctx.scale(textHScale, 1);
+ var simpleFillText =
+ current.textRenderingMode === TextRenderingMode.FILL &&
+ !font.disableFontFace;
- if (textSelection) {
- this.save();
- ctx.scale(1, -1);
- geom = this.createTextGeometry();
- this.restore();
- }
- for (var i = 0; i < glyphsLength; ++i) {
+ ctx.save();
+ ctx.transform.apply(ctx, current.textMatrix);
+ ctx.translate(current.x, current.y + current.textRise);
- var glyph = glyphs[i];
- if (glyph === null) {
- // word break
- this.ctx.translate(wordSpacing, 0);
- current.x += wordSpacing * textHScale;
- continue;
- }
+ if (fontDirection > 0) {
+ ctx.scale(textHScale, -1);
+ } else {
+ ctx.scale(textHScale, 1);
+ }
- this.processingType3 = glyph;
- this.save();
- ctx.scale(fontSize, fontSize);
- ctx.transform.apply(ctx, fontMatrix);
- this.executeOperatorList(glyph.operatorList);
- this.restore();
+ var lineWidth = current.lineWidth;
+ var scale = current.textMatrixScale;
+ if (scale === 0 || lineWidth === 0) {
+ lineWidth = this.getSinglePixelWidth();
+ } else {
+ lineWidth /= scale;
+ }
- var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
- var width = (transformed[0] * fontSize + charSpacing) *
- current.fontDirection;
+ if (fontSizeScale != 1.0) {
+ ctx.scale(fontSizeScale, fontSizeScale);
+ lineWidth /= fontSizeScale;
+ }
- ctx.translate(width, 0);
- current.x += width * textHScale;
+ ctx.lineWidth = lineWidth;
- canvasWidth += width;
+ var x = 0, i;
+ for (i = 0; i < glyphsLength; ++i) {
+ var glyph = glyphs[i];
+ if (glyph === null) {
+ // word break
+ x += fontDirection * wordSpacing;
+ continue;
+ } else if (isNum(glyph)) {
+ x += -glyph * fontSize * 0.001;
+ continue;
}
- ctx.restore();
- this.processingType3 = null;
- } else {
- ctx.save();
- this.applyTextTransforms();
- var lineWidth = current.lineWidth;
- var a1 = current.textMatrix[0], b1 = current.textMatrix[1];
- var scale = Math.sqrt(a1 * a1 + b1 * b1);
- if (scale === 0 || lineWidth === 0) {
- lineWidth = this.getSinglePixelWidth();
- } else {
- lineWidth /= scale;
- }
+ var restoreNeeded = false;
+ var character = glyph.fontChar;
+ var accent = glyph.accent;
+ var scaledX, scaledY, scaledAccentX, scaledAccentY;
+ var width = glyph.width;
+ if (vertical) {
+ var vmetric, vx, vy;
+ vmetric = glyph.vmetric || defaultVMetrics;
+ vx = glyph.vmetric ? vmetric[1] : width * 0.5;
+ vx = -vx * widthAdvanceScale;
+ vy = vmetric[2] * widthAdvanceScale;
- if (textSelection) {
- geom = this.createTextGeometry();
+ width = vmetric ? -vmetric[0] : width;
+ scaledX = vx / fontSizeScale;
+ scaledY = (x + vy) / fontSizeScale;
+ } else {
+ scaledX = x / fontSizeScale;
+ scaledY = 0;
}
- if (fontSizeScale != 1.0) {
- ctx.scale(fontSizeScale, fontSizeScale);
- lineWidth /= fontSizeScale;
+ if (font.remeasure && width > 0 && this.isFontSubpixelAAEnabled) {
+ // some standard fonts may not have the exact width, trying to
+ // rescale per character
+ var measuredWidth = ctx.measureText(character).width * 1000 /
+ fontSize * fontSizeScale;
+ var characterScaleX = width / measuredWidth;
+ restoreNeeded = true;
+ ctx.save();
+ ctx.scale(characterScaleX, 1);
+ scaledX /= characterScaleX;
}
- ctx.lineWidth = lineWidth;
-
- var x = 0;
- for (var i = 0; i < glyphsLength; ++i) {
- var glyph = glyphs[i];
- if (glyph === null) {
- // word break
- x += current.fontDirection * wordSpacing;
- continue;
- }
-
- var restoreNeeded = false;
- var character = glyph.fontChar;
- var vmetric = glyph.vmetric || defaultVMetrics;
- if (vertical) {
- var vx = glyph.vmetric ? vmetric[1] : glyph.width * 0.5;
- vx = -vx * fontSize * current.fontMatrix[0];
- var vy = vmetric[2] * fontSize * current.fontMatrix[0];
- }
- var width = vmetric ? -vmetric[0] : glyph.width;
- var charWidth = width * fontSize * current.fontMatrix[0] +
- charSpacing * current.fontDirection;
- var accent = glyph.accent;
-
- var scaledX, scaledY, scaledAccentX, scaledAccentY;
-
- if (vertical) {
- scaledX = vx / fontSizeScale;
- scaledY = (x + vy) / fontSizeScale;
- } else {
- scaledX = x / fontSizeScale;
- scaledY = 0;
- }
-
- if (font.remeasure && width > 0 && this.isFontSubpixelAAEnabled) {
- // some standard fonts may not have the exact width, trying to
- // rescale per character
- var measuredWidth = ctx.measureText(character).width * 1000 /
- current.fontSize * current.fontSizeScale;
- var characterScaleX = width / measuredWidth;
- restoreNeeded = true;
- ctx.save();
- ctx.scale(characterScaleX, 1);
- scaledX /= characterScaleX;
- if (accent) {
- scaledAccentX /= characterScaleX;
- }
- }
-
+ if (simpleFillText && !accent) {
+ // common case
+ ctx.fillText(character, scaledX, scaledY);
+ } else {
this.paintChar(character, scaledX, scaledY);
if (accent) {
scaledAccentX = scaledX + accent.offset.x / fontSizeScale;
scaledAccentY = scaledY - accent.offset.y / fontSizeScale;
this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY);
}
+ }
- x += charWidth;
-
- canvasWidth += charWidth;
+ var charWidth = width * widthAdvanceScale + charSpacing * fontDirection;
+ x += charWidth;
- if (restoreNeeded) {
- ctx.restore();
- }
+ if (restoreNeeded) {
+ ctx.restore();
}
- if (vertical) {
- current.y -= x * textHScale;
- } else {
- current.x += x * textHScale;
- }
- ctx.restore();
}
-
- if (textSelection) {
- geom.canvasWidth = canvasWidth;
- if (vertical) {
- var VERTICAL_TEXT_ROTATION = Math.PI / 2;
- geom.angle += VERTICAL_TEXT_ROTATION;
- }
- this.textLayer.appendText(geom);
+ if (vertical) {
+ current.y -= x * textHScale;
+ } else {
+ current.x += x * textHScale;
}
-
- return canvasWidth;
+ ctx.restore();
},
- showSpacedText: function CanvasGraphics_showSpacedText(arr) {
+
+ showType3Text: function CanvasGraphics_showType3Text(glyphs) {
+ // Type3 fonts - each glyph is a "mini-PDF"
var ctx = this.ctx;
var current = this.current;
var font = current.font;
var fontSize = current.fontSize;
- // TJ array's number is independent from fontMatrix
- var textHScale = current.textHScale * 0.001 * current.fontDirection;
- var arrLength = arr.length;
- var textLayer = this.textLayer;
- var geom;
- var canvasWidth = 0.0;
- var textSelection = textLayer ? true : false;
- var vertical = font.vertical;
- var spacingAccumulator = 0;
+ var fontDirection = current.fontDirection;
+ var charSpacing = current.charSpacing;
+ var wordSpacing = current.wordSpacing;
+ var textHScale = current.textHScale * fontDirection;
+ var fontMatrix = current.fontMatrix || FONT_IDENTITY_MATRIX;
+ var glyphsLength = glyphs.length;
+ var i, glyph, width;
- if (textSelection) {
- ctx.save();
- this.applyTextTransforms();
- geom = this.createTextGeometry();
- ctx.restore();
+ if (fontSize === 0) {
+ return;
}
- for (var i = 0; i < arrLength; ++i) {
- var e = arr[i];
- if (isNum(e)) {
- var spacingLength = -e * fontSize * textHScale;
- if (vertical) {
- current.y += spacingLength;
- } else {
- current.x += spacingLength;
- }
+ ctx.save();
+ ctx.transform.apply(ctx, current.textMatrix);
+ ctx.translate(current.x, current.y);
- if (textSelection) {
- spacingAccumulator += spacingLength;
- }
- } else {
- var shownCanvasWidth = this.showText(e, true);
+ ctx.scale(textHScale, 1);
- if (textSelection) {
- canvasWidth += spacingAccumulator + shownCanvasWidth;
- spacingAccumulator = 0;
- }
+ for (i = 0; i < glyphsLength; ++i) {
+ glyph = glyphs[i];
+ if (glyph === null) {
+ // word break
+ this.ctx.translate(wordSpacing, 0);
+ current.x += wordSpacing * textHScale;
+ continue;
+ } else if (isNum(glyph)) {
+ var spacingLength = -glyph * 0.001 * fontSize;
+ this.ctx.translate(spacingLength, 0);
+ current.x += spacingLength * textHScale;
+ continue;
}
- }
- if (textSelection) {
- geom.canvasWidth = canvasWidth;
- if (vertical) {
- var VERTICAL_TEXT_ROTATION = Math.PI / 2;
- geom.angle += VERTICAL_TEXT_ROTATION;
- }
- this.textLayer.appendText(geom);
+ this.processingType3 = glyph;
+ this.save();
+ ctx.scale(fontSize, fontSize);
+ ctx.transform.apply(ctx, fontMatrix);
+ var operatorList = font.charProcOperatorList[glyph.operatorListId];
+ this.executeOperatorList(operatorList);
+ this.restore();
+
+ var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
+ width = ((transformed[0] * fontSize + charSpacing) * fontDirection);
+
+ ctx.translate(width, 0);
+ current.x += width * textHScale;
}
- },
- nextLineShowText: function CanvasGraphics_nextLineShowText(text) {
- this.nextLine();
- this.showText(text);
- },
- nextLineSetSpacingShowText:
- function CanvasGraphics_nextLineSetSpacingShowText(wordSpacing,
- charSpacing,
- text) {
- this.setWordSpacing(wordSpacing);
- this.setCharSpacing(charSpacing);
- this.nextLineShowText(text);
+ ctx.restore();
+ this.processingType3 = null;
},
// Type3 fonts
@@ -6655,104 +5211,30 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
},
// Color
- setStrokeColorSpace: function CanvasGraphics_setStrokeColorSpace(raw) {
- this.current.strokeColorSpace = ColorSpace.fromIR(raw);
- },
- setFillColorSpace: function CanvasGraphics_setFillColorSpace(raw) {
- this.current.fillColorSpace = ColorSpace.fromIR(raw);
- },
- setStrokeColor: function CanvasGraphics_setStrokeColor(/*...*/) {
- var cs = this.current.strokeColorSpace;
- var rgbColor = cs.getRgb(arguments, 0);
- var color = Util.makeCssRgb(rgbColor);
- this.ctx.strokeStyle = color;
- this.current.strokeColor = color;
- },
- getColorN_Pattern: function CanvasGraphics_getColorN_Pattern(IR, cs) {
+ getColorN_Pattern: function CanvasGraphics_getColorN_Pattern(IR) {
+ var pattern;
if (IR[0] == 'TilingPattern') {
- var args = IR[1];
- var base = cs.base;
- var color;
- if (base) {
- var baseComps = base.numComps;
-
- color = base.getRgb(args, 0);
- }
- var pattern = new TilingPattern(IR, color, this.ctx, this.objs,
- this.commonObjs, this.baseTransform);
+ var color = IR[1];
+ pattern = new TilingPattern(IR, color, this.ctx, this.objs,
+ this.commonObjs, this.baseTransform);
} else {
- var pattern = getShadingPatternFromIR(IR);
+ pattern = getShadingPatternFromIR(IR);
}
return pattern;
},
setStrokeColorN: function CanvasGraphics_setStrokeColorN(/*...*/) {
- var cs = this.current.strokeColorSpace;
-
- if (cs.name == 'Pattern') {
- this.current.strokeColor = this.getColorN_Pattern(arguments, cs);
- } else {
- this.setStrokeColor.apply(this, arguments);
- }
- },
- setFillColor: function CanvasGraphics_setFillColor(/*...*/) {
- var cs = this.current.fillColorSpace;
- var rgbColor = cs.getRgb(arguments, 0);
- var color = Util.makeCssRgb(rgbColor);
- this.ctx.fillStyle = color;
- this.current.fillColor = color;
+ this.current.strokeColor = this.getColorN_Pattern(arguments);
},
setFillColorN: function CanvasGraphics_setFillColorN(/*...*/) {
- var cs = this.current.fillColorSpace;
-
- if (cs.name == 'Pattern') {
- this.current.fillColor = this.getColorN_Pattern(arguments, cs);
- } else {
- this.setFillColor.apply(this, arguments);
- }
- },
- setStrokeGray: function CanvasGraphics_setStrokeGray(gray) {
- this.current.strokeColorSpace = ColorSpace.singletons.gray;
-
- var rgbColor = this.current.strokeColorSpace.getRgb(arguments, 0);
- var color = Util.makeCssRgb(rgbColor);
- this.ctx.strokeStyle = color;
- this.current.strokeColor = color;
- },
- setFillGray: function CanvasGraphics_setFillGray(gray) {
- this.current.fillColorSpace = ColorSpace.singletons.gray;
-
- var rgbColor = this.current.fillColorSpace.getRgb(arguments, 0);
- var color = Util.makeCssRgb(rgbColor);
- this.ctx.fillStyle = color;
- this.current.fillColor = color;
+ this.current.fillColor = this.getColorN_Pattern(arguments);
},
setStrokeRGBColor: function CanvasGraphics_setStrokeRGBColor(r, g, b) {
- this.current.strokeColorSpace = ColorSpace.singletons.rgb;
-
- var rgbColor = this.current.strokeColorSpace.getRgb(arguments, 0);
- var color = Util.makeCssRgb(rgbColor);
+ var color = Util.makeCssRgb(arguments);
this.ctx.strokeStyle = color;
this.current.strokeColor = color;
},
setFillRGBColor: function CanvasGraphics_setFillRGBColor(r, g, b) {
- this.current.fillColorSpace = ColorSpace.singletons.rgb;
-
- var rgbColor = this.current.fillColorSpace.getRgb(arguments, 0);
- var color = Util.makeCssRgb(rgbColor);
- this.ctx.fillStyle = color;
- this.current.fillColor = color;
- },
- setStrokeCMYKColor: function CanvasGraphics_setStrokeCMYKColor(c, m, y, k) {
- this.current.strokeColorSpace = ColorSpace.singletons.cmyk;
-
- var color = Util.makeCssCmyk(arguments);
- this.ctx.strokeStyle = color;
- this.current.strokeColor = color;
- },
- setFillCMYKColor: function CanvasGraphics_setFillCMYKColor(c, m, y, k) {
- this.current.fillColorSpace = ColorSpace.singletons.cmyk;
-
- var color = Util.makeCssCmyk(arguments);
+ var color = Util.makeCssRgb(arguments);
this.ctx.fillStyle = color;
this.current.fillColor = color;
},
@@ -6872,8 +5354,19 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
bounds = Util.intersect(bounds, canvasBounds) || [0, 0, 0, 0];
// Use ceil in case we're between sizes so we don't create canvas that is
// too small and make the canvas at least 1x1 pixels.
- var drawnWidth = Math.max(Math.ceil(bounds[2] - bounds[0]), 1);
- var drawnHeight = Math.max(Math.ceil(bounds[3] - bounds[1]), 1);
+ var offsetX = Math.floor(bounds[0]);
+ var offsetY = Math.floor(bounds[1]);
+ var drawnWidth = Math.max(Math.ceil(bounds[2]) - offsetX, 1);
+ var drawnHeight = Math.max(Math.ceil(bounds[3]) - offsetY, 1);
+ var scaleX = 1, scaleY = 1;
+ if (drawnWidth > MAX_GROUP_SIZE) {
+ scaleX = drawnWidth / MAX_GROUP_SIZE;
+ drawnWidth = MAX_GROUP_SIZE;
+ }
+ if (drawnHeight > MAX_GROUP_SIZE) {
+ scaleY = drawnHeight / MAX_GROUP_SIZE;
+ drawnHeight = MAX_GROUP_SIZE;
+ }
var cacheId = 'groupAt' + this.groupLevel;
if (group.smask) {
@@ -6886,8 +5379,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
// Since we created a new canvas that is just the size of the bounding box
// we have to translate the group ctx.
- var offsetX = bounds[0];
- var offsetY = bounds[1];
+ groupCtx.scale(1 / scaleX, 1 / scaleY);
groupCtx.translate(-offsetX, -offsetY);
groupCtx.transform.apply(groupCtx, currentTransform);
@@ -6898,15 +5390,17 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
context: groupCtx,
offsetX: offsetX,
offsetY: offsetY,
+ scaleX: scaleX,
+ scaleY: scaleY,
subtype: group.smask.subtype,
- backdrop: group.smask.backdrop,
- colorSpace: group.colorSpace && ColorSpace.fromIR(group.colorSpace)
+ backdrop: group.smask.backdrop
});
} else {
// Setup the current ctx so when the group is popped we draw it at the
// right location.
currentCtx.setTransform(1, 0, 0, 1, 0, 0);
currentCtx.translate(offsetX, offsetY);
+ currentCtx.scale(scaleX, scaleY);
}
// The transparency group inherits all off the current graphics state
// except the blend mode, soft mask, and alpha constants.
@@ -6927,7 +5421,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.ctx = this.groupStack.pop();
// Turn off image smoothing to avoid sub pixel interpolation which can
// look kind of blurry for some pdfs.
- if ('imageSmoothingEnabled' in this.ctx) {
+ if (this.ctx.imageSmoothingEnabled !== undefined) {
this.ctx.imageSmoothingEnabled = false;
} else {
this.ctx.mozImageSmoothingEnabled = false;
@@ -6972,7 +5466,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
paintJpegXObject: function CanvasGraphics_paintJpegXObject(objId, w, h) {
var domImage = this.objs.get(objId);
if (!domImage) {
- error('Dependent image isn\'t ready yet');
+ warn('Dependent image isn\'t ready yet');
+ return;
}
this.save();
@@ -7106,7 +5601,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
paintImageXObject: function CanvasGraphics_paintImageXObject(objId) {
var imgData = this.objs.get(objId);
if (!imgData) {
- error('Dependent image isn\'t ready yet');
+ warn('Dependent image isn\'t ready yet');
+ return;
}
this.paintInlineImageXObject(imgData);
@@ -7117,7 +5613,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
positions) {
var imgData = this.objs.get(objId);
if (!imgData) {
- error('Dependent image isn\'t ready yet');
+ warn('Dependent image isn\'t ready yet');
+ return;
}
var width = imgData.width;
@@ -7146,12 +5643,12 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
var c = currentTransform[2], d = currentTransform[3];
var heightScale = Math.max(Math.sqrt(c * c + d * d), 1);
- var imgToPaint;
+ var imgToPaint, tmpCanvas;
// instanceof HTMLElement does not work in jsdom node.js module
if (imgData instanceof HTMLElement || !imgData.data) {
imgToPaint = imgData;
} else {
- var tmpCanvas = CachedCanvases.getCanvas('inlineImage', width, height);
+ tmpCanvas = CachedCanvases.getCanvas('inlineImage', width, height);
var tmpCtx = tmpCanvas.context;
putBinaryImageData(tmpCtx, imgData);
imgToPaint = tmpCanvas.canvas;
@@ -7173,8 +5670,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
newHeight = Math.ceil(paintHeight / 2);
heightScale /= paintHeight / newHeight;
}
- var tmpCanvas = CachedCanvases.getCanvas(tmpCanvasId,
- newWidth, newHeight);
+ tmpCanvas = CachedCanvases.getCanvas(tmpCanvasId, newWidth, newHeight);
tmpCtx = tmpCanvas.context;
tmpCtx.clearRect(0, 0, newWidth, newHeight);
tmpCtx.drawImage(imgToPaint, 0, 0, paintWidth, paintHeight,
@@ -7231,6 +5727,11 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
},
+ paintSolidColorImageMask:
+ function CanvasGraphics_paintSolidColorImageMask() {
+ this.ctx.fillRect(0, 0, 1, 1);
+ },
+
// Marked content
markPoint: function CanvasGraphics_markPoint(tag) {
@@ -7262,26 +5763,27 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
// Helper functions
consumePath: function CanvasGraphics_consumePath() {
+ var ctx = this.ctx;
if (this.pendingClip) {
if (this.pendingClip == EO_CLIP) {
- if ('mozFillRule' in this.ctx) {
- this.ctx.mozFillRule = 'evenodd';
- this.ctx.clip();
- this.ctx.mozFillRule = 'nonzero';
+ if (ctx.mozFillRule !== undefined) {
+ ctx.mozFillRule = 'evenodd';
+ ctx.clip();
+ ctx.mozFillRule = 'nonzero';
} else {
try {
- this.ctx.clip('evenodd');
+ ctx.clip('evenodd');
} catch (ex) {
// shouldn't really happen, but browsers might think differently
- this.ctx.clip();
+ ctx.clip();
}
}
} else {
- this.ctx.clip();
+ ctx.clip();
}
this.pendingClip = null;
}
- this.ctx.beginPath();
+ ctx.beginPath();
},
getSinglePixelWidth: function CanvasGraphics_getSinglePixelWidth(scale) {
var inverse = this.ctx.mozCurrentTransformInverse;
@@ -7308,6 +5810,416 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
+var WebGLUtils = (function WebGLUtilsClosure() {
+ function loadShader(gl, code, shaderType) {
+ var shader = gl.createShader(shaderType);
+ gl.shaderSource(shader, code);
+ gl.compileShader(shader);
+ var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
+ if (!compiled) {
+ var errorMsg = gl.getShaderInfoLog(shader);
+ throw new Error('Error during shader compilation: ' + errorMsg);
+ }
+ return shader;
+ }
+ function createVertexShader(gl, code) {
+ return loadShader(gl, code, gl.VERTEX_SHADER);
+ }
+ function createFragmentShader(gl, code) {
+ return loadShader(gl, code, gl.FRAGMENT_SHADER);
+ }
+ function createProgram(gl, shaders) {
+ var program = gl.createProgram();
+ for (var i = 0, ii = shaders.length; i < ii; ++i) {
+ gl.attachShader(program, shaders[i]);
+ }
+ gl.linkProgram(program);
+ var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
+ if (!linked) {
+ var errorMsg = gl.getProgramInfoLog(program);
+ throw new Error('Error during program linking: ' + errorMsg);
+ }
+ return program;
+ }
+ function createTexture(gl, image, textureId) {
+ gl.activeTexture(textureId);
+ var texture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+
+ // Set the parameters so we can render any size image.
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+
+ // Upload the image into the texture.
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
+ return texture;
+ }
+
+ var currentGL, currentCanvas;
+ function generageGL() {
+ if (currentGL) {
+ return;
+ }
+ currentCanvas = document.createElement('canvas');
+ currentGL = currentCanvas.getContext('webgl',
+ { premultipliedalpha: false });
+ }
+
+ var smaskVertexShaderCode = '\
+ attribute vec2 a_position; \
+ attribute vec2 a_texCoord; \
+ \
+ uniform vec2 u_resolution; \
+ \
+ varying vec2 v_texCoord; \
+ \
+ void main() { \
+ vec2 clipSpace = (a_position / u_resolution) * 2.0 - 1.0; \
+ gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \
+ \
+ v_texCoord = a_texCoord; \
+ } ';
+
+ var smaskFragmentShaderCode = '\
+ precision mediump float; \
+ \
+ uniform vec4 u_backdrop; \
+ uniform int u_subtype; \
+ uniform sampler2D u_image; \
+ uniform sampler2D u_mask; \
+ \
+ varying vec2 v_texCoord; \
+ \
+ void main() { \
+ vec4 imageColor = texture2D(u_image, v_texCoord); \
+ vec4 maskColor = texture2D(u_mask, v_texCoord); \
+ if (u_backdrop.a > 0.0) { \
+ maskColor.rgb = maskColor.rgb * maskColor.a + \
+ u_backdrop.rgb * (1.0 - maskColor.a); \
+ } \
+ float lum; \
+ if (u_subtype == 0) { \
+ lum = maskColor.a; \
+ } else { \
+ lum = maskColor.r * 0.3 + maskColor.g * 0.59 + \
+ maskColor.b * 0.11; \
+ } \
+ imageColor.a *= lum; \
+ imageColor.rgb *= imageColor.a; \
+ gl_FragColor = imageColor; \
+ } ';
+
+ var smaskCache = null;
+
+ function initSmaskGL() {
+ var canvas, gl;
+
+ generageGL();
+ canvas = currentCanvas;
+ currentCanvas = null;
+ gl = currentGL;
+ currentGL = null;
+
+ // setup a GLSL program
+ var vertexShader = createVertexShader(gl, smaskVertexShaderCode);
+ var fragmentShader = createFragmentShader(gl, smaskFragmentShaderCode);
+ var program = createProgram(gl, [vertexShader, fragmentShader]);
+ gl.useProgram(program);
+
+ var cache = {};
+ cache.gl = gl;
+ cache.canvas = canvas;
+ cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
+ cache.positionLocation = gl.getAttribLocation(program, 'a_position');
+ cache.backdropLocation = gl.getUniformLocation(program, 'u_backdrop');
+ cache.subtypeLocation = gl.getUniformLocation(program, 'u_subtype');
+
+ var texCoordLocation = gl.getAttribLocation(program, 'a_texCoord');
+ var texLayerLocation = gl.getUniformLocation(program, 'u_image');
+ var texMaskLocation = gl.getUniformLocation(program, 'u_mask');
+
+ // provide texture coordinates for the rectangle.
+ var texCoordBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ 0.0, 0.0,
+ 1.0, 0.0,
+ 0.0, 1.0,
+ 0.0, 1.0,
+ 1.0, 0.0,
+ 1.0, 1.0]), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(texCoordLocation);
+ gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
+
+ gl.uniform1i(texLayerLocation, 0);
+ gl.uniform1i(texMaskLocation, 1);
+
+ smaskCache = cache;
+ }
+
+ function composeSMask(layer, mask, properties) {
+ var width = layer.width, height = layer.height;
+
+ if (!smaskCache) {
+ initSmaskGL();
+ }
+ var cache = smaskCache,canvas = cache.canvas, gl = cache.gl;
+ canvas.width = width;
+ canvas.height = height;
+ gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
+ gl.uniform2f(cache.resolutionLocation, width, height);
+
+ if (properties.backdrop) {
+ gl.uniform4f(cache.resolutionLocation, properties.backdrop[0],
+ properties.backdrop[1], properties.backdrop[2], 1);
+ } else {
+ gl.uniform4f(cache.resolutionLocation, 0, 0, 0, 0);
+ }
+ gl.uniform1i(cache.subtypeLocation,
+ properties.subtype === 'Luminosity' ? 1 : 0);
+
+ // Create a textures
+ var texture = createTexture(gl, layer, gl.TEXTURE0);
+ var maskTexture = createTexture(gl, mask, gl.TEXTURE1);
+
+
+ // Create a buffer and put a single clipspace rectangle in
+ // it (2 triangles)
+ var buffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ 0, 0,
+ width, 0,
+ 0, height,
+ 0, height,
+ width, 0,
+ width, height]), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(cache.positionLocation);
+ gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0);
+
+ // draw
+ gl.clearColor(0, 0, 0, 0);
+ gl.enable(gl.BLEND);
+ gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+
+ gl.flush();
+
+ gl.deleteTexture(texture);
+ gl.deleteTexture(maskTexture);
+ gl.deleteBuffer(buffer);
+
+ return canvas;
+ }
+
+ var figuresVertexShaderCode = '\
+ attribute vec2 a_position; \
+ attribute vec3 a_color; \
+ \
+ uniform vec2 u_resolution; \
+ uniform vec2 u_scale; \
+ uniform vec2 u_offset; \
+ \
+ varying vec4 v_color; \
+ \
+ void main() { \
+ vec2 position = (a_position + u_offset) * u_scale; \
+ vec2 clipSpace = (position / u_resolution) * 2.0 - 1.0; \
+ gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \
+ \
+ v_color = vec4(a_color / 255.0, 1.0); \
+ } ';
+
+ var figuresFragmentShaderCode = '\
+ precision mediump float; \
+ \
+ varying vec4 v_color; \
+ \
+ void main() { \
+ gl_FragColor = v_color; \
+ } ';
+
+ var figuresCache = null;
+
+ function initFiguresGL() {
+ var canvas, gl;
+
+ generageGL();
+ canvas = currentCanvas;
+ currentCanvas = null;
+ gl = currentGL;
+ currentGL = null;
+
+ // setup a GLSL program
+ var vertexShader = createVertexShader(gl, figuresVertexShaderCode);
+ var fragmentShader = createFragmentShader(gl, figuresFragmentShaderCode);
+ var program = createProgram(gl, [vertexShader, fragmentShader]);
+ gl.useProgram(program);
+
+ var cache = {};
+ cache.gl = gl;
+ cache.canvas = canvas;
+ cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
+ cache.scaleLocation = gl.getUniformLocation(program, 'u_scale');
+ cache.offsetLocation = gl.getUniformLocation(program, 'u_offset');
+ cache.positionLocation = gl.getAttribLocation(program, 'a_position');
+ cache.colorLocation = gl.getAttribLocation(program, 'a_color');
+
+ figuresCache = cache;
+ }
+
+ function drawFigures(width, height, backgroundColor, figures, context) {
+ if (!figuresCache) {
+ initFiguresGL();
+ }
+ var cache = figuresCache, canvas = cache.canvas, gl = cache.gl;
+
+ canvas.width = width;
+ canvas.height = height;
+ gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
+ gl.uniform2f(cache.resolutionLocation, width, height);
+
+ // count triangle points
+ var count = 0;
+ var i, ii, rows;
+ for (i = 0, ii = figures.length; i < ii; i++) {
+ switch (figures[i].type) {
+ case 'lattice':
+ rows = (figures[i].coords.length / figures[i].verticesPerRow) | 0;
+ count += (rows - 1) * (figures[i].verticesPerRow - 1) * 6;
+ break;
+ case 'triangles':
+ count += figures[i].coords.length;
+ break;
+ }
+ }
+ // transfer data
+ var coords = new Float32Array(count * 2);
+ var colors = new Uint8Array(count * 3);
+ var coordsMap = context.coords, colorsMap = context.colors;
+ var pIndex = 0, cIndex = 0;
+ for (i = 0, ii = figures.length; i < ii; i++) {
+ var figure = figures[i], ps = figure.coords, cs = figure.colors;
+ switch (figure.type) {
+ case 'lattice':
+ var cols = figure.verticesPerRow;
+ rows = (ps.length / cols) | 0;
+ for (var row = 1; row < rows; row++) {
+ var offset = row * cols + 1;
+ for (var col = 1; col < cols; col++, offset++) {
+ coords[pIndex] = coordsMap[ps[offset - cols - 1]];
+ coords[pIndex + 1] = coordsMap[ps[offset - cols - 1] + 1];
+ coords[pIndex + 2] = coordsMap[ps[offset - cols]];
+ coords[pIndex + 3] = coordsMap[ps[offset - cols] + 1];
+ coords[pIndex + 4] = coordsMap[ps[offset - 1]];
+ coords[pIndex + 5] = coordsMap[ps[offset - 1] + 1];
+ colors[cIndex] = colorsMap[cs[offset - cols - 1]];
+ colors[cIndex + 1] = colorsMap[cs[offset - cols - 1] + 1];
+ colors[cIndex + 2] = colorsMap[cs[offset - cols - 1] + 2];
+ colors[cIndex + 3] = colorsMap[cs[offset - cols]];
+ colors[cIndex + 4] = colorsMap[cs[offset - cols] + 1];
+ colors[cIndex + 5] = colorsMap[cs[offset - cols] + 2];
+ colors[cIndex + 6] = colorsMap[cs[offset - 1]];
+ colors[cIndex + 7] = colorsMap[cs[offset - 1] + 1];
+ colors[cIndex + 8] = colorsMap[cs[offset - 1] + 2];
+
+ coords[pIndex + 6] = coords[pIndex + 2];
+ coords[pIndex + 7] = coords[pIndex + 3];
+ coords[pIndex + 8] = coords[pIndex + 4];
+ coords[pIndex + 9] = coords[pIndex + 5];
+ coords[pIndex + 10] = coordsMap[ps[offset]];
+ coords[pIndex + 11] = coordsMap[ps[offset] + 1];
+ colors[cIndex + 9] = colors[cIndex + 3];
+ colors[cIndex + 10] = colors[cIndex + 4];
+ colors[cIndex + 11] = colors[cIndex + 5];
+ colors[cIndex + 12] = colors[cIndex + 6];
+ colors[cIndex + 13] = colors[cIndex + 7];
+ colors[cIndex + 14] = colors[cIndex + 8];
+ colors[cIndex + 15] = colorsMap[cs[offset]];
+ colors[cIndex + 16] = colorsMap[cs[offset] + 1];
+ colors[cIndex + 17] = colorsMap[cs[offset] + 2];
+ pIndex += 12;
+ cIndex += 18;
+ }
+ }
+ break;
+ case 'triangles':
+ for (var j = 0, jj = ps.length; j < jj; j++) {
+ coords[pIndex] = coordsMap[ps[j]];
+ coords[pIndex + 1] = coordsMap[ps[j] + 1];
+ colors[cIndex] = colorsMap[cs[i]];
+ colors[cIndex + 1] = colorsMap[cs[j] + 1];
+ colors[cIndex + 2] = colorsMap[cs[j] + 2];
+ pIndex += 2;
+ cIndex += 3;
+ }
+ break;
+ }
+ }
+
+ // draw
+ if (backgroundColor) {
+ gl.clearColor(backgroundColor[0] / 255, backgroundColor[1] / 255,
+ backgroundColor[2] / 255, 1.0);
+ } else {
+ gl.clearColor(0, 0, 0, 0);
+ }
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ var coordsBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, coordsBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, coords, gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(cache.positionLocation);
+ gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0);
+
+ var colorsBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorsBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(cache.colorLocation);
+ gl.vertexAttribPointer(cache.colorLocation, 3, gl.UNSIGNED_BYTE, false,
+ 0, 0);
+
+ gl.uniform2f(cache.scaleLocation, context.scaleX, context.scaleY);
+ gl.uniform2f(cache.offsetLocation, context.offsetX, context.offsetY);
+
+ gl.drawArrays(gl.TRIANGLES, 0, count);
+
+ gl.flush();
+
+ gl.deleteBuffer(coordsBuffer);
+ gl.deleteBuffer(colorsBuffer);
+
+ return canvas;
+ }
+
+ function cleanup() {
+ smaskCache = null;
+ figuresCache = null;
+ }
+
+ return {
+ get isEnabled() {
+ if (PDFJS.disableWebGL) {
+ return false;
+ }
+ var enabled = false;
+ try {
+ generageGL();
+ enabled = !!currentGL;
+ } catch (e) { }
+ return shadow(this, 'isEnabled', enabled);
+ },
+ composeSMask: composeSMask,
+ drawFigures: drawFigures,
+ clear: cleanup
+ };
+})();
+
+
var ShadingIRs = {};
ShadingIRs.RadialAxial = {
@@ -7344,28 +6256,27 @@ var createMeshCanvas = (function createMeshCanvasClosure() {
var coords = context.coords, colors = context.colors;
var bytes = data.data, rowSize = data.width * 4;
var tmp;
- if (coords[p1 * 2 + 1] > coords[p2 * 2 + 1]) {
+ if (coords[p1 + 1] > coords[p2 + 1]) {
tmp = p1; p1 = p2; p2 = tmp; tmp = c1; c1 = c2; c2 = tmp;
}
- if (coords[p2 * 2 + 1] > coords[p3 * 2 + 1]) {
+ if (coords[p2 + 1] > coords[p3 + 1]) {
tmp = p2; p2 = p3; p3 = tmp; tmp = c2; c2 = c3; c3 = tmp;
}
- if (coords[p1 * 2 + 1] > coords[p2 * 2 + 1]) {
+ if (coords[p1 + 1] > coords[p2 + 1]) {
tmp = p1; p1 = p2; p2 = tmp; tmp = c1; c1 = c2; c2 = tmp;
}
- var x1 = (coords[p1 * 2] + context.offsetX) * context.scaleX;
- var y1 = (coords[p1 * 2 + 1] + context.offsetY) * context.scaleY;
- var x2 = (coords[p2 * 2] + context.offsetX) * context.scaleX;
- var y2 = (coords[p2 * 2 + 1] + context.offsetY) * context.scaleY;
- var x3 = (coords[p3 * 2] + context.offsetX) * context.scaleX;
- var y3 = (coords[p3 * 2 + 1] + context.offsetY) * context.scaleY;
+ var x1 = (coords[p1] + context.offsetX) * context.scaleX;
+ var y1 = (coords[p1 + 1] + context.offsetY) * context.scaleY;
+ var x2 = (coords[p2] + context.offsetX) * context.scaleX;
+ var y2 = (coords[p2 + 1] + context.offsetY) * context.scaleY;
+ var x3 = (coords[p3] + context.offsetX) * context.scaleX;
+ var y3 = (coords[p3 + 1] + context.offsetY) * context.scaleY;
if (y1 >= y3) {
return;
}
- var c1i = c1 * 3, c2i = c2 * 3, c3i = c3 * 3;
- var c1r = colors[c1i], c1g = colors[c1i + 1], c1b = colors[c1i + 2];
- var c2r = colors[c2i], c2g = colors[c2i + 1], c2b = colors[c2i + 2];
- var c3r = colors[c3i], c3g = colors[c3i + 1], c3b = colors[c3i + 2];
+ var c1r = colors[c1], c1g = colors[c1 + 1], c1b = colors[c1 + 2];
+ var c2r = colors[c2], c2g = colors[c2 + 1], c2b = colors[c2 + 2];
+ var c3r = colors[c3], c3g = colors[c3 + 1], c3b = colors[c3 + 2];
var minY = Math.round(y1), maxY = Math.round(y3);
var xa, car, cag, cab;
@@ -7407,12 +6318,13 @@ var createMeshCanvas = (function createMeshCanvasClosure() {
function drawFigure(data, figure, context) {
var ps = figure.coords;
var cs = figure.colors;
+ var i, ii;
switch (figure.type) {
case 'lattice':
var verticesPerRow = figure.verticesPerRow;
var rows = Math.floor(ps.length / verticesPerRow) - 1;
var cols = verticesPerRow - 1;
- for (var i = 0; i < rows; i++) {
+ for (i = 0; i < rows; i++) {
var q = i * verticesPerRow;
for (var j = 0; j < cols; j++, q++) {
drawTriangle(data, context,
@@ -7425,7 +6337,7 @@ var createMeshCanvas = (function createMeshCanvasClosure() {
}
break;
case 'triangles':
- for (var i = 0, ii = ps.length; i < ii; i += 3) {
+ for (i = 0, ii = ps.length; i < ii; i += 3) {
drawTriangle(data, context,
ps[i], ps[i + 1], ps[i + 2],
cs[i], cs[i + 1], cs[i + 2]);
@@ -7445,52 +6357,72 @@ var createMeshCanvas = (function createMeshCanvasClosure() {
// MAX_PATTERN_SIZE is used to avoid OOM situation.
var MAX_PATTERN_SIZE = 3000; // 10in @ 300dpi shall be enough
- var boundsWidth = bounds[2] - bounds[0];
- var boundsHeight = bounds[3] - bounds[1];
+ var offsetX = Math.floor(bounds[0]);
+ var offsetY = Math.floor(bounds[1]);
+ var boundsWidth = Math.ceil(bounds[2]) - offsetX;
+ var boundsHeight = Math.ceil(bounds[3]) - offsetY;
var width = Math.min(Math.ceil(Math.abs(boundsWidth * combinesScale[0] *
EXPECTED_SCALE)), MAX_PATTERN_SIZE);
var height = Math.min(Math.ceil(Math.abs(boundsHeight * combinesScale[1] *
EXPECTED_SCALE)), MAX_PATTERN_SIZE);
- var scaleX = width / boundsWidth;
- var scaleY = height / boundsHeight;
-
- var tmpCanvas = CachedCanvases.getCanvas('mesh', width, height, false);
- var tmpCtx = tmpCanvas.context;
- if (backgroundColor) {
- tmpCtx.fillStyle = makeCssRgb(backgroundColor);
- tmpCtx.fillRect(0, 0, width, height);
- }
+ var scaleX = boundsWidth / width;
+ var scaleY = boundsHeight / height;
var context = {
coords: coords,
colors: colors,
- offsetX: -bounds[0],
- offsetY: -bounds[1],
- scaleX: scaleX,
- scaleY: scaleY
+ offsetX: -offsetX,
+ offsetY: -offsetY,
+ scaleX: 1 / scaleX,
+ scaleY: 1 / scaleY
};
- var data = tmpCtx.getImageData(0, 0, width, height);
- for (var i = 0; i < figures.length; i++) {
- drawFigure(data, figures[i], context);
+ var canvas, tmpCanvas, i, ii;
+ if (WebGLUtils.isEnabled) {
+ canvas = WebGLUtils.drawFigures(width, height, backgroundColor,
+ figures, context);
+
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=972126
+ tmpCanvas = CachedCanvases.getCanvas('mesh', width, height, false);
+ tmpCanvas.context.drawImage(canvas, 0, 0);
+ canvas = tmpCanvas.canvas;
+ } else {
+ tmpCanvas = CachedCanvases.getCanvas('mesh', width, height, false);
+ var tmpCtx = tmpCanvas.context;
+
+ var data = tmpCtx.createImageData(width, height);
+ if (backgroundColor) {
+ var bytes = data.data;
+ for (i = 0, ii = bytes.length; i < ii; i += 4) {
+ bytes[i] = backgroundColor[0];
+ bytes[i + 1] = backgroundColor[1];
+ bytes[i + 2] = backgroundColor[2];
+ bytes[i + 3] = 255;
+ }
+ }
+ for (i = 0; i < figures.length; i++) {
+ drawFigure(data, figures[i], context);
+ }
+ tmpCtx.putImageData(data, 0, 0);
+ canvas = tmpCanvas.canvas;
}
- tmpCtx.putImageData(data, 0, 0);
- return {canvas: tmpCanvas.canvas, scaleX: 1 / scaleX, scaleY: 1 / scaleY};
+ return {canvas: canvas, offsetX: offsetX, offsetY: offsetY,
+ scaleX: scaleX, scaleY: scaleY};
}
return createMeshCanvas;
})();
ShadingIRs.Mesh = {
fromIR: function Mesh_fromIR(raw) {
- var type = raw[1];
+ //var type = raw[1];
var coords = raw[2];
var colors = raw[3];
var figures = raw[4];
var bounds = raw[5];
var matrix = raw[6];
- var bbox = raw[7];
+ //var bbox = raw[7];
var background = raw[8];
return {
type: 'Pattern',
@@ -7511,7 +6443,6 @@ ShadingIRs.Mesh = {
// Rasterizing on the main thread since sending/queue large canvases
// might cause OOM.
- // TODO consider using WebGL or asm.js to perform rasterization
var temporaryPatternCanvas = createMeshCanvas(bounds, combinedScale,
coords, colors, figures, shadingFill ? null : background);
@@ -7522,7 +6453,8 @@ ShadingIRs.Mesh = {
}
}
- ctx.translate(bounds[0], bounds[1]);
+ ctx.translate(temporaryPatternCanvas.offsetX,
+ temporaryPatternCanvas.offsetY);
ctx.scale(temporaryPatternCanvas.scaleX,
temporaryPatternCanvas.scaleY);
@@ -7560,7 +6492,6 @@ var TilingPattern = (function TilingPatternClosure() {
var MAX_PATTERN_SIZE = 3000; // 10in @ 300dpi shall be enough
function TilingPattern(IR, color, ctx, objs, commonObjs, baseTransform) {
- this.name = IR[1][0].name;
this.operatorList = IR[2];
this.matrix = IR[3] || [1, 0, 0, 1, 0, 0];
this.bbox = IR[4];
@@ -7587,7 +6518,6 @@ var TilingPattern = (function TilingPatternClosure() {
var color = this.color;
var objs = this.objs;
var commonObjs = this.commonObjs;
- var ctx = this.ctx;
info('TilingType: ' + tilingType);
@@ -7671,8 +6601,7 @@ var TilingPattern = (function TilingPatternClosure() {
context.strokeStyle = ctx.strokeStyle;
break;
case PaintType.UNCOLORED:
- var rgbColor = ColorSpace.singletons.rgb.getRgb(color, 0);
- var cssColor = Util.makeCssRgb(rgbColor);
+ var cssColor = Util.makeCssRgb(color);
context.fillStyle = cssColor;
context.strokeStyle = cssColor;
break;
@@ -7684,7 +6613,7 @@ var TilingPattern = (function TilingPatternClosure() {
getPattern: function TilingPattern_getPattern(ctx, owner) {
var temporaryPatternCanvas = this.createPatternCanvas(owner);
- var ctx = this.ctx;
+ ctx = this.ctx;
ctx.setTransform.apply(ctx, this.baseTransform);
ctx.transform.apply(ctx, this.matrix);
this.scaleToContext();
@@ -7841,16 +6770,9 @@ var FontLoader = {
(data.charCodeAt(offset + 3) & 0xff);
}
- function string32(value) {
- return String.fromCharCode((value >> 24) & 0xff) +
- String.fromCharCode((value >> 16) & 0xff) +
- String.fromCharCode((value >> 8) & 0xff) +
- String.fromCharCode(value & 0xff);
- }
-
function spliceString(s, offset, remove, insert) {
- var chunk1 = data.substr(0, offset);
- var chunk2 = data.substr(offset + remove);
+ var chunk1 = s.substr(0, offset);
+ var chunk2 = s.substr(offset + remove);
return chunk1 + insert + chunk2;
}
@@ -7958,7 +6880,7 @@ var FontFace = (function FontFaceClosure() {
return null;
}
- var data = bytesToString(this.data);
+ var data = bytesToString(new Uint8Array(this.data));
var fontName = this.loadedName;
// Add the font-face rule to the document