Merge pull request #3913 from brendandahl/int-ops

Reduce the memory usage of the operator list.
This commit is contained in:
Yury Delendik 2013-11-13 13:14:59 -08:00
commit 516d2e79be
8 changed files with 288 additions and 155 deletions

View File

@ -184,7 +184,6 @@ var Page = (function PageClosure() {
var annotations = datas[1];
if (annotations.length === 0) {
PartialEvaluator.optimizeQueue(pageOpList);
pageOpList.flush(true);
promise.resolve(pageOpList);
return;
@ -193,7 +192,6 @@ var Page = (function PageClosure() {
var annotationsReadyPromise = Annotation.appendToOperatorList(
annotations, pageOpList, pdfManager, partialEvaluator);
annotationsReadyPromise.then(function () {
PartialEvaluator.optimizeQueue(pageOpList);
pageOpList.flush(true);
promise.resolve(pageOpList);
}, reject);

View File

@ -20,7 +20,7 @@
isStream, isString, JpegStream, Lexer, Metrics, Name, Parser,
Pattern, PDFImage, PDFJS, serifFonts, stdFontMap, symbolsFonts,
TilingPattern, TODO, warn, Util, Promise,
RefSetCache, isRef, TextRenderingMode, CMapFactory */
RefSetCache, isRef, TextRenderingMode, CMapFactory, OPS */
'use strict';
@ -45,98 +45,99 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
// If variableArgs === false: exactly `numArgs` expected
var OP_MAP = {
// Graphic state
w: { fnName: 'setLineWidth', numArgs: 1, variableArgs: false },
J: { fnName: 'setLineCap', numArgs: 1, variableArgs: false },
j: { fnName: 'setLineJoin', numArgs: 1, variableArgs: false },
M: { fnName: 'setMiterLimit', numArgs: 1, variableArgs: false },
d: { fnName: 'setDash', numArgs: 2, variableArgs: false },
ri: { fnName: 'setRenderingIntent', numArgs: 1, variableArgs: false },
i: { fnName: 'setFlatness', numArgs: 1, variableArgs: false },
gs: { fnName: 'setGState', numArgs: 1, variableArgs: false },
q: { fnName: 'save', numArgs: 0, variableArgs: false },
Q: { fnName: 'restore', numArgs: 0, variableArgs: false },
cm: { fnName: 'transform', numArgs: 6, variableArgs: false },
w: { id: OPS.setLineWidth, numArgs: 1, variableArgs: false },
J: { id: OPS.setLineCap, numArgs: 1, variableArgs: false },
j: { id: OPS.setLineJoin, numArgs: 1, variableArgs: false },
M: { id: OPS.setMiterLimit, numArgs: 1, variableArgs: false },
d: { id: OPS.setDash, numArgs: 2, variableArgs: false },
ri: { id: OPS.setRenderingIntent, numArgs: 1, variableArgs: false },
i: { id: OPS.setFlatness, numArgs: 1, variableArgs: false },
gs: { id: OPS.setGState, numArgs: 1, variableArgs: false },
q: { id: OPS.save, numArgs: 0, variableArgs: false },
Q: { id: OPS.restore, numArgs: 0, variableArgs: false },
cm: { id: OPS.transform, numArgs: 6, variableArgs: false },
// Path
m: { fnName: 'moveTo', numArgs: 2, variableArgs: false },
l: { fnName: 'lineTo', numArgs: 2, variableArgs: false },
c: { fnName: 'curveTo', numArgs: 6, variableArgs: false },
v: { fnName: 'curveTo2', numArgs: 4, variableArgs: false },
y: { fnName: 'curveTo3', numArgs: 4, variableArgs: false },
h: { fnName: 'closePath', numArgs: 0, variableArgs: false },
re: { fnName: 'rectangle', numArgs: 4, variableArgs: false },
S: { fnName: 'stroke', numArgs: 0, variableArgs: false },
s: { fnName: 'closeStroke', numArgs: 0, variableArgs: false },
f: { fnName: 'fill', numArgs: 0, variableArgs: false },
F: { fnName: 'fill', numArgs: 0, variableArgs: false },
'f*': { fnName: 'eoFill', numArgs: 0, variableArgs: false },
B: { fnName: 'fillStroke', numArgs: 0, variableArgs: false },
'B*': { fnName: 'eoFillStroke', numArgs: 0, variableArgs: false },
b: { fnName: 'closeFillStroke', numArgs: 0, variableArgs: false },
'b*': { fnName: 'closeEOFillStroke', numArgs: 0, variableArgs: false },
n: { fnName: 'endPath', numArgs: 0, variableArgs: false },
m: { id: OPS.moveTo, numArgs: 2, variableArgs: false },
l: { id: OPS.lineTo, numArgs: 2, variableArgs: false },
c: { id: OPS.curveTo, numArgs: 6, variableArgs: false },
v: { id: OPS.curveTo2, numArgs: 4, variableArgs: false },
y: { id: OPS.curveTo3, numArgs: 4, variableArgs: false },
h: { id: OPS.closePath, numArgs: 0, variableArgs: false },
re: { id: OPS.rectangle, numArgs: 4, variableArgs: false },
S: { id: OPS.stroke, numArgs: 0, variableArgs: false },
s: { id: OPS.closeStroke, numArgs: 0, variableArgs: false },
f: { id: OPS.fill, numArgs: 0, variableArgs: false },
F: { id: OPS.fill, numArgs: 0, variableArgs: false },
'f*': { id: OPS.eoFill, numArgs: 0, variableArgs: false },
B: { id: OPS.fillStroke, numArgs: 0, variableArgs: false },
'B*': { id: OPS.eoFillStroke, numArgs: 0, variableArgs: false },
b: { id: OPS.closeFillStroke, numArgs: 0, variableArgs: false },
'b*': { id: OPS.closeEOFillStroke, numArgs: 0, variableArgs: false },
n: { id: OPS.endPath, numArgs: 0, variableArgs: false },
// Clipping
W: { fnName: 'clip', numArgs: 0, variableArgs: false },
'W*': { fnName: 'eoClip', numArgs: 0, variableArgs: false },
W: { id: OPS.clip, numArgs: 0, variableArgs: false },
'W*': { id: OPS.eoClip, numArgs: 0, variableArgs: false },
// Text
BT: { fnName: 'beginText', numArgs: 0, variableArgs: false },
ET: { fnName: 'endText', numArgs: 0, variableArgs: false },
Tc: { fnName: 'setCharSpacing', numArgs: 1, variableArgs: false },
Tw: { fnName: 'setWordSpacing', numArgs: 1, variableArgs: false },
Tz: { fnName: 'setHScale', numArgs: 1, variableArgs: false },
TL: { fnName: 'setLeading', numArgs: 1, variableArgs: false },
Tf: { fnName: 'setFont', numArgs: 2, variableArgs: false },
Tr: { fnName: 'setTextRenderingMode', numArgs: 1, variableArgs: false },
Ts: { fnName: 'setTextRise', numArgs: 1, variableArgs: false },
Td: { fnName: 'moveText', numArgs: 2, variableArgs: false },
TD: { fnName: 'setLeadingMoveText', numArgs: 2, variableArgs: false },
Tm: { fnName: 'setTextMatrix', numArgs: 6, variableArgs: false },
'T*': { fnName: 'nextLine', numArgs: 0, variableArgs: false },
Tj: { fnName: 'showText', numArgs: 1, variableArgs: false },
TJ: { fnName: 'showSpacedText', numArgs: 1, variableArgs: false },
'\'': { fnName: 'nextLineShowText', numArgs: 1, variableArgs: false },
'"': { fnName: 'nextLineSetSpacingShowText', numArgs: 3,
BT: { id: OPS.beginText, numArgs: 0, variableArgs: false },
ET: { id: OPS.endText, numArgs: 0, variableArgs: false },
Tc: { id: OPS.setCharSpacing, numArgs: 1, variableArgs: false },
Tw: { id: OPS.setWordSpacing, numArgs: 1, variableArgs: false },
Tz: { id: OPS.setHScale, numArgs: 1, variableArgs: false },
TL: { id: OPS.setLeading, numArgs: 1, variableArgs: false },
Tf: { id: OPS.setFont, numArgs: 2, variableArgs: false },
Tr: { id: OPS.setTextRenderingMode, numArgs: 1, variableArgs: false },
Ts: { id: OPS.setTextRise, numArgs: 1, variableArgs: false },
Td: { id: OPS.moveText, numArgs: 2, variableArgs: false },
TD: { id: OPS.setLeadingMoveText, numArgs: 2, variableArgs: false },
Tm: { id: OPS.setTextMatrix, numArgs: 6, variableArgs: false },
'T*': { id: OPS.nextLine, numArgs: 0, variableArgs: false },
Tj: { id: OPS.showText, numArgs: 1, variableArgs: false },
TJ: { id: OPS.showSpacedText, numArgs: 1, variableArgs: false },
'\'': { id: OPS.nextLineShowText, numArgs: 1, variableArgs: false },
'"': { id: OPS.nextLineSetSpacingShowText, numArgs: 3,
variableArgs: false },
// Type3 fonts
d0: { fnName: 'setCharWidth', numArgs: 2, variableArgs: false },
d1: { fnName: 'setCharWidthAndBounds', numArgs: 6, variableArgs: false },
d0: { id: OPS.setCharWidth, numArgs: 2, variableArgs: false },
d1: { id: OPS.setCharWidthAndBounds, numArgs: 6, variableArgs: false },
// Color
CS: { fnName: 'setStrokeColorSpace', numArgs: 1, variableArgs: false },
cs: { fnName: 'setFillColorSpace', numArgs: 1, variableArgs: false },
SC: { fnName: 'setStrokeColor', numArgs: 4, variableArgs: true },
SCN: { fnName: 'setStrokeColorN', numArgs: 33, variableArgs: true },
sc: { fnName: 'setFillColor', numArgs: 4, variableArgs: true },
scn: { fnName: 'setFillColorN', numArgs: 33, variableArgs: true },
G: { fnName: 'setStrokeGray', numArgs: 1, variableArgs: false },
g: { fnName: 'setFillGray', numArgs: 1, variableArgs: false },
RG: { fnName: 'setStrokeRGBColor', numArgs: 3, variableArgs: false },
rg: { fnName: 'setFillRGBColor', numArgs: 3, variableArgs: false },
K: { fnName: 'setStrokeCMYKColor', numArgs: 4, variableArgs: false },
k: { fnName: 'setFillCMYKColor', numArgs: 4, variableArgs: false },
CS: { id: OPS.setStrokeColorSpace, numArgs: 1, variableArgs: false },
cs: { id: OPS.setFillColorSpace, numArgs: 1, variableArgs: false },
SC: { id: OPS.setStrokeColor, numArgs: 4, variableArgs: true },
SCN: { id: OPS.setStrokeColorN, numArgs: 33, variableArgs: true },
sc: { id: OPS.setFillColor, numArgs: 4, variableArgs: true },
scn: { id: OPS.setFillColorN, numArgs: 33, variableArgs: true },
G: { id: OPS.setStrokeGray, numArgs: 1, variableArgs: false },
g: { id: OPS.setFillGray, numArgs: 1, variableArgs: false },
RG: { id: OPS.setStrokeRGBColor, numArgs: 3, variableArgs: false },
rg: { id: OPS.setFillRGBColor, numArgs: 3, variableArgs: false },
K: { id: OPS.setStrokeCMYKColor, numArgs: 4, variableArgs: false },
k: { id: OPS.setFillCMYKColor, numArgs: 4, variableArgs: false },
// Shading
sh: { fnName: 'shadingFill', numArgs: 1, variableArgs: false },
sh: { id: OPS.shadingFill, numArgs: 1, variableArgs: false },
// Images
BI: { fnName: 'beginInlineImage', numArgs: 0, variableArgs: false },
ID: { fnName: 'beginImageData', numArgs: 0, variableArgs: false },
EI: { fnName: 'endInlineImage', numArgs: 1, variableArgs: false },
BI: { id: OPS.beginInlineImage, numArgs: 0, variableArgs: false },
ID: { id: OPS.beginImageData, numArgs: 0, variableArgs: false },
EI: { id: OPS.endInlineImage, numArgs: 1, variableArgs: false },
// XObjects
Do: { fnName: 'paintXObject', numArgs: 1, variableArgs: false },
MP: { fnName: 'markPoint', numArgs: 1, variableArgs: false },
DP: { fnName: 'markPointProps', numArgs: 2, variableArgs: false },
BMC: { fnName: 'beginMarkedContent', numArgs: 1, variableArgs: false },
BDC: { fnName: 'beginMarkedContentProps', numArgs: 2, variableArgs: false },
EMC: { fnName: 'endMarkedContent', numArgs: 0, variableArgs: false },
Do: { id: OPS.paintXObject, numArgs: 1, variableArgs: false },
MP: { id: OPS.markPoint, numArgs: 1, variableArgs: false },
DP: { id: OPS.markPointProps, numArgs: 2, variableArgs: false },
BMC: { id: OPS.beginMarkedContent, numArgs: 1, variableArgs: false },
BDC: { id: OPS.beginMarkedContentProps, numArgs: 2,
variableArgs: false },
EMC: { id: OPS.endMarkedContent, numArgs: 0, variableArgs: false },
// Compatibility
BX: { fnName: 'beginCompat', numArgs: 0, variableArgs: false },
EX: { fnName: 'endCompat', numArgs: 0, variableArgs: false },
BX: { id: OPS.beginCompat, numArgs: 0, variableArgs: false },
EX: { id: OPS.endCompat, numArgs: 0, variableArgs: false },
// (reserved partial commands for the lexer)
BM: null,
@ -218,17 +219,17 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
// There is also a group colorspace, but since we put everything in
// RGB I'm not sure we need it.
}
operatorList.addOp('beginGroup', [groupOptions]);
operatorList.addOp(OPS.beginGroup, [groupOptions]);
}
operatorList.addOp('paintFormXObjectBegin', [matrix, bbox]);
operatorList.addOp(OPS.paintFormXObjectBegin, [matrix, bbox]);
this.getOperatorList(xobj, xobj.dict.get('Resources') || resources,
operatorList);
operatorList.addOp('paintFormXObjectEnd', []);
operatorList.addOp(OPS.paintFormXObjectEnd, []);
if (group) {
operatorList.addOp('endGroup', [groupOptions]);
operatorList.addOp(OPS.endGroup, [groupOptions]);
}
},
@ -259,7 +260,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var decode = dict.get('Decode', 'D');
var inverseDecode = !!decode && decode[0] > 0;
operatorList.addOp('paintImageMaskXObject',
operatorList.addOp(OPS.paintImageMaskXObject,
[PDFImage.createMask(imgArray, width, height,
inverseDecode)]
);
@ -277,7 +278,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var imageObj = new PDFImage(this.xref, resources, image,
inline, null, null);
var imgData = imageObj.getImageData();
operatorList.addOp('paintInlineImageXObject', [imgData]);
operatorList.addOp(OPS.paintInlineImageXObject, [imgData]);
return;
}
@ -291,7 +292,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
if (!softMask && !mask && image instanceof JpegStream &&
image.isNativelySupported(this.xref, resources)) {
// These JPEGs don't need any more processing so we can just send it.
operatorList.addOp('paintJpegXObject', args);
operatorList.addOp(OPS.paintJpegXObject, args);
this.handler.send(
'obj', [objId, this.pageIndex, 'JpegStream', image.getIR()]);
return;
@ -303,7 +304,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
self.handler.send('obj', [objId, self.pageIndex, 'Image', imgData]);
}, self.handler, self.xref, resources, image, inline);
operatorList.addOp('paintImageXObject', args);
operatorList.addOp(OPS.paintImageXObject, args);
},
handleTilingType: function PartialEvaluator_handleTilingType(
@ -442,7 +443,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
setGStateForKey(gStateObj, key, value);
}
operatorList.addOp('setGState', [gStateObj]);
operatorList.addOp(OPS.setGState, [gStateObj]);
},
loadFont: function PartialEvaluator_loadFont(fontName, font, xref,
@ -557,7 +558,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
continue;
}
var fn = opSpec.fnName;
var fn = opSpec.id;
// Validate the number of arguments for the command
if (opSpec.variableArgs) {
@ -640,7 +641,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var loadedName = self.handleSetFont(resources, args, null,
operatorList);
operatorList.addDependency(loadedName);
fn = 'setFont';
fn = OPS.setFont;
args[0] = loadedName;
} else if (cmd == 'EI') {
self.buildPaintImageXObject(resources, args[0], true, operatorList);
@ -675,11 +676,11 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
switch (fn) {
// Parse the ColorSpace data to a raw format.
case 'setFillColorSpace':
case 'setStrokeColorSpace':
case OPS.setFillColorSpace:
case OPS.setStrokeColorSpace:
args = [ColorSpace.parseToIR(args[0], xref, resources)];
break;
case 'shadingFill':
case OPS.shadingFill:
var shadingRes = resources.get('Shading');
if (!shadingRes)
error('No shading resource found');
@ -692,9 +693,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
shading, null, xref, resources);
var patternIR = shadingFill.getIR();
args = [patternIR];
fn = 'shadingFill';
fn = OPS.shadingFill;
break;
case 'setGState':
case OPS.setGState:
var dictName = args[0];
var extGState = resources.get('ExtGState');
@ -1330,6 +1331,18 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
PartialEvaluator.optimizeQueue =
function PartialEvaluator_optimizeQueue(queue) {
function squash(array, index, howMany, element) {
if (isArray(array)) {
array.splice(index, howMany, element);
} else {
// Replace the element.
array[index] = element;
// Shift everything after the element up.
var sub = array.subarray(index + howMany);
array.set(sub, index + 1);
}
}
var fnArray = queue.fnArray, argsArray = queue.argsArray;
// grouping paintInlineImageXObject's into paintInlineImageXObjectGroup
// searching for (save, transform, paintInlineImageXObject, restore)+
@ -1337,10 +1350,10 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var MAX_IMAGES_IN_INLINE_IMAGES_BLOCK = 200;
var MAX_WIDTH = 1000;
var IMAGE_PADDING = 1;
for (var i = 0, ii = fnArray.length; i < ii; i++) {
if (fnArray[i] === 'paintInlineImageXObject' &&
fnArray[i - 2] === 'save' && fnArray[i - 1] === 'transform' &&
fnArray[i + 1] === 'restore') {
for (var i = 0, ii = argsArray.length; i < ii; i++) {
if (fnArray[i] === OPS.paintInlineImageXObject &&
fnArray[i - 2] === OPS.save && fnArray[i - 1] === OPS.transform &&
fnArray[i + 1] === OPS.restore) {
var j = i - 2;
for (i += 2; i < ii && fnArray[i - 4] === fnArray[i]; i++) {
}
@ -1405,21 +1418,21 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}
}
// replacing queue items
fnArray.splice(j, count * 4, ['paintInlineImageXObjectGroup']);
squash(fnArray, j, count * 4, OPS.paintInlineImageXObjectGroup);
argsArray.splice(j, count * 4,
[{width: imgWidth, height: imgHeight, data: imgData}, map]);
i = j;
ii = fnArray.length;
ii = argsArray.length;
}
}
// grouping paintImageMaskXObject's into paintImageMaskXObjectGroup
// searching for (save, transform, paintImageMaskXObject, restore)+
var MIN_IMAGES_IN_MASKS_BLOCK = 10;
var MAX_IMAGES_IN_MASKS_BLOCK = 100;
for (var i = 0, ii = fnArray.length; i < ii; i++) {
if (fnArray[i] === 'paintImageMaskXObject' &&
fnArray[i - 2] === 'save' && fnArray[i - 1] === 'transform' &&
fnArray[i + 1] === 'restore') {
for (var i = 0, ii = argsArray.length; i < ii; i++) {
if (fnArray[i] === OPS.paintImageMaskXObject &&
fnArray[i - 2] === OPS.save && fnArray[i - 1] === OPS.transform &&
fnArray[i + 1] === OPS.restore) {
var j = i - 2;
for (i += 2; i < ii && fnArray[i - 4] === fnArray[i]; i++) {
}
@ -1436,10 +1449,10 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
height: maskParams.height, transform: transform});
}
// replacing queue items
fnArray.splice(j, count * 4, ['paintImageMaskXObjectGroup']);
squash(fnArray, j, count * 4, OPS.paintImageMaskXObjectGroup);
argsArray.splice(j, count * 4, [images]);
i = j;
ii = fnArray.length;
ii = argsArray.length;
}
}
};
@ -1448,25 +1461,40 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
return PartialEvaluator;
})();
var OperatorList = (function OperatorListClosure() {
var CHUNK_SIZE = 100;
function OperatorList(messageHandler, pageIndex) {
this.messageHandler = messageHandler;
// When there isn't a message handler the fn array needs to be able to grow
// since we can't flush the operators.
if (messageHandler) {
this.fnArray = new Uint8Array(CHUNK_SIZE);
} else {
this.fnArray = [];
}
this.argsArray = [];
this.dependencies = {},
this.pageIndex = pageIndex;
this.fnIndex = 0;
}
OperatorList.prototype = {
get length() {
return this.argsArray.length;
},
addOp: function(fn, args) {
if (this.messageHandler) {
this.fnArray[this.fnIndex++] = fn;
this.argsArray.push(args);
if (this.fnIndex >= CHUNK_SIZE) {
this.flush();
}
} else {
this.fnArray.push(fn);
this.argsArray.push(args);
if (this.messageHandler && this.fnArray.length >= CHUNK_SIZE) {
this.flush();
}
},
@ -1475,7 +1503,7 @@ var OperatorList = (function OperatorListClosure() {
return;
}
this.dependencies[dependency] = true;
this.addOp('dependency', [dependency]);
this.addOp(OPS.dependency, [dependency]);
},
addDependencies: function(dependencies) {
@ -1485,15 +1513,17 @@ var OperatorList = (function OperatorListClosure() {
},
addOpList: function(opList) {
Util.concatenateToArray(this.fnArray, opList.fnArray);
Util.concatenateToArray(this.argsArray, opList.argsArray);
Util.extendObj(this.dependencies, opList.dependencies);
for (var i = 0, ii = opList.length; i < ii; i++) {
this.addOp(opList.fnArray[i], opList.argsArray[i]);
}
},
getIR: function() {
return {
fnArray: this.fnArray,
argsArray: this.argsArray
argsArray: this.argsArray,
length: this.length
};
},
@ -1503,12 +1533,13 @@ var OperatorList = (function OperatorListClosure() {
operatorList: {
fnArray: this.fnArray,
argsArray: this.argsArray,
lastChunk: lastChunk
lastChunk: lastChunk,
length: this.length
},
pageIndex: this.pageIndex
});
this.dependencies = [];
this.fnArray = [];
this.fnIndex = 0;
this.argsArray = [];
}
};

View File

@ -481,10 +481,10 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
*/
_renderPageChunk: function PDFPageProxy_renderPageChunk(operatorListChunk) {
// Add the new chunk to the current operator list.
Util.concatenateToArray(this.operatorList.fnArray,
operatorListChunk.fnArray);
Util.concatenateToArray(this.operatorList.argsArray,
operatorListChunk.argsArray);
for (var i = 0, ii = operatorListChunk.length; i < ii; i++) {
this.operatorList.fnArray.push(operatorListChunk.fnArray[i]);
this.operatorList.argsArray.push(operatorListChunk.argsArray[i]);
}
this.operatorList.lastChunk = operatorListChunk.lastChunk;
// Notify all the rendering tasks there are more operators to be consumed.
@ -1094,7 +1094,7 @@ var InternalRenderTask = (function InternalRenderTaskClosure() {
this.operatorListIdx,
this._continue.bind(this),
this.stepper);
if (this.operatorListIdx === this.operatorList.fnArray.length) {
if (this.operatorListIdx === this.operatorList.argsArray.length) {
this.running = false;
if (this.operatorList.lastChunk) {
this.gfx.endDrawing();

View File

@ -17,7 +17,7 @@
/* globals ColorSpace, DeviceCmykCS, DeviceGrayCS, DeviceRgbCS, error,
FONT_IDENTITY_MATRIX, IDENTITY_MATRIX, ImageData, isArray, isNum,
Pattern, TilingPattern, TODO, Util, warn, assert, info,
TextRenderingMode */
TextRenderingMode, OPS */
'use strict';
@ -538,7 +538,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
var commonObjs = this.commonObjs;
var objs = this.objs;
var fnName;
var fnId;
var slowCommands = this.slowCommands;
while (true) {
@ -547,10 +547,10 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
return i;
}
fnName = fnArray[i];
fnId = fnArray[i];
if (fnName !== 'dependency') {
this[fnName].apply(this, argsArray[i]);
if (fnId !== OPS.dependency) {
this[fnId].apply(this, argsArray[i]);
} else {
var deps = argsArray[i];
for (var n = 0, nn = deps.length; n < nn; n++) {
@ -580,7 +580,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
// If the execution took longer then a certain amount of time, shedule
// to continue exeution after a short delay.
// However, this is only possible if a 'continueCallback' is passed in.
if (continueCallback && slowCommands[fnName] && Date.now() > endTime) {
if (continueCallback && slowCommands[fnId] && Date.now() > endTime) {
setTimeout(continueCallback, 0);
return i;
}
@ -1867,6 +1867,10 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
};
for (var op in OPS) {
CanvasGraphics.prototype[OPS[op]] = CanvasGraphics.prototype[op];
}
return CanvasGraphics;
})();

View File

@ -16,7 +16,7 @@
*/
/* globals Util, isDict, isName, stringToPDFString, TODO, Dict, Stream,
stringToBytes, PDFJS, isWorker, assert, NotImplementedException,
Promise, isArray, ObjectLoader, isValidUrl, OperatorList */
Promise, isArray, ObjectLoader, isValidUrl, OperatorList, OPS */
'use strict';
@ -188,9 +188,9 @@ var Annotation = (function AnnotationClosure() {
resourcesPromise.then(function(resources) {
var opList = new OperatorList();
opList.addOp('beginAnnotation', [data.rect, transform, matrix]);
opList.addOp(OPS.beginAnnotation, [data.rect, transform, matrix]);
evaluator.getOperatorList(this.appearance, resources, opList);
opList.addOp('endAnnotation', []);
opList.addOp(OPS.endAnnotation, []);
promise.resolve(opList);
}.bind(this));
@ -284,12 +284,12 @@ var Annotation = (function AnnotationClosure() {
annotationPromises.push(annotations[i].getOperatorList(partialEvaluator));
}
Promise.all(annotationPromises).then(function(datas) {
opList.addOp('beginAnnotations', []);
opList.addOp(OPS.beginAnnotations, []);
for (var i = 0, n = datas.length; i < n; ++i) {
var annotOpList = datas[i];
opList.addOpList(annotOpList);
}
opList.addOp('endAnnotations', []);
opList.addOp(OPS.endAnnotations, []);
annotationsReadyPromise.resolve();
}, reject);
@ -465,10 +465,10 @@ var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
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 fnName = appearanceFnArray[i];
var fnId = appearanceFnArray[i];
var args = appearanceArgsArray[i];
if (fnName === 'setFont') {
if (fnId === OPS.setFont) {
data.fontRefName = args[0];
var size = args[1];
if (size < 0) {
@ -478,9 +478,9 @@ var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
data.fontDirection = 1;
data.fontSize = size;
}
} else if (fnName === 'setFillRGBColor') {
} else if (fnId === OPS.setFillRGBColor) {
data.rgb = args;
} else if (fnName === 'setFillGray') {
} else if (fnId === OPS.setFillGray) {
var rgbValue = args[0] * 255;
data.rgb = [rgbValue, rgbValue, rgbValue];
}

View File

@ -49,6 +49,98 @@ if (!globalScope.PDFJS) {
globalScope.PDFJS.pdfBug = false;
// All the possible operations for an operator list.
var OPS = PDFJS.OPS = {
// Intentially start from 1 so it is easy to spot bad operators that will be
// 0's.
dependency: 1,
setLineWidth: 2,
setLineCap: 3,
setLineJoin: 4,
setMiterLimit: 5,
setDash: 6,
setRenderingIntent: 7,
setFlatness: 8,
setGState: 9,
save: 10,
restore: 11,
transform: 12,
moveTo: 13,
lineTo: 14,
curveTo: 15,
curveTo2: 16,
curveTo3: 17,
closePath: 18,
rectangle: 19,
stroke: 20,
closeStroke: 21,
fill: 22,
eoFill: 23,
fillStroke: 24,
eoFillStroke: 25,
closeFillStroke: 26,
closeEOFillStroke: 27,
endPath: 28,
clip: 29,
eoClip: 30,
beginText: 31,
endText: 32,
setCharSpacing: 33,
setWordSpacing: 34,
setHScale: 35,
setLeading: 36,
setFont: 37,
setTextRenderingMode: 38,
setTextRise: 39,
moveText: 40,
setLeadingMoveText: 41,
setTextMatrix: 42,
nextLine: 43,
showText: 44,
showSpacedText: 45,
nextLineShowText: 46,
nextLineSetSpacingShowText: 47,
setCharWidth: 48,
setCharWidthAndBounds: 49,
setStrokeColorSpace: 50,
setFillColorSpace: 51,
setStrokeColor: 52,
setStrokeColorN: 53,
setFillColor: 54,
setFillColorN: 55,
setStrokeGray: 56,
setFillGray: 57,
setStrokeRGBColor: 58,
setFillRGBColor: 59,
setStrokeCMYKColor: 60,
setFillCMYKColor: 61,
shadingFill: 62,
beginInlineImage: 63,
beginImageData: 64,
endInlineImage: 65,
paintXObject: 66,
markPoint: 67,
markPointProps: 68,
beginMarkedContent: 69,
beginMarkedContentProps: 70,
endMarkedContent: 71,
beginCompat: 72,
endCompat: 73,
paintFormXObjectBegin: 74,
paintFormXObjectEnd: 75,
beginGroup: 76,
endGroup: 77,
beginAnnotations: 78,
endAnnotations: 79,
beginAnnotation: 80,
endAnnotation: 81,
paintJpegXObject: 82,
paintImageMaskXObject: 83,
paintImageMaskXObjectGroup: 84,
paintImageXObject: 85,
paintInlineImageXObject: 86,
paintInlineImageXObjectGroup: 87
};
// Use only for debugging purposes. This should not be used in any code that is
// in mozilla master.

View File

@ -1,6 +1,6 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* globals expect, it, describe, PartialEvaluator, StringStream */
/* globals expect, it, describe, PartialEvaluator, StringStream, OPS */
'use strict';
@ -39,7 +39,7 @@ describe('evaluator', function() {
var result = evaluator.getOperatorList(stream, new ResourcesMock());
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
expect(result.fnArray.length).toEqual(1);
expect(result.fnArray[0]).toEqual('save');
expect(result.fnArray[0]).toEqual(OPS.save);
expect(result.argsArray[0].length).toEqual(0);
});
@ -51,7 +51,7 @@ describe('evaluator', function() {
var result = evaluator.getOperatorList(stream, new ResourcesMock());
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
expect(result.fnArray.length).toEqual(1);
expect(result.fnArray[0]).toEqual('restore');
expect(result.fnArray[0]).toEqual(OPS.restore);
});
it('should handle two glued operations', function() {
@ -64,8 +64,8 @@ describe('evaluator', function() {
var result = evaluator.getOperatorList(stream, resources);
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
expect(result.fnArray.length).toEqual(2);
expect(result.fnArray[0]).toEqual('paintXObject');
expect(result.fnArray[1]).toEqual('restore');
expect(result.fnArray[0]).toEqual(OPS.paintXObject);
expect(result.fnArray[1]).toEqual(OPS.restore);
});
it('should handle tree glued operations', function() {
@ -76,9 +76,9 @@ describe('evaluator', function() {
var result = evaluator.getOperatorList(stream, new ResourcesMock());
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
expect(result.fnArray.length).toEqual(3);
expect(result.fnArray[0]).toEqual('save');
expect(result.fnArray[1]).toEqual('save');
expect(result.fnArray[2]).toEqual('save');
expect(result.fnArray[0]).toEqual(OPS.save);
expect(result.fnArray[1]).toEqual(OPS.save);
expect(result.fnArray[2]).toEqual(OPS.save);
});
it('should handle three glued operations #2', function() {
@ -91,9 +91,9 @@ describe('evaluator', function() {
var result = evaluator.getOperatorList(stream, resources);
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
expect(result.fnArray.length).toEqual(3);
expect(result.fnArray[0]).toEqual('eoFillStroke');
expect(result.fnArray[1]).toEqual('fillStroke');
expect(result.fnArray[2]).toEqual('eoFill');
expect(result.fnArray[0]).toEqual(OPS.eoFillStroke);
expect(result.fnArray[1]).toEqual(OPS.fillStroke);
expect(result.fnArray[2]).toEqual(OPS.eoFill);
});
it('should handle glued operations and operands', function() {
@ -104,8 +104,8 @@ describe('evaluator', function() {
var result = evaluator.getOperatorList(stream, new ResourcesMock());
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
expect(result.fnArray.length).toEqual(2);
expect(result.fnArray[0]).toEqual('save');
expect(result.fnArray[1]).toEqual('setTextRise');
expect(result.fnArray[0]).toEqual(OPS.save);
expect(result.fnArray[1]).toEqual(OPS.setTextRise);
expect(result.argsArray.length).toEqual(2);
expect(result.argsArray[1].length).toEqual(1);
expect(result.argsArray[1][0]).toEqual(5);
@ -119,9 +119,9 @@ describe('evaluator', function() {
var result = evaluator.getOperatorList(stream, new ResourcesMock());
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
expect(result.fnArray.length).toEqual(3);
expect(result.fnArray[0]).toEqual('setFlatness');
expect(result.fnArray[1]).toEqual('setRenderingIntent');
expect(result.fnArray[2]).toEqual('save');
expect(result.fnArray[0]).toEqual(OPS.setFlatness);
expect(result.fnArray[1]).toEqual(OPS.setRenderingIntent);
expect(result.fnArray[2]).toEqual(OPS.save);
expect(result.argsArray.length).toEqual(3);
expect(result.argsArray[0].length).toEqual(1);
expect(result.argsArray[0][0]).toEqual(true);
@ -141,7 +141,7 @@ describe('evaluator', function() {
var result = evaluator.getOperatorList(stream, new ResourcesMock());
expect(result.argsArray[0][0]).toEqual(5);
expect(result.argsArray[0][1]).toEqual(1);
expect(result.fnArray[0]).toEqual('setCharWidth');
expect(result.fnArray[0]).toEqual(OPS.setCharWidth);
});
it('should execute if too many arguments', function() {
var evaluator = new PartialEvaluator(new PdfManagerMock(),
@ -152,7 +152,7 @@ describe('evaluator', function() {
expect(result.argsArray[0][0]).toEqual(5);
expect(result.argsArray[0][1]).toEqual(1);
expect(result.argsArray[0][2]).toEqual(4);
expect(result.fnArray[0]).toEqual('setCharWidth');
expect(result.fnArray[0]).toEqual(OPS.setCharWidth);
});
it('should skip if too few arguments', function() {
var evaluator = new PartialEvaluator(new PdfManagerMock(),

View File

@ -240,6 +240,8 @@ var Stepper = (function StepperClosure() {
return out;
}
var opMap = null;
var glyphCommands = {
'showText': 0,
'showSpacedText': 0,
@ -271,6 +273,12 @@ var Stepper = (function StepperClosure() {
headerRow.appendChild(c('th', 'args'));
panel.appendChild(content);
this.table = table;
if (!opMap) {
opMap = Object.create(null);
for (var key in PDFJS.OPS) {
opMap[PDFJS.OPS[key]] = key;
}
}
},
updateOperatorList: function updateOperatorList(operatorList) {
var self = this;
@ -300,7 +308,7 @@ var Stepper = (function StepperClosure() {
breakCell.appendChild(cbox);
line.appendChild(breakCell);
line.appendChild(c('td', i.toString()));
var fn = operatorList.fnArray[i];
var fn = opMap[operatorList.fnArray[i]];
var decArgs = args;
if (fn in glyphCommands) {
var glyphIndex = glyphCommands[fn];