Incrementally render by sending the operator list by chunks as they're ready.
This commit is contained in:
parent
f7d2a09bf8
commit
bf72bc94e2
@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
/* globals Util, isDict, isName, stringToPDFString, TODO, Dict, Stream,
|
/* globals Util, isDict, isName, stringToPDFString, TODO, Dict, Stream,
|
||||||
stringToBytes, PDFJS, isWorker, assert, NotImplementedException,
|
stringToBytes, PDFJS, isWorker, assert, NotImplementedException,
|
||||||
Promise, isArray, ObjectLoader, isValidUrl */
|
Promise, isArray, ObjectLoader, isValidUrl, OperatorList */
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@ -162,13 +162,7 @@ var Annotation = (function AnnotationClosure() {
|
|||||||
var promise = new Promise();
|
var promise = new Promise();
|
||||||
|
|
||||||
if (!this.appearance) {
|
if (!this.appearance) {
|
||||||
promise.resolve({
|
promise.resolve(new OperatorList());
|
||||||
queue: {
|
|
||||||
fnArray: [],
|
|
||||||
argsArray: []
|
|
||||||
},
|
|
||||||
dependency: {}
|
|
||||||
});
|
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,19 +186,11 @@ var Annotation = (function AnnotationClosure() {
|
|||||||
var border = data.border;
|
var border = data.border;
|
||||||
|
|
||||||
resourcesPromise.then(function(resources) {
|
resourcesPromise.then(function(resources) {
|
||||||
var listPromise = evaluator.getOperatorList(this.appearance, resources);
|
var opList = new OperatorList();
|
||||||
listPromise.then(function(appearanceStreamData) {
|
opList.addOp('beginAnnotation', [data.rect, transform, matrix]);
|
||||||
var fnArray = appearanceStreamData.queue.fnArray;
|
evaluator.getOperatorList(this.appearance, resources, opList);
|
||||||
var argsArray = appearanceStreamData.queue.argsArray;
|
opList.addOp('endAnnotation', []);
|
||||||
|
promise.resolve(opList);
|
||||||
fnArray.unshift('beginAnnotation');
|
|
||||||
argsArray.unshift([data.rect, transform, matrix]);
|
|
||||||
|
|
||||||
fnArray.push('endAnnotation');
|
|
||||||
argsArray.push([]);
|
|
||||||
|
|
||||||
promise.resolve(appearanceStreamData);
|
|
||||||
});
|
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
@ -284,7 +270,7 @@ var Annotation = (function AnnotationClosure() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Annotation.appendToOperatorList = function Annotation_appendToOperatorList(
|
Annotation.appendToOperatorList = function Annotation_appendToOperatorList(
|
||||||
annotations, pageQueue, pdfManager, dependencies, partialEvaluator) {
|
annotations, opList, pdfManager, partialEvaluator) {
|
||||||
|
|
||||||
function reject(e) {
|
function reject(e) {
|
||||||
annotationsReadyPromise.reject(e);
|
annotationsReadyPromise.reject(e);
|
||||||
@ -296,22 +282,13 @@ var Annotation = (function AnnotationClosure() {
|
|||||||
for (var i = 0, n = annotations.length; i < n; ++i) {
|
for (var i = 0, n = annotations.length; i < n; ++i) {
|
||||||
annotationPromises.push(annotations[i].getOperatorList(partialEvaluator));
|
annotationPromises.push(annotations[i].getOperatorList(partialEvaluator));
|
||||||
}
|
}
|
||||||
|
|
||||||
Promise.all(annotationPromises).then(function(datas) {
|
Promise.all(annotationPromises).then(function(datas) {
|
||||||
var fnArray = pageQueue.fnArray;
|
opList.addOp('beginAnnotations', []);
|
||||||
var argsArray = pageQueue.argsArray;
|
|
||||||
fnArray.push('beginAnnotations');
|
|
||||||
argsArray.push([]);
|
|
||||||
for (var i = 0, n = datas.length; i < n; ++i) {
|
for (var i = 0, n = datas.length; i < n; ++i) {
|
||||||
var annotationData = datas[i];
|
var annotOpList = datas[i];
|
||||||
var annotationQueue = annotationData.queue;
|
opList.addOpList(annotOpList);
|
||||||
Util.concatenateToArray(fnArray, annotationQueue.fnArray);
|
|
||||||
Util.concatenateToArray(argsArray, annotationQueue.argsArray);
|
|
||||||
Util.extendObj(dependencies, annotationData.dependencies);
|
|
||||||
}
|
}
|
||||||
fnArray.push('endAnnotations');
|
opList.addOp('endAnnotations', []);
|
||||||
argsArray.push([]);
|
|
||||||
|
|
||||||
annotationsReadyPromise.resolve();
|
annotationsReadyPromise.resolve();
|
||||||
}, reject);
|
}, reject);
|
||||||
|
|
||||||
@ -458,8 +435,8 @@ var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
|
|||||||
|
|
||||||
getOperatorList: function TextWidgetAnnotation_getOperatorList(evaluator) {
|
getOperatorList: function TextWidgetAnnotation_getOperatorList(evaluator) {
|
||||||
|
|
||||||
|
|
||||||
var promise = new Promise();
|
var promise = new Promise();
|
||||||
|
var opList = new OperatorList();
|
||||||
var data = this.data;
|
var data = this.data;
|
||||||
|
|
||||||
// Even if there is an appearance stream, ignore it. This is the
|
// Even if there is an appearance stream, ignore it. This is the
|
||||||
@ -467,65 +444,44 @@ var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
|
|||||||
|
|
||||||
var defaultAppearance = data.defaultAppearance;
|
var defaultAppearance = data.defaultAppearance;
|
||||||
if (!defaultAppearance) {
|
if (!defaultAppearance) {
|
||||||
promise.resolve({
|
promise.resolve(opList);
|
||||||
queue: {
|
|
||||||
fnArray: [],
|
|
||||||
argsArray: []
|
|
||||||
},
|
|
||||||
dependency: {}
|
|
||||||
});
|
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Include any font resources found in the default appearance
|
// Include any font resources found in the default appearance
|
||||||
|
|
||||||
var stream = new Stream(stringToBytes(defaultAppearance));
|
var stream = new Stream(stringToBytes(defaultAppearance));
|
||||||
var listPromise = evaluator.getOperatorList(stream, this.fieldResources);
|
evaluator.getOperatorList(stream, this.fieldResources, opList);
|
||||||
listPromise.then(function(appearanceStreamData) {
|
var appearanceFnArray = opList.fnArray;
|
||||||
var appearanceFnArray = appearanceStreamData.queue.fnArray;
|
var appearanceArgsArray = opList.argsArray;
|
||||||
var appearanceArgsArray = appearanceStreamData.queue.argsArray;
|
var fnArray = [];
|
||||||
var fnArray = [];
|
var argsArray = [];
|
||||||
var argsArray = [];
|
|
||||||
|
|
||||||
// TODO(mack): Add support for stroke color
|
// TODO(mack): Add support for stroke color
|
||||||
data.rgb = [0, 0, 0];
|
data.rgb = [0, 0, 0];
|
||||||
for (var i = 0, n = fnArray.length; i < n; ++i) {
|
// TODO THIS DOESN'T MAKE ANY SENSE SINCE THE fnArray IS EMPTY!
|
||||||
var fnName = appearanceFnArray[i];
|
for (var i = 0, n = fnArray.length; i < n; ++i) {
|
||||||
var args = appearanceArgsArray[i];
|
var fnName = appearanceFnArray[i];
|
||||||
if (fnName === 'dependency') {
|
var args = appearanceArgsArray[i];
|
||||||
var dependency = args[i];
|
|
||||||
if (dependency.indexOf('g_font_') === 0) {
|
if (fnName === 'setFont') {
|
||||||
data.fontRefName = dependency;
|
data.fontRefName = args[0];
|
||||||
}
|
var size = args[1];
|
||||||
fnArray.push(fnName);
|
if (size < 0) {
|
||||||
argsArray.push(args);
|
data.fontDirection = -1;
|
||||||
} else if (fnName === 'setFont') {
|
data.fontSize = -size;
|
||||||
data.fontRefName = args[0];
|
} else {
|
||||||
var size = args[1];
|
data.fontDirection = 1;
|
||||||
if (size < 0) {
|
data.fontSize = size;
|
||||||
data.fontDirection = -1;
|
|
||||||
data.fontSize = -size;
|
|
||||||
} else {
|
|
||||||
data.fontDirection = 1;
|
|
||||||
data.fontSize = size;
|
|
||||||
}
|
|
||||||
} else if (fnName === 'setFillRGBColor') {
|
|
||||||
data.rgb = args;
|
|
||||||
} else if (fnName === 'setFillGray') {
|
|
||||||
var rgbValue = args[0] * 255;
|
|
||||||
data.rgb = [rgbValue, rgbValue, rgbValue];
|
|
||||||
}
|
}
|
||||||
|
} else if (fnName === 'setFillRGBColor') {
|
||||||
|
data.rgb = args;
|
||||||
|
} else if (fnName === 'setFillGray') {
|
||||||
|
var rgbValue = args[0] * 255;
|
||||||
|
data.rgb = [rgbValue, rgbValue, rgbValue];
|
||||||
}
|
}
|
||||||
promise.resolve({
|
}
|
||||||
queue: {
|
promise.resolve(opList);
|
||||||
fnArray: fnArray,
|
|
||||||
argsArray: argsArray
|
|
||||||
},
|
|
||||||
dependency: {}
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -557,13 +513,7 @@ var TextAnnotation = (function TextAnnotationClosure() {
|
|||||||
|
|
||||||
getOperatorList: function TextAnnotation_getOperatorList(evaluator) {
|
getOperatorList: function TextAnnotation_getOperatorList(evaluator) {
|
||||||
var promise = new Promise();
|
var promise = new Promise();
|
||||||
promise.resolve({
|
promise.resolve(new OperatorList());
|
||||||
queue: {
|
|
||||||
fnArray: [],
|
|
||||||
argsArray: []
|
|
||||||
},
|
|
||||||
dependency: {}
|
|
||||||
});
|
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
338
src/api.js
338
src/api.js
@ -17,7 +17,7 @@
|
|||||||
/* globals CanvasGraphics, combineUrl, createScratchCanvas, error, ErrorFont,
|
/* globals CanvasGraphics, combineUrl, createScratchCanvas, error, ErrorFont,
|
||||||
Font, FontLoader, globalScope, info, isArrayBuffer, loadJpegStream,
|
Font, FontLoader, globalScope, info, isArrayBuffer, loadJpegStream,
|
||||||
MessageHandler, PDFJS, PDFObjects, Promise, StatTimer, warn,
|
MessageHandler, PDFJS, PDFObjects, Promise, StatTimer, warn,
|
||||||
WorkerMessageHandler, PasswordResponses */
|
WorkerMessageHandler, PasswordResponses, Util */
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@ -222,6 +222,7 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
|
|||||||
this.objs = new PDFObjects();
|
this.objs = new PDFObjects();
|
||||||
this.renderInProgress = false;
|
this.renderInProgress = false;
|
||||||
this.cleanupAfterRender = false;
|
this.cleanupAfterRender = false;
|
||||||
|
this.renderTasks = [];
|
||||||
}
|
}
|
||||||
PDFPageProxy.prototype = {
|
PDFPageProxy.prototype = {
|
||||||
/**
|
/**
|
||||||
@ -289,20 +290,24 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
|
|||||||
* rendering call the function that is the
|
* rendering call the function that is the
|
||||||
* first argument to the callback.
|
* first argument to the callback.
|
||||||
* }.
|
* }.
|
||||||
* @return {Promise} A promise that is resolved when the page finishes
|
* @return {RenderTask} An extended promise that is resolved when the page
|
||||||
* rendering.
|
* finishes rendering (see RenderTask).
|
||||||
*/
|
*/
|
||||||
render: function PDFPageProxy_render(params) {
|
render: function PDFPageProxy_render(params) {
|
||||||
this.renderInProgress = true;
|
this.renderInProgress = true;
|
||||||
|
|
||||||
var promise = new Promise();
|
|
||||||
var stats = this.stats;
|
var stats = this.stats;
|
||||||
stats.time('Overall');
|
stats.time('Overall');
|
||||||
|
|
||||||
// If there is no displayReadyPromise yet, then the operatorList was never
|
// If there is no displayReadyPromise yet, then the operatorList was never
|
||||||
// requested before. Make the request and create the promise.
|
// requested before. Make the request and create the promise.
|
||||||
if (!this.displayReadyPromise) {
|
if (!this.displayReadyPromise) {
|
||||||
this.displayReadyPromise = new Promise();
|
this.displayReadyPromise = new Promise();
|
||||||
this.destroyed = false;
|
this.destroyed = false;
|
||||||
|
this.operatorList = {
|
||||||
|
fnArray: [],
|
||||||
|
argsArray: [],
|
||||||
|
lastChunk: false
|
||||||
|
};
|
||||||
|
|
||||||
this.stats.time('Page Request');
|
this.stats.time('Page Request');
|
||||||
this.transport.messageHandler.send('RenderPageRequest', {
|
this.transport.messageHandler.send('RenderPageRequest', {
|
||||||
@ -310,128 +315,48 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var internalRenderTask = new InternalRenderTask(complete, params,
|
||||||
|
this.objs, this.commonObjs,
|
||||||
|
this.operatorList, this.pageNumber);
|
||||||
|
this.renderTasks.push(internalRenderTask);
|
||||||
|
var renderTask = new RenderTask(internalRenderTask);
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
function complete(error) {
|
|
||||||
self.renderInProgress = false;
|
|
||||||
if (self.destroyed || self.cleanupAfterRender) {
|
|
||||||
delete self.displayReadyPromise;
|
|
||||||
delete self.operatorList;
|
|
||||||
self.objs.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
promise.reject(error);
|
|
||||||
else
|
|
||||||
promise.resolve();
|
|
||||||
}
|
|
||||||
var continueCallback = params.continueCallback;
|
|
||||||
|
|
||||||
// Once the operatorList and fonts are loaded, do the actual rendering.
|
|
||||||
this.displayReadyPromise.then(
|
this.displayReadyPromise.then(
|
||||||
function pageDisplayReadyPromise() {
|
function pageDisplayReadyPromise(transparency) {
|
||||||
if (self.destroyed) {
|
if (self.destroyed) {
|
||||||
complete();
|
complete();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
stats.time('Rendering');
|
||||||
var gfx = new CanvasGraphics(params.canvasContext, this.commonObjs,
|
internalRenderTask.initalizeGraphics(transparency);
|
||||||
this.objs, params.textLayer, params.imageLayer);
|
internalRenderTask.operatorListChanged();
|
||||||
try {
|
},
|
||||||
this.display(gfx, params.viewport, complete, continueCallback);
|
|
||||||
} catch (e) {
|
|
||||||
complete(e);
|
|
||||||
}
|
|
||||||
}.bind(this),
|
|
||||||
function pageDisplayReadPromiseError(reason) {
|
function pageDisplayReadPromiseError(reason) {
|
||||||
complete(reason);
|
complete(reason);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return promise;
|
function complete(error) {
|
||||||
},
|
var i = self.renderTasks.indexOf(internalRenderTask);
|
||||||
/**
|
if (i >= 0) {
|
||||||
* For internal use only.
|
self.renderTasks.splice(i, 1);
|
||||||
*/
|
}
|
||||||
startRenderingFromOperatorList:
|
|
||||||
function PDFPageProxy_startRenderingFromOperatorList(operatorList,
|
|
||||||
fonts) {
|
|
||||||
var self = this;
|
|
||||||
this.operatorList = operatorList;
|
|
||||||
|
|
||||||
this.ensureFonts(fonts,
|
if (self.renderTasks.length === 0 &&
|
||||||
function pageStartRenderingFromOperatorListEnsureFonts() {
|
(self.destroyed || self.cleanupAfterRender)) {
|
||||||
self.displayReadyPromise.resolve();
|
self._destroy();
|
||||||
}
|
}
|
||||||
);
|
if (error) {
|
||||||
},
|
renderTask.reject(error);
|
||||||
/**
|
} else {
|
||||||
* For internal use only.
|
renderTask.resolve();
|
||||||
*/
|
|
||||||
ensureFonts: function PDFPageProxy_ensureFonts(fonts, callback) {
|
|
||||||
this.stats.time('Font Loading');
|
|
||||||
// Convert the font names to the corresponding font obj.
|
|
||||||
var fontObjs = [];
|
|
||||||
for (var i = 0, ii = fonts.length; i < ii; i++) {
|
|
||||||
var obj = this.commonObjs.getData(fonts[i]);
|
|
||||||
if (obj.error) {
|
|
||||||
warn('Error during font loading: ' + obj.error);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
if (!obj.coded) {
|
stats.timeEnd('Rendering');
|
||||||
this.transport.embeddedFontsUsed = true;
|
stats.timeEnd('Overall');
|
||||||
}
|
|
||||||
fontObjs.push(obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load all the fonts
|
return renderTask;
|
||||||
FontLoader.bind(
|
|
||||||
fontObjs,
|
|
||||||
function pageEnsureFontsFontObjs(fontObjs) {
|
|
||||||
this.stats.timeEnd('Font Loading');
|
|
||||||
|
|
||||||
callback.call(this);
|
|
||||||
}.bind(this)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* For internal use only.
|
|
||||||
*/
|
|
||||||
display: function PDFPageProxy_display(gfx, viewport, callback,
|
|
||||||
continueCallback) {
|
|
||||||
var stats = this.stats;
|
|
||||||
stats.time('Rendering');
|
|
||||||
|
|
||||||
var operatorList = this.operatorList;
|
|
||||||
gfx.beginDrawing(viewport, operatorList.transparency);
|
|
||||||
|
|
||||||
var startIdx = 0;
|
|
||||||
var length = operatorList.fnArray.length;
|
|
||||||
var stepper = null;
|
|
||||||
if (PDFJS.pdfBug && 'StepperManager' in globalScope &&
|
|
||||||
globalScope['StepperManager'].enabled) {
|
|
||||||
stepper = globalScope['StepperManager'].create(this.pageNumber - 1);
|
|
||||||
stepper.init(operatorList);
|
|
||||||
stepper.nextBreakPoint = stepper.getNextBreakPoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
var continueWrapper;
|
|
||||||
if (continueCallback)
|
|
||||||
continueWrapper = function() { continueCallback(next); };
|
|
||||||
else
|
|
||||||
continueWrapper = next;
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
function next() {
|
|
||||||
startIdx = gfx.executeOperatorList(operatorList, startIdx,
|
|
||||||
continueWrapper, stepper);
|
|
||||||
if (startIdx == length) {
|
|
||||||
gfx.endDrawing();
|
|
||||||
stats.timeEnd('Rendering');
|
|
||||||
stats.timeEnd('Overall');
|
|
||||||
if (callback) callback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continueWrapper();
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @return {Promise} That is resolved with the a {string} that is the text
|
* @return {Promise} That is resolved with the a {string} that is the text
|
||||||
@ -466,10 +391,38 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
|
|||||||
destroy: function PDFPageProxy_destroy() {
|
destroy: function PDFPageProxy_destroy() {
|
||||||
this.destroyed = true;
|
this.destroyed = true;
|
||||||
|
|
||||||
if (!this.renderInProgress) {
|
if (this.renderTasks.length === 0) {
|
||||||
delete this.operatorList;
|
this._destroy();
|
||||||
delete this.displayReadyPromise;
|
}
|
||||||
this.objs.clear();
|
},
|
||||||
|
/**
|
||||||
|
* For internal use only. Does the actual cleanup.
|
||||||
|
*/
|
||||||
|
_destroy: function PDFPageProxy__destroy() {
|
||||||
|
delete this.operatorList;
|
||||||
|
delete this.displayReadyPromise;
|
||||||
|
this.objs.clear();
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* For internal use only.
|
||||||
|
*/
|
||||||
|
_startRenderPage: function PDFPageProxy_startRenderPage(transparency) {
|
||||||
|
this.displayReadyPromise.resolve(transparency);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* For internal use only.
|
||||||
|
*/
|
||||||
|
_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);
|
||||||
|
this.operatorList.lastChunk = operatorListChunk.lastChunk;
|
||||||
|
|
||||||
|
// Notify all the rendering tasks there are more operators to be consumed.
|
||||||
|
for (var i = 0; i < this.renderTasks.length; i++) {
|
||||||
|
this.renderTasks[i].operatorListChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -644,12 +597,17 @@ var WorkerTransport = (function WorkerTransportClosure() {
|
|||||||
promise.resolve(annotations);
|
promise.resolve(annotations);
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
messageHandler.on('RenderPage', function transportRender(data) {
|
messageHandler.on('StartRenderPage', function transportRender(data) {
|
||||||
var page = this.pageCache[data.pageIndex];
|
var page = this.pageCache[data.pageIndex];
|
||||||
var depFonts = data.depFonts;
|
|
||||||
|
|
||||||
page.stats.timeEnd('Page Request');
|
page.stats.timeEnd('Page Request');
|
||||||
page.startRenderingFromOperatorList(data.operatorList, depFonts);
|
page._startRenderPage(data.transparency);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
messageHandler.on('RenderPageChunk', function transportRender(data) {
|
||||||
|
var page = this.pageCache[data.pageIndex];
|
||||||
|
|
||||||
|
page._renderPageChunk(data.operatorList);
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
messageHandler.on('commonobj', function transportObj(data) {
|
messageHandler.on('commonobj', function transportObj(data) {
|
||||||
@ -662,14 +620,22 @@ var WorkerTransport = (function WorkerTransportClosure() {
|
|||||||
case 'Font':
|
case 'Font':
|
||||||
var exportedData = data[2];
|
var exportedData = data[2];
|
||||||
|
|
||||||
// At this point, only the font object is created but the font is
|
|
||||||
// not yet attached to the DOM. This is done in `FontLoader.bind`.
|
|
||||||
var font;
|
var font;
|
||||||
if ('error' in exportedData)
|
if ('error' in exportedData) {
|
||||||
font = new ErrorFont(exportedData.error);
|
font = new ErrorFont(exportedData.error);
|
||||||
else
|
warn('Error during font loading: ' + font.error);
|
||||||
|
this.commonObjs.resolve(id, font);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
font = new Font(exportedData);
|
font = new Font(exportedData);
|
||||||
this.commonObjs.resolve(id, font);
|
}
|
||||||
|
|
||||||
|
FontLoader.bind(
|
||||||
|
[font],
|
||||||
|
function fontReady(fontObjs) {
|
||||||
|
this.commonObjs.resolve(id, font);
|
||||||
|
}.bind(this)
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error('Got unknown common object type ' + type);
|
error('Got unknown common object type ' + type);
|
||||||
@ -814,3 +780,129 @@ var WorkerTransport = (function WorkerTransportClosure() {
|
|||||||
return WorkerTransport;
|
return WorkerTransport;
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RenderTask is basically a promise but adds a cancel function to terminate it.
|
||||||
|
*/
|
||||||
|
var RenderTask = (function RenderTaskClosure() {
|
||||||
|
function RenderTask(internalRenderTask) {
|
||||||
|
this.internalRenderTask = internalRenderTask;
|
||||||
|
Promise.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderTask.prototype = Object.create(Promise.prototype);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel the rendering task. If the task is curently rendering it will not be
|
||||||
|
* cancelled until graphics pauses with a timeout. The promise that this
|
||||||
|
* object extends will resolved when cancelled.
|
||||||
|
*/
|
||||||
|
RenderTask.prototype.cancel = function RenderTask_cancel() {
|
||||||
|
this.internalRenderTask.cancel();
|
||||||
|
};
|
||||||
|
|
||||||
|
return RenderTask;
|
||||||
|
})();
|
||||||
|
|
||||||
|
var InternalRenderTask = (function InternalRenderTaskClosure() {
|
||||||
|
|
||||||
|
function InternalRenderTask(callback, params, objs, commonObjs, operatorList,
|
||||||
|
pageNumber) {
|
||||||
|
this.callback = callback;
|
||||||
|
this.params = params;
|
||||||
|
this.objs = objs;
|
||||||
|
this.commonObjs = commonObjs;
|
||||||
|
this.operatorListIdx = null;
|
||||||
|
this.operatorList = operatorList;
|
||||||
|
this.pageNumber = pageNumber;
|
||||||
|
this.running = false;
|
||||||
|
this.graphicsReadyCallback = null;
|
||||||
|
this.graphicsReady = false;
|
||||||
|
this.cancelled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalRenderTask.prototype = {
|
||||||
|
|
||||||
|
initalizeGraphics:
|
||||||
|
function InternalRenderTask_initalizeGraphics(transparency) {
|
||||||
|
|
||||||
|
if (this.cancelled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (PDFJS.pdfBug && 'StepperManager' in globalScope &&
|
||||||
|
globalScope.StepperManager.enabled) {
|
||||||
|
this.stepper = globalScope.StepperManager.create(this.pageNumber - 1);
|
||||||
|
this.stepper.init(this.operatorList);
|
||||||
|
this.stepper.nextBreakPoint = this.stepper.getNextBreakPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
var params = this.params;
|
||||||
|
this.gfx = new CanvasGraphics(params.canvasContext, this.commonObjs,
|
||||||
|
this.objs, params.textLayer,
|
||||||
|
params.imageLayer);
|
||||||
|
|
||||||
|
this.gfx.beginDrawing(params.viewport, transparency);
|
||||||
|
this.operatorListIdx = 0;
|
||||||
|
this.graphicsReady = true;
|
||||||
|
if (this.graphicsReadyCallback) {
|
||||||
|
this.graphicsReadyCallback();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
cancel: function InternalRenderTask_cancel() {
|
||||||
|
this.running = false;
|
||||||
|
this.cancelled = true;
|
||||||
|
this.callback();
|
||||||
|
},
|
||||||
|
|
||||||
|
operatorListChanged: function InternalRenderTask_operatorListChanged() {
|
||||||
|
if (!this.graphicsReady) {
|
||||||
|
if (!this.graphicsReadyCallback) {
|
||||||
|
this.graphicsReadyCallback = this._continue.bind(this);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.stepper) {
|
||||||
|
this.stepper.updateOperatorList(this.operatorList);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._continue();
|
||||||
|
},
|
||||||
|
|
||||||
|
_continue: function InternalRenderTask__continue() {
|
||||||
|
this.running = true;
|
||||||
|
if (this.cancelled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.params.continueCallback) {
|
||||||
|
this.params.continueCallback(this._next.bind(this));
|
||||||
|
} else {
|
||||||
|
this._next();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_next: function InternalRenderTask__next() {
|
||||||
|
if (this.cancelled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.operatorListIdx = this.gfx.executeOperatorList(this.operatorList,
|
||||||
|
this.operatorListIdx,
|
||||||
|
this._continue.bind(this),
|
||||||
|
this.stepper);
|
||||||
|
if (this.operatorListIdx === this.operatorList.fnArray.length) {
|
||||||
|
this.running = false;
|
||||||
|
if (this.operatorList.lastChunk) {
|
||||||
|
this.gfx.endDrawing();
|
||||||
|
this.callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return InternalRenderTask;
|
||||||
|
})();
|
||||||
|
@ -670,7 +670,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
this.setFlatness(value);
|
this.setFlatness(value);
|
||||||
break;
|
break;
|
||||||
case 'Font':
|
case 'Font':
|
||||||
this.setFont(state[1], state[2]);
|
this.setFont(value[0], value[1]);
|
||||||
break;
|
break;
|
||||||
case 'CA':
|
case 'CA':
|
||||||
this.current.strokeAlpha = state[1];
|
this.current.strokeAlpha = state[1];
|
||||||
|
44
src/core.js
44
src/core.js
@ -18,7 +18,8 @@
|
|||||||
isArrayBuffer, isDict, isName, isStream, isString, Lexer,
|
isArrayBuffer, isDict, isName, isStream, isString, Lexer,
|
||||||
Linearization, NullStream, PartialEvaluator, shadow, Stream,
|
Linearization, NullStream, PartialEvaluator, shadow, Stream,
|
||||||
StreamsSequenceStream, stringToPDFString, TODO, Util, warn, XRef,
|
StreamsSequenceStream, stringToPDFString, TODO, Util, warn, XRef,
|
||||||
MissingDataException, Promise, Annotation, ObjectLoader */
|
MissingDataException, Promise, Annotation, ObjectLoader, OperatorList
|
||||||
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@ -183,33 +184,35 @@ var Page = (function PageClosure() {
|
|||||||
dataPromises.then(function(data) {
|
dataPromises.then(function(data) {
|
||||||
var contentStream = data[0];
|
var contentStream = data[0];
|
||||||
|
|
||||||
partialEvaluator.getOperatorList(contentStream, self.resources).then(
|
|
||||||
function(data) {
|
var opList = new OperatorList(handler, self.pageIndex);
|
||||||
pageListPromise.resolve(data);
|
|
||||||
},
|
handler.send('StartRenderPage', {
|
||||||
reject
|
transparency: partialEvaluator.hasBlendModes(self.resources),
|
||||||
);
|
pageIndex: self.pageIndex
|
||||||
|
});
|
||||||
|
partialEvaluator.getOperatorList(contentStream, self.resources, opList);
|
||||||
|
pageListPromise.resolve(opList);
|
||||||
});
|
});
|
||||||
|
|
||||||
var annotationsPromise = pdfManager.ensure(this, 'annotations');
|
var annotationsPromise = pdfManager.ensure(this, 'annotations');
|
||||||
Promise.all([pageListPromise, annotationsPromise]).then(function(datas) {
|
Promise.all([pageListPromise, annotationsPromise]).then(function(datas) {
|
||||||
var pageData = datas[0];
|
var pageOpList = datas[0];
|
||||||
var pageQueue = pageData.queue;
|
|
||||||
var annotations = datas[1];
|
var annotations = datas[1];
|
||||||
|
|
||||||
if (annotations.length === 0) {
|
if (annotations.length === 0) {
|
||||||
PartialEvaluator.optimizeQueue(pageQueue);
|
PartialEvaluator.optimizeQueue(pageOpList);
|
||||||
promise.resolve(pageData);
|
pageOpList.flush(true);
|
||||||
|
promise.resolve(pageOpList);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var dependencies = pageData.dependencies;
|
|
||||||
var annotationsReadyPromise = Annotation.appendToOperatorList(
|
var annotationsReadyPromise = Annotation.appendToOperatorList(
|
||||||
annotations, pageQueue, pdfManager, dependencies, partialEvaluator);
|
annotations, pageOpList, pdfManager, partialEvaluator);
|
||||||
annotationsReadyPromise.then(function () {
|
annotationsReadyPromise.then(function () {
|
||||||
PartialEvaluator.optimizeQueue(pageQueue);
|
PartialEvaluator.optimizeQueue(pageOpList);
|
||||||
|
pageOpList.flush(true);
|
||||||
promise.resolve(pageData);
|
promise.resolve(pageOpList);
|
||||||
}, reject);
|
}, reject);
|
||||||
}, reject);
|
}, reject);
|
||||||
|
|
||||||
@ -244,12 +247,9 @@ var Page = (function PageClosure() {
|
|||||||
self.pageIndex, 'p' + self.pageIndex + '_',
|
self.pageIndex, 'p' + self.pageIndex + '_',
|
||||||
self.idCounters);
|
self.idCounters);
|
||||||
|
|
||||||
partialEvaluator.getTextContent(
|
var bidiTexts = partialEvaluator.getTextContent(contentStream,
|
||||||
contentStream, self.resources).then(function(bidiTexts) {
|
self.resources);
|
||||||
textContentPromise.resolve({
|
textContentPromise.resolve(bidiTexts);
|
||||||
bidiTexts: bidiTexts
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return textContentPromise;
|
return textContentPromise;
|
||||||
|
679
src/evaluator.js
679
src/evaluator.js
@ -153,24 +153,51 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
|
|
||||||
var TILING_PATTERN = 1, SHADING_PATTERN = 2;
|
var TILING_PATTERN = 1, SHADING_PATTERN = 2;
|
||||||
|
|
||||||
function createOperatorList(fnArray, argsArray, dependencies) {
|
|
||||||
return {
|
|
||||||
queue: {
|
|
||||||
fnArray: fnArray || [],
|
|
||||||
argsArray: argsArray || []
|
|
||||||
},
|
|
||||||
dependencies: dependencies || {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
PartialEvaluator.prototype = {
|
PartialEvaluator.prototype = {
|
||||||
|
hasBlendModes: function PartialEvaluator_hasBlendModes(resources) {
|
||||||
|
if (!isDict(resources)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var nodes = [resources];
|
||||||
|
while (nodes.length) {
|
||||||
|
var node = nodes.shift();
|
||||||
|
// First check the current resources for blend modes.
|
||||||
|
var graphicStates = node.get('ExtGState');
|
||||||
|
if (isDict(graphicStates)) {
|
||||||
|
graphicStates = graphicStates.getAll();
|
||||||
|
for (var key in graphicStates) {
|
||||||
|
var graphicState = graphicStates[key];
|
||||||
|
var bm = graphicState['BM'];
|
||||||
|
if (isName(bm) && bm.name !== 'Normal') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Descend into the XObjects to look for more resources and blend modes.
|
||||||
|
var xObjects = node.get('XObject');
|
||||||
|
if (!isDict(xObjects)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
xObjects = xObjects.getAll();
|
||||||
|
for (var key in xObjects) {
|
||||||
|
var xObject = xObjects[key];
|
||||||
|
if (!isStream(xObject)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var xResources = xObject.dict.get('Resources');
|
||||||
|
if (isDict(xResources)) {
|
||||||
|
nodes.push(xResources);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
buildFormXObject: function PartialEvaluator_buildFormXObject(resources,
|
buildFormXObject: function PartialEvaluator_buildFormXObject(resources,
|
||||||
xobj, smask) {
|
xobj, smask,
|
||||||
|
operatorList) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var promise = new Promise();
|
|
||||||
var fnArray = [];
|
|
||||||
var argsArray = [];
|
|
||||||
|
|
||||||
var matrix = xobj.dict.get('Matrix');
|
var matrix = xobj.dict.get('Matrix');
|
||||||
var bbox = xobj.dict.get('BBox');
|
var bbox = xobj.dict.get('BBox');
|
||||||
@ -191,44 +218,22 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
// There is also a group colorspace, but since we put everything in
|
// There is also a group colorspace, but since we put everything in
|
||||||
// RGB I'm not sure we need it.
|
// RGB I'm not sure we need it.
|
||||||
}
|
}
|
||||||
fnArray.push('beginGroup');
|
operatorList.addOp('beginGroup', [groupOptions]);
|
||||||
argsArray.push([groupOptions]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fnArray.push('paintFormXObjectBegin');
|
operatorList.addOp('paintFormXObjectBegin', [matrix, bbox]);
|
||||||
argsArray.push([matrix, bbox]);
|
|
||||||
|
|
||||||
// Pass in the current `queue` object. That means the `fnArray`
|
this.getOperatorList(xobj, xobj.dict.get('Resources') || resources,
|
||||||
// and the `argsArray` in this scope is reused and new commands
|
operatorList);
|
||||||
// are added to them.
|
operatorList.addOp('paintFormXObjectEnd', []);
|
||||||
var opListPromise = this.getOperatorList(xobj,
|
|
||||||
xobj.dict.get('Resources') || resources);
|
|
||||||
opListPromise.then(function(data) {
|
|
||||||
var queue = data.queue;
|
|
||||||
var dependencies = data.dependencies;
|
|
||||||
Util.prependToArray(queue.fnArray, fnArray);
|
|
||||||
Util.prependToArray(queue.argsArray, argsArray);
|
|
||||||
self.insertDependencies(queue, dependencies);
|
|
||||||
|
|
||||||
queue.fnArray.push('paintFormXObjectEnd');
|
if (group) {
|
||||||
queue.argsArray.push([]);
|
operatorList.addOp('endGroup', [groupOptions]);
|
||||||
|
}
|
||||||
if (group) {
|
|
||||||
queue.fnArray.push('endGroup');
|
|
||||||
queue.argsArray.push([groupOptions]);
|
|
||||||
}
|
|
||||||
|
|
||||||
promise.resolve({
|
|
||||||
queue: queue,
|
|
||||||
dependencies: dependencies
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return promise;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
buildPaintImageXObject: function PartialEvaluator_buildPaintImageXObject(
|
buildPaintImageXObject: function PartialEvaluator_buildPaintImageXObject(
|
||||||
resources, image, inline) {
|
resources, image, inline, operatorList) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var dict = image.dict;
|
var dict = image.dict;
|
||||||
var w = dict.get('Width', 'W');
|
var w = dict.get('Width', 'W');
|
||||||
@ -236,14 +241,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
|
|
||||||
if (PDFJS.maxImageSize !== -1 && w * h > PDFJS.maxImageSize) {
|
if (PDFJS.maxImageSize !== -1 && w * h > PDFJS.maxImageSize) {
|
||||||
warn('Image exceeded maximum allowed size and was removed.');
|
warn('Image exceeded maximum allowed size and was removed.');
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var dependencies = {};
|
|
||||||
var retData = {
|
|
||||||
dependencies: dependencies
|
|
||||||
};
|
|
||||||
|
|
||||||
var imageMask = dict.get('ImageMask', 'IM') || false;
|
var imageMask = dict.get('ImageMask', 'IM') || false;
|
||||||
if (imageMask) {
|
if (imageMask) {
|
||||||
// This depends on a tmpCanvas beeing filled with the
|
// This depends on a tmpCanvas beeing filled with the
|
||||||
@ -259,10 +259,11 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
var decode = dict.get('Decode', 'D');
|
var decode = dict.get('Decode', 'D');
|
||||||
var inverseDecode = !!decode && decode[0] > 0;
|
var inverseDecode = !!decode && decode[0] > 0;
|
||||||
|
|
||||||
retData.fn = 'paintImageMaskXObject';
|
operatorList.addOp('paintImageMaskXObject',
|
||||||
retData.args = [PDFImage.createMask(imgArray, width, height,
|
[PDFImage.createMask(imgArray, width, height,
|
||||||
inverseDecode)];
|
inverseDecode)]
|
||||||
return retData;
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var softMask = dict.get('SMask', 'SM') || false;
|
var softMask = dict.get('SMask', 'SM') || false;
|
||||||
@ -276,64 +277,53 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
var imageObj = new PDFImage(this.xref, resources, image,
|
var imageObj = new PDFImage(this.xref, resources, image,
|
||||||
inline, null, null);
|
inline, null, null);
|
||||||
var imgData = imageObj.getImageData();
|
var imgData = imageObj.getImageData();
|
||||||
retData.fn = 'paintInlineImageXObject';
|
operatorList.addOp('paintInlineImageXObject', [imgData]);
|
||||||
retData.args = [imgData];
|
return;
|
||||||
return retData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is no imageMask, create the PDFImage and a lot
|
// If there is no imageMask, create the PDFImage and a lot
|
||||||
// of image processing can be done here.
|
// of image processing can be done here.
|
||||||
var uniquePrefix = this.uniquePrefix || '';
|
var uniquePrefix = this.uniquePrefix || '';
|
||||||
var objId = 'img_' + uniquePrefix + (++this.idCounters.obj);
|
var objId = 'img_' + uniquePrefix + (++this.idCounters.obj);
|
||||||
dependencies[objId] = true;
|
operatorList.addDependency(objId);
|
||||||
retData.args = [objId, w, h];
|
var args = [objId, w, h];
|
||||||
|
|
||||||
if (!softMask && !mask && image instanceof JpegStream &&
|
if (!softMask && !mask && image instanceof JpegStream &&
|
||||||
image.isNativelySupported(this.xref, resources)) {
|
image.isNativelySupported(this.xref, resources)) {
|
||||||
// These JPEGs don't need any more processing so we can just send it.
|
// These JPEGs don't need any more processing so we can just send it.
|
||||||
retData.fn = 'paintJpegXObject';
|
operatorList.addOp('paintJpegXObject', args);
|
||||||
this.handler.send(
|
this.handler.send(
|
||||||
'obj', [objId, this.pageIndex, 'JpegStream', image.getIR()]);
|
'obj', [objId, this.pageIndex, 'JpegStream', image.getIR()]);
|
||||||
return retData;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
retData.fn = 'paintImageXObject';
|
|
||||||
|
|
||||||
PDFImage.buildImage(function(imageObj) {
|
PDFImage.buildImage(function(imageObj) {
|
||||||
var imgData = imageObj.getImageData();
|
var imgData = imageObj.getImageData();
|
||||||
self.handler.send('obj', [objId, self.pageIndex, 'Image', imgData]);
|
self.handler.send('obj', [objId, self.pageIndex, 'Image', imgData]);
|
||||||
}, self.handler, self.xref, resources, image, inline);
|
}, self.handler, self.xref, resources, image, inline);
|
||||||
|
|
||||||
return retData;
|
operatorList.addOp('paintImageXObject', args);
|
||||||
},
|
},
|
||||||
|
|
||||||
handleTilingType: function PartialEvaluator_handleTilingType(
|
handleTilingType: function PartialEvaluator_handleTilingType(
|
||||||
fn, args, resources, pattern, patternDict) {
|
fn, args, resources, pattern, patternDict,
|
||||||
var self = this;
|
operatorList) {
|
||||||
// Create an IR of the pattern code.
|
// Create an IR of the pattern code.
|
||||||
var promise = new Promise();
|
var tilingOpList = this.getOperatorList(pattern,
|
||||||
var opListPromise = this.getOperatorList(pattern,
|
patternDict.get('Resources') || resources);
|
||||||
patternDict.get('Resources') || resources);
|
// Add the dependencies to the parent operator list so they are resolved
|
||||||
opListPromise.then(function(data) {
|
// before sub operator list is executed synchronously.
|
||||||
var opListData = createOperatorList([], [], data.dependencies);
|
operatorList.addDependencies(tilingOpList.dependencies);
|
||||||
var queue = opListData.queue;
|
operatorList.addOp(fn, TilingPattern.getIR({
|
||||||
|
fnArray: tilingOpList.fnArray,
|
||||||
// Add the dependencies that are required to execute the
|
argsArray: tilingOpList.argsArray
|
||||||
// operatorList.
|
}, patternDict, args));
|
||||||
self.insertDependencies(queue, data.dependencies);
|
|
||||||
queue.fnArray.push(fn);
|
|
||||||
queue.argsArray.push(
|
|
||||||
TilingPattern.getIR(data.queue, patternDict, args));
|
|
||||||
promise.resolve(opListData);
|
|
||||||
});
|
|
||||||
|
|
||||||
return promise;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
handleSetFont: function PartialEvaluator_handleSetFont(
|
handleSetFont: function PartialEvaluator_handleSetFont(
|
||||||
resources, fontArgs, font) {
|
resources, fontArgs, fontRef, operatorList) {
|
||||||
|
|
||||||
var promise = new Promise();
|
|
||||||
// TODO(mack): Not needed?
|
// TODO(mack): Not needed?
|
||||||
var fontName;
|
var fontName;
|
||||||
if (fontArgs) {
|
if (fontArgs) {
|
||||||
@ -341,69 +331,27 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
fontName = fontArgs[0].name;
|
fontName = fontArgs[0].name;
|
||||||
}
|
}
|
||||||
var self = this;
|
var self = this;
|
||||||
var fontPromise = this.loadFont(fontName, font, this.xref, resources);
|
var font = this.loadFont(fontName, fontRef, this.xref, resources,
|
||||||
fontPromise.then(function(data) {
|
operatorList);
|
||||||
var font = data.font;
|
var loadedName = font.loadedName;
|
||||||
var loadedName = font.loadedName;
|
if (!font.sent) {
|
||||||
if (!font.sent) {
|
var fontData = font.translated.exportData();
|
||||||
var fontData = font.translated.exportData();
|
|
||||||
|
|
||||||
self.handler.send('commonobj', [
|
self.handler.send('commonobj', [
|
||||||
loadedName,
|
loadedName,
|
||||||
'Font',
|
'Font',
|
||||||
fontData
|
fontData
|
||||||
]);
|
]);
|
||||||
font.sent = true;
|
font.sent = true;
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure the font is ready before the font is set
|
|
||||||
// and later on used for drawing.
|
|
||||||
// OPTIMIZE: This should get insert to the operatorList only once per
|
|
||||||
// page.
|
|
||||||
var fnArray = [];
|
|
||||||
var argsArray = [];
|
|
||||||
var queue = {
|
|
||||||
fnArray: fnArray,
|
|
||||||
argsArray: argsArray
|
|
||||||
};
|
|
||||||
var dependencies = data.dependencies;
|
|
||||||
dependencies[loadedName] = true;
|
|
||||||
self.insertDependencies(queue, dependencies);
|
|
||||||
if (fontArgs) {
|
|
||||||
fontArgs[0] = loadedName;
|
|
||||||
fnArray.push('setFont');
|
|
||||||
argsArray.push(fontArgs);
|
|
||||||
}
|
|
||||||
promise.resolve({
|
|
||||||
loadedName: loadedName,
|
|
||||||
queue: queue,
|
|
||||||
dependencies: dependencies
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return promise;
|
|
||||||
},
|
|
||||||
|
|
||||||
insertDependencies: function PartialEvaluator_insertDependencies(
|
|
||||||
queue, dependencies) {
|
|
||||||
|
|
||||||
var fnArray = queue.fnArray;
|
|
||||||
var argsArray = queue.argsArray;
|
|
||||||
var depList = Object.keys(dependencies);
|
|
||||||
if (depList.length) {
|
|
||||||
fnArray.push('dependency');
|
|
||||||
argsArray.push(depList);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return loadedName;
|
||||||
},
|
},
|
||||||
|
|
||||||
setGState: function PartialEvaluator_setGState(resources, gState) {
|
setGState: function PartialEvaluator_setGState(resources, gState,
|
||||||
|
operatorList) {
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
var opListData = createOperatorList();
|
|
||||||
var queue = opListData.queue;
|
|
||||||
var fnArray = queue.fnArray;
|
|
||||||
var argsArray = queue.argsArray;
|
|
||||||
var dependencies = opListData.dependencies;
|
|
||||||
|
|
||||||
// TODO(mack): This should be rewritten so that this function returns
|
// TODO(mack): This should be rewritten so that this function returns
|
||||||
// what should be added to the queue during each iteration
|
// what should be added to the queue during each iteration
|
||||||
function setGStateForKey(gStateObj, key, value) {
|
function setGStateForKey(gStateObj, key, value) {
|
||||||
@ -422,21 +370,12 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
gStateObj.push([key, value]);
|
gStateObj.push([key, value]);
|
||||||
break;
|
break;
|
||||||
case 'Font':
|
case 'Font':
|
||||||
var promise = new Promise();
|
var loadedName = self.handleSetFont(resources, null, value[0],
|
||||||
self.handleSetFont(resources, null, value[0]).then(function(data) {
|
operatorList);
|
||||||
var gState = ['Font', data.loadedName, value[1]];
|
operatorList.addDependency(loadedName);
|
||||||
promise.resolve({
|
gStateObj.push([key, [loadedName, value[1]]]);
|
||||||
gState: gState,
|
|
||||||
queue: data.queue,
|
|
||||||
dependencies: data.dependencies
|
|
||||||
});
|
|
||||||
});
|
|
||||||
gStateObj.push(['promise', promise]);
|
|
||||||
break;
|
break;
|
||||||
case 'BM':
|
case 'BM':
|
||||||
if (!isName(value) || value.name !== 'Normal') {
|
|
||||||
queue.transparency = true;
|
|
||||||
}
|
|
||||||
gStateObj.push([key, value]);
|
gStateObj.push([key, value]);
|
||||||
break;
|
break;
|
||||||
case 'SMask':
|
case 'SMask':
|
||||||
@ -477,47 +416,18 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
setGStateForKey(gStateObj, key, value);
|
setGStateForKey(gStateObj, key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
var promises = [];
|
operatorList.addOp('setGState', [gStateObj]);
|
||||||
var indices = [];
|
|
||||||
for (var i = 0, n = gStateObj.length; i < n; ++i) {
|
|
||||||
var value = gStateObj[i];
|
|
||||||
if (value[0] === 'promise') {
|
|
||||||
promises.push(value[1]);
|
|
||||||
indices.push(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var promise = new Promise();
|
|
||||||
Promise.all(promises).then(function(datas) {
|
|
||||||
for (var i = 0, n = datas.length; i < n; ++i) {
|
|
||||||
var data = datas[i];
|
|
||||||
var index = indices[i];
|
|
||||||
gStateObj[index] = data.gState;
|
|
||||||
var subQueue = data.queue;
|
|
||||||
Util.concatenateToArray(fnArray, subQueue.fnArray);
|
|
||||||
Util.concatenateToArray(argsArray, subQueue.argsArray);
|
|
||||||
queue.transparency = subQueue.transparency || queue.transparency;
|
|
||||||
Util.extendObj(dependencies, data.dependencies);
|
|
||||||
}
|
|
||||||
fnArray.push('setGState');
|
|
||||||
argsArray.push([gStateObj]);
|
|
||||||
promise.resolve(opListData);
|
|
||||||
});
|
|
||||||
|
|
||||||
return promise;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
loadFont: function PartialEvaluator_loadFont(fontName, font, xref,
|
loadFont: function PartialEvaluator_loadFont(fontName, font, xref,
|
||||||
resources) {
|
resources,
|
||||||
function errorFont(promise) {
|
parentOperatorList) {
|
||||||
promise.resolve({
|
|
||||||
font: {
|
function errorFont() {
|
||||||
translated: new ErrorFont('Font ' + fontName + ' is not available'),
|
return {
|
||||||
loadedName: 'g_font_error'
|
translated: new ErrorFont('Font ' + fontName + ' is not available'),
|
||||||
},
|
loadedName: 'g_font_error'
|
||||||
dependencies: {}
|
};
|
||||||
});
|
|
||||||
return promise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var fontRef;
|
var fontRef;
|
||||||
@ -530,20 +440,19 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
fontRef = fontRes.getRaw(fontName);
|
fontRef = fontRes.getRaw(fontName);
|
||||||
} else {
|
} else {
|
||||||
warn('fontRes not available');
|
warn('fontRes not available');
|
||||||
return errorFont(new Promise());
|
return errorFont();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.fontCache.has(fontRef)) {
|
if (this.fontCache.has(fontRef)) {
|
||||||
return this.fontCache.get(fontRef);
|
return this.fontCache.get(fontRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
var promise = new Promise();
|
|
||||||
this.fontCache.put(fontRef, promise);
|
|
||||||
|
|
||||||
font = xref.fetchIfRef(fontRef);
|
font = xref.fetchIfRef(fontRef);
|
||||||
if (!isDict(font)) {
|
if (!isDict(font)) {
|
||||||
return errorFont(promise);
|
return errorFont();
|
||||||
}
|
}
|
||||||
|
this.fontCache.put(fontRef, font);
|
||||||
|
|
||||||
// keep track of each font we translated so the caller can
|
// keep track of each font we translated so the caller can
|
||||||
// load them asynchronously before calling display on a page
|
// load them asynchronously before calling display on a page
|
||||||
@ -562,55 +471,37 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
if (font.translated.loadCharProcs) {
|
if (font.translated.loadCharProcs) {
|
||||||
var charProcs = font.get('CharProcs').getAll();
|
var charProcs = font.get('CharProcs').getAll();
|
||||||
var fontResources = font.get('Resources') || resources;
|
var fontResources = font.get('Resources') || resources;
|
||||||
var opListPromises = [];
|
|
||||||
var charProcKeys = Object.keys(charProcs);
|
var charProcKeys = Object.keys(charProcs);
|
||||||
|
var charProcOperatorList = {};
|
||||||
for (var i = 0, n = charProcKeys.length; i < n; ++i) {
|
for (var i = 0, n = charProcKeys.length; i < n; ++i) {
|
||||||
var key = charProcKeys[i];
|
var key = charProcKeys[i];
|
||||||
var glyphStream = charProcs[key];
|
var glyphStream = charProcs[key];
|
||||||
opListPromises.push(
|
var operatorList = this.getOperatorList(glyphStream, fontResources);
|
||||||
this.getOperatorList(glyphStream, fontResources));
|
charProcOperatorList[key] = operatorList.getIR();
|
||||||
}
|
if (!parentOperatorList) {
|
||||||
Promise.all(opListPromises).then(function(datas) {
|
continue;
|
||||||
var charProcOperatorList = {};
|
|
||||||
var dependencies = {};
|
|
||||||
for (var i = 0, n = charProcKeys.length; i < n; ++i) {
|
|
||||||
var key = charProcKeys[i];
|
|
||||||
var data = datas[i];
|
|
||||||
charProcOperatorList[key] = data.queue;
|
|
||||||
Util.extendObj(dependencies, data.dependencies);
|
|
||||||
}
|
}
|
||||||
font.translated.charProcOperatorList = charProcOperatorList;
|
// Add the dependencies to the parent operator list so they are
|
||||||
font.loaded = true;
|
// resolved before sub operator list is executed synchronously.
|
||||||
promise.resolve({
|
parentOperatorList.addDependencies(charProcOperatorList.dependencies);
|
||||||
font: font,
|
}
|
||||||
dependencies: dependencies
|
font.translated.charProcOperatorList = charProcOperatorList;
|
||||||
});
|
font.loaded = true;
|
||||||
}.bind(this));
|
|
||||||
} else {
|
} else {
|
||||||
font.loaded = true;
|
font.loaded = true;
|
||||||
promise.resolve({
|
|
||||||
font: font,
|
|
||||||
dependencies: {}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return promise;
|
return font;
|
||||||
},
|
},
|
||||||
|
|
||||||
getOperatorList: function PartialEvaluator_getOperatorList(stream,
|
getOperatorList: function PartialEvaluator_getOperatorList(stream,
|
||||||
resources) {
|
resources,
|
||||||
|
operatorList) {
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
var xref = this.xref;
|
var xref = this.xref;
|
||||||
var handler = this.handler;
|
var handler = this.handler;
|
||||||
|
|
||||||
var fnArray = [];
|
operatorList = operatorList || new OperatorList();
|
||||||
var argsArray = [];
|
|
||||||
var queue = {
|
|
||||||
transparency: false,
|
|
||||||
fnArray: fnArray,
|
|
||||||
argsArray: argsArray
|
|
||||||
};
|
|
||||||
var dependencies = {};
|
|
||||||
|
|
||||||
resources = resources || new Dict();
|
resources = resources || new Dict();
|
||||||
var xobjs = resources.get('XObject') || new Dict();
|
var xobjs = resources.get('XObject') || new Dict();
|
||||||
@ -621,6 +512,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
|
|
||||||
var promise = new Promise();
|
var promise = new Promise();
|
||||||
var args = [];
|
var args = [];
|
||||||
|
nextOp:
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
var obj = parser.getObj();
|
var obj = parser.getObj();
|
||||||
@ -677,10 +569,10 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
var typeNum = dict.get('PatternType');
|
var typeNum = dict.get('PatternType');
|
||||||
|
|
||||||
if (typeNum == TILING_PATTERN) {
|
if (typeNum == TILING_PATTERN) {
|
||||||
var patternPromise = self.handleTilingType(
|
self.handleTilingType(fn, args, resources, pattern, dict,
|
||||||
fn, args, resources, pattern, dict);
|
operatorList);
|
||||||
fn = 'promise';
|
args = [];
|
||||||
args = [patternPromise];
|
continue;
|
||||||
} else if (typeNum == SHADING_PATTERN) {
|
} else if (typeNum == SHADING_PATTERN) {
|
||||||
var shading = dict.get('Shading');
|
var shading = dict.get('Shading');
|
||||||
var matrix = dict.get('Matrix');
|
var matrix = dict.get('Matrix');
|
||||||
@ -706,37 +598,28 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if ('Form' == type.name) {
|
if ('Form' == type.name) {
|
||||||
fn = 'promise';
|
self.buildFormXObject(resources, xobj, null, operatorList);
|
||||||
args = [self.buildFormXObject(resources, xobj)];
|
args = [];
|
||||||
|
continue;
|
||||||
} else if ('Image' == type.name) {
|
} else if ('Image' == type.name) {
|
||||||
var data = self.buildPaintImageXObject(
|
self.buildPaintImageXObject(resources, xobj, false,
|
||||||
resources, xobj, false);
|
operatorList);
|
||||||
if (!data) {
|
args = [];
|
||||||
args = [];
|
continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Util.extendObj(dependencies, data.dependencies);
|
|
||||||
self.insertDependencies(queue, data.dependencies);
|
|
||||||
fn = data.fn;
|
|
||||||
args = data.args;
|
|
||||||
} else {
|
} else {
|
||||||
error('Unhandled XObject subtype ' + type.name);
|
error('Unhandled XObject subtype ' + type.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (cmd == 'Tf') { // eagerly collect all fonts
|
} else if (cmd == 'Tf') { // eagerly collect all fonts
|
||||||
fn = 'promise';
|
var loadedName = self.handleSetFont(resources, args, null,
|
||||||
args = [self.handleSetFont(resources, args)];
|
operatorList);
|
||||||
|
operatorList.addDependency(loadedName);
|
||||||
|
fn = 'setFont';
|
||||||
|
args[0] = loadedName;
|
||||||
} else if (cmd == 'EI') {
|
} else if (cmd == 'EI') {
|
||||||
var data = self.buildPaintImageXObject(
|
self.buildPaintImageXObject(resources, args[0], true, operatorList);
|
||||||
resources, args[0], true);
|
args = [];
|
||||||
if (!data) {
|
continue;
|
||||||
args = [];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Util.extendObj(dependencies, data.dependencies);
|
|
||||||
self.insertDependencies(queue, data.dependencies);
|
|
||||||
fn = data.fn;
|
|
||||||
args = data.args;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (fn) {
|
switch (fn) {
|
||||||
@ -768,12 +651,12 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
var gState = extGState.get(dictName.name);
|
var gState = extGState.get(dictName.name);
|
||||||
fn = 'promise';
|
self.setGState(resources, gState, operatorList);
|
||||||
args = [self.setGState(resources, gState)];
|
args = [];
|
||||||
|
continue nextOp;
|
||||||
} // switch
|
} // switch
|
||||||
|
|
||||||
fnArray.push(fn);
|
operatorList.addOp(fn, args);
|
||||||
argsArray.push(args);
|
|
||||||
args = [];
|
args = [];
|
||||||
parser.saveState();
|
parser.saveState();
|
||||||
} else if (obj !== null && obj !== undefined) {
|
} else if (obj !== null && obj !== undefined) {
|
||||||
@ -782,163 +665,86 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var subQueuePromises = [];
|
return operatorList;
|
||||||
for (var i = 0; i < fnArray.length; ++i) {
|
|
||||||
if (fnArray[i] === 'promise') {
|
|
||||||
subQueuePromises.push(argsArray[i][0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Promise.all(subQueuePromises).then(function(datas) {
|
|
||||||
// TODO(mack): Optimize by using repositioning elements
|
|
||||||
// in original queue rather than creating new queue
|
|
||||||
|
|
||||||
for (var i = 0, n = datas.length; i < n; ++i) {
|
|
||||||
var data = datas[i];
|
|
||||||
var subQueue = data.queue;
|
|
||||||
queue.transparency = subQueue.transparency || queue.transparency;
|
|
||||||
Util.extendObj(dependencies, data.dependencies);
|
|
||||||
}
|
|
||||||
|
|
||||||
var newFnArray = [];
|
|
||||||
var newArgsArray = [];
|
|
||||||
var currOffset = 0;
|
|
||||||
var subQueueIdx = 0;
|
|
||||||
for (var i = 0, n = fnArray.length; i < n; ++i) {
|
|
||||||
var offset = i + currOffset;
|
|
||||||
if (fnArray[i] === 'promise') {
|
|
||||||
var data = datas[subQueueIdx++];
|
|
||||||
var subQueue = data.queue;
|
|
||||||
var subQueueFnArray = subQueue.fnArray;
|
|
||||||
var subQueueArgsArray = subQueue.argsArray;
|
|
||||||
for (var j = 0, nn = subQueueFnArray.length; j < nn; ++j) {
|
|
||||||
newFnArray[offset + j] = subQueueFnArray[j];
|
|
||||||
newArgsArray[offset + j] = subQueueArgsArray[j];
|
|
||||||
}
|
|
||||||
currOffset += subQueueFnArray.length - 1;
|
|
||||||
} else {
|
|
||||||
newFnArray[offset] = fnArray[i];
|
|
||||||
newArgsArray[offset] = argsArray[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
promise.resolve({
|
|
||||||
queue: {
|
|
||||||
fnArray: newFnArray,
|
|
||||||
argsArray: newArgsArray,
|
|
||||||
transparency: queue.transparency
|
|
||||||
},
|
|
||||||
dependencies: dependencies
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return promise;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getTextContent: function PartialEvaluator_getTextContent(
|
getTextContent: function PartialEvaluator_getTextContent(
|
||||||
stream, resources) {
|
stream, resources, state) {
|
||||||
|
|
||||||
|
var bidiTexts;
|
||||||
var SPACE_FACTOR = 0.35;
|
var SPACE_FACTOR = 0.35;
|
||||||
var MULTI_SPACE_FACTOR = 1.5;
|
var MULTI_SPACE_FACTOR = 1.5;
|
||||||
|
|
||||||
|
if (!state) {
|
||||||
|
bidiTexts = [];
|
||||||
|
state = {
|
||||||
|
bidiTexts: bidiTexts
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
bidiTexts = state.bidiTexts;
|
||||||
|
}
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
var xref = this.xref;
|
||||||
|
|
||||||
var statePromise = new Promise();
|
function handleSetFont(fontName, fontRef) {
|
||||||
|
return self.loadFont(fontName, fontRef, xref, resources, null);
|
||||||
function handleSetFont(fontName, fontRef, resources) {
|
|
||||||
var promise = new Promise();
|
|
||||||
self.loadFont(fontName, fontRef, self.xref, resources).then(
|
|
||||||
function(data) {
|
|
||||||
promise.resolve(data.font.translated);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return promise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBidiText(str, startLevel, vertical) {
|
resources = xref.fetchIfRef(resources) || new Dict();
|
||||||
if (str) {
|
|
||||||
return PDFJS.bidi(str, -1, vertical);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resources = this.xref.fetchIfRef(resources) || new Dict();
|
|
||||||
// The xobj is parsed iff it's needed, e.g. if there is a `DO` cmd.
|
// The xobj is parsed iff it's needed, e.g. if there is a `DO` cmd.
|
||||||
var xobjs = null;
|
var xobjs = null;
|
||||||
|
|
||||||
var parser = new Parser(new Lexer(stream), false);
|
var parser = new Parser(new Lexer(stream), false);
|
||||||
|
var res = resources;
|
||||||
|
var args = [], obj;
|
||||||
|
|
||||||
var chunkPromises = [];
|
var chunk = '';
|
||||||
var fontPromise;
|
var font = null;
|
||||||
var args = [];
|
while (!isEOF(obj = parser.getObj())) {
|
||||||
|
|
||||||
while (true) {
|
|
||||||
var obj = parser.getObj();
|
|
||||||
if (isEOF(obj)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isCmd(obj)) {
|
if (isCmd(obj)) {
|
||||||
var cmd = obj.cmd;
|
var cmd = obj.cmd;
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
// TODO: Add support for SAVE/RESTORE and XFORM here.
|
// TODO: Add support for SAVE/RESTORE and XFORM here.
|
||||||
case 'Tf':
|
case 'Tf':
|
||||||
fontPromise = handleSetFont(args[0].name, null, resources);
|
font = handleSetFont(args[0].name).translated;
|
||||||
//.translated;
|
|
||||||
break;
|
break;
|
||||||
case 'TJ':
|
case 'TJ':
|
||||||
var chunkPromise = new Promise();
|
var items = args[0];
|
||||||
chunkPromises.push(chunkPromise);
|
for (var j = 0, jj = items.length; j < jj; j++) {
|
||||||
fontPromise.then(function(items, chunkPromise, font) {
|
if (typeof items[j] === 'string') {
|
||||||
var chunk = '';
|
chunk += fontCharsToUnicode(items[j], font);
|
||||||
for (var j = 0, jj = items.length; j < jj; j++) {
|
} else if (items[j] < 0 && font.spaceWidth > 0) {
|
||||||
if (typeof items[j] === 'string') {
|
var fakeSpaces = -items[j] / font.spaceWidth;
|
||||||
chunk += fontCharsToUnicode(items[j], font);
|
if (fakeSpaces > MULTI_SPACE_FACTOR) {
|
||||||
} else if (items[j] < 0 && font.spaceWidth > 0) {
|
fakeSpaces = Math.round(fakeSpaces);
|
||||||
var fakeSpaces = -items[j] / font.spaceWidth;
|
while (fakeSpaces--) {
|
||||||
if (fakeSpaces > MULTI_SPACE_FACTOR) {
|
|
||||||
fakeSpaces = Math.round(fakeSpaces);
|
|
||||||
while (fakeSpaces--) {
|
|
||||||
chunk += ' ';
|
|
||||||
}
|
|
||||||
} else if (fakeSpaces > SPACE_FACTOR) {
|
|
||||||
chunk += ' ';
|
chunk += ' ';
|
||||||
}
|
}
|
||||||
|
} else if (fakeSpaces > SPACE_FACTOR) {
|
||||||
|
chunk += ' ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chunkPromise.resolve(
|
}
|
||||||
getBidiText(chunk, -1, font.vertical));
|
|
||||||
}.bind(null, args[0], chunkPromise));
|
|
||||||
break;
|
break;
|
||||||
case 'Tj':
|
case 'Tj':
|
||||||
var chunkPromise = new Promise();
|
chunk += fontCharsToUnicode(args[0], font);
|
||||||
chunkPromises.push(chunkPromise);
|
|
||||||
fontPromise.then(function(charCodes, chunkPromise, font) {
|
|
||||||
var chunk = fontCharsToUnicode(charCodes, font);
|
|
||||||
chunkPromise.resolve(
|
|
||||||
getBidiText(chunk, -1, font.vertical));
|
|
||||||
}.bind(null, args[0], chunkPromise));
|
|
||||||
break;
|
break;
|
||||||
case '\'':
|
case '\'':
|
||||||
// For search, adding a extra white space for line breaks
|
// For search, adding a extra white space for line breaks would be
|
||||||
// would be better here, but that causes too much spaces in
|
// better here, but that causes too much spaces in the
|
||||||
// the text-selection divs.
|
// text-selection divs.
|
||||||
var chunkPromise = new Promise();
|
chunk += fontCharsToUnicode(args[0], font);
|
||||||
chunkPromises.push(chunkPromise);
|
|
||||||
fontPromise.then(function(charCodes, chunkPromise, font) {
|
|
||||||
var chunk = fontCharsToUnicode(charCodes, font);
|
|
||||||
chunkPromise.resolve(
|
|
||||||
getBidiText(chunk, -1, font.vertical));
|
|
||||||
}.bind(null, args[0], chunkPromise));
|
|
||||||
break;
|
break;
|
||||||
case '"':
|
case '"':
|
||||||
// Note comment in "'"
|
// Note comment in "'"
|
||||||
var chunkPromise = new Promise();
|
chunk += fontCharsToUnicode(args[2], font);
|
||||||
chunkPromises.push(chunkPromise);
|
|
||||||
fontPromise.then(function(charCodes, chunkPromise, font) {
|
|
||||||
var chunk = fontCharsToUnicode(charCodes, font);
|
|
||||||
chunkPromise.resolve(
|
|
||||||
getBidiText(chunk, -1, font.vertical));
|
|
||||||
}.bind(null, args[2], chunkPromise));
|
|
||||||
break;
|
break;
|
||||||
case 'Do':
|
case 'Do':
|
||||||
|
// Set the chunk such that the following if won't add something
|
||||||
|
// to the state.
|
||||||
|
chunk = '';
|
||||||
|
|
||||||
if (args[0].code) {
|
if (args[0].code) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -951,8 +757,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
var xobj = xobjs.get(name);
|
var xobj = xobjs.get(name);
|
||||||
if (!xobj)
|
if (!xobj)
|
||||||
break;
|
break;
|
||||||
assertWellFormed(isStream(xobj),
|
assertWellFormed(isStream(xobj), 'XObject should be a stream');
|
||||||
'XObject should be a stream');
|
|
||||||
|
|
||||||
var type = xobj.dict.get('Subtype');
|
var type = xobj.dict.get('Subtype');
|
||||||
assertWellFormed(
|
assertWellFormed(
|
||||||
@ -963,11 +768,11 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
if ('Form' !== type.name)
|
if ('Form' !== type.name)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
var chunkPromise = self.getTextContent(
|
state = this.getTextContent(
|
||||||
xobj,
|
xobj,
|
||||||
xobj.dict.get('Resources') || resources
|
xobj.dict.get('Resources') || resources,
|
||||||
|
state
|
||||||
);
|
);
|
||||||
chunkPromises.push(chunkPromise);
|
|
||||||
break;
|
break;
|
||||||
case 'gs':
|
case 'gs':
|
||||||
var dictName = args[0];
|
var dictName = args[0];
|
||||||
@ -980,37 +785,27 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
|
|
||||||
for (var i = 0; i < gsState.length; i++) {
|
for (var i = 0; i < gsState.length; i++) {
|
||||||
if (gsState[i] === 'Font') {
|
if (gsState[i] === 'Font') {
|
||||||
fontPromise = handleSetFont(
|
font = handleSetFont(args[0].name).translated;
|
||||||
args[0].name, null, resources);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} // switch
|
} // switch
|
||||||
|
|
||||||
|
if (chunk !== '') {
|
||||||
|
var bidiText = PDFJS.bidi(chunk, -1, font.vertical);
|
||||||
|
bidiTexts.push(bidiText);
|
||||||
|
|
||||||
|
chunk = '';
|
||||||
|
}
|
||||||
|
|
||||||
args = [];
|
args = [];
|
||||||
parser.saveState();
|
|
||||||
} else if (obj !== null && obj !== undefined) {
|
} else if (obj !== null && obj !== undefined) {
|
||||||
assertWellFormed(args.length <= 33, 'Too many arguments');
|
assertWellFormed(args.length <= 33, 'Too many arguments');
|
||||||
args.push(obj);
|
args.push(obj);
|
||||||
}
|
}
|
||||||
} // while
|
} // while
|
||||||
|
|
||||||
Promise.all(chunkPromises).then(function(datas) {
|
return state;
|
||||||
var bidiTexts = [];
|
|
||||||
for (var i = 0, n = datas.length; i < n; ++i) {
|
|
||||||
var bidiText = datas[i];
|
|
||||||
if (!bidiText) {
|
|
||||||
continue;
|
|
||||||
} else if (isArray(bidiText)) {
|
|
||||||
Util.concatenateToArray(bidiTexts, bidiText);
|
|
||||||
} else {
|
|
||||||
bidiTexts.push(bidiText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
statePromise.resolve(bidiTexts);
|
|
||||||
});
|
|
||||||
|
|
||||||
return statePromise;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
extractDataStructures: function
|
extractDataStructures: function
|
||||||
@ -1639,6 +1434,74 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
return PartialEvaluator;
|
return PartialEvaluator;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
var OperatorList = (function OperatorListClosure() {
|
||||||
|
var CHUNK_SIZE = 100;
|
||||||
|
|
||||||
|
function OperatorList(messageHandler, pageIndex) {
|
||||||
|
this.messageHandler = messageHandler;
|
||||||
|
this.fnArray = [];
|
||||||
|
this.argsArray = [];
|
||||||
|
this.dependencies = {},
|
||||||
|
this.pageIndex = pageIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
OperatorList.prototype = {
|
||||||
|
|
||||||
|
addOp: function(fn, args) {
|
||||||
|
this.fnArray.push(fn);
|
||||||
|
this.argsArray.push(args);
|
||||||
|
if (this.messageHandler && this.fnArray.length >= CHUNK_SIZE) {
|
||||||
|
this.flush();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addDependency: function(dependency) {
|
||||||
|
if (dependency in this.dependencies) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.dependencies[dependency] = true;
|
||||||
|
this.addOp('dependency', [dependency]);
|
||||||
|
},
|
||||||
|
|
||||||
|
addDependencies: function(dependencies) {
|
||||||
|
for (var key in dependencies) {
|
||||||
|
this.addDependency(key);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addOpList: function(opList) {
|
||||||
|
Util.concatenateToArray(this.fnArray, opList.fnArray);
|
||||||
|
Util.concatenateToArray(this.argsArray, opList.argsArray);
|
||||||
|
Util.extendObj(this.dependencies, opList.dependencies);
|
||||||
|
},
|
||||||
|
|
||||||
|
getIR: function() {
|
||||||
|
return {
|
||||||
|
fnArray: this.fnArray,
|
||||||
|
argsArray: this.argsArray
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
flush: function(lastChunk) {
|
||||||
|
PartialEvaluator.optimizeQueue(this);
|
||||||
|
this.messageHandler.send('RenderPageChunk', {
|
||||||
|
operatorList: {
|
||||||
|
fnArray: this.fnArray,
|
||||||
|
argsArray: this.argsArray,
|
||||||
|
lastChunk: lastChunk
|
||||||
|
},
|
||||||
|
pageIndex: this.pageIndex
|
||||||
|
});
|
||||||
|
this.dependencies = [];
|
||||||
|
this.fnArray = [];
|
||||||
|
this.argsArray = [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return OperatorList;
|
||||||
|
})();
|
||||||
|
|
||||||
var EvalState = (function EvalStateClosure() {
|
var EvalState = (function EvalStateClosure() {
|
||||||
function EvalState() {
|
function EvalState() {
|
||||||
// Are soft masks and alpha values shapes or opacities?
|
// Are soft masks and alpha values shapes or opacities?
|
||||||
|
@ -903,14 +903,14 @@ var StatTimer = (function StatTimerClosure() {
|
|||||||
if (!this.enabled)
|
if (!this.enabled)
|
||||||
return;
|
return;
|
||||||
if (name in this.started)
|
if (name in this.started)
|
||||||
throw 'Timer is already running for ' + name;
|
warn('Timer is already running for ' + name);
|
||||||
this.started[name] = Date.now();
|
this.started[name] = Date.now();
|
||||||
},
|
},
|
||||||
timeEnd: function StatTimer_timeEnd(name) {
|
timeEnd: function StatTimer_timeEnd(name) {
|
||||||
if (!this.enabled)
|
if (!this.enabled)
|
||||||
return;
|
return;
|
||||||
if (!(name in this.started))
|
if (!(name in this.started))
|
||||||
throw 'Timer has not been started for ' + name;
|
warn('Timer has not been started for ' + name);
|
||||||
this.times.push({
|
this.times.push({
|
||||||
'name': name,
|
'name': name,
|
||||||
'start': this.started[name],
|
'start': this.started[name],
|
||||||
|
@ -398,31 +398,11 @@ var WorkerMessageHandler = {
|
|||||||
var pageNum = data.pageIndex + 1;
|
var pageNum = data.pageIndex + 1;
|
||||||
var start = Date.now();
|
var start = Date.now();
|
||||||
// Pre compile the pdf page and fetch the fonts/images.
|
// Pre compile the pdf page and fetch the fonts/images.
|
||||||
page.getOperatorList(handler).then(function(opListData) {
|
page.getOperatorList(handler).then(function(operatorList) {
|
||||||
|
|
||||||
var operatorList = opListData.queue;
|
|
||||||
var dependency = Object.keys(opListData.dependencies);
|
|
||||||
|
|
||||||
// The following code does quite the same as
|
|
||||||
// Page.prototype.startRendering, but stops at one point and sends the
|
|
||||||
// result back to the main thread.
|
|
||||||
|
|
||||||
log('page=%d - getOperatorList: time=%dms, len=%d', pageNum,
|
log('page=%d - getOperatorList: time=%dms, len=%d', pageNum,
|
||||||
Date.now() - start, operatorList.fnArray.length);
|
Date.now() - start, operatorList.fnArray.length);
|
||||||
|
|
||||||
// Filter the dependecies for fonts.
|
|
||||||
var fonts = {};
|
|
||||||
for (var i = 0, ii = dependency.length; i < ii; i++) {
|
|
||||||
var dep = dependency[i];
|
|
||||||
if (dep.indexOf('g_font_') === 0) {
|
|
||||||
fonts[dep] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
handler.send('RenderPage', {
|
|
||||||
pageIndex: data.pageIndex,
|
|
||||||
operatorList: operatorList,
|
|
||||||
depFonts: Object.keys(fonts)
|
|
||||||
});
|
|
||||||
}, function(e) {
|
}, function(e) {
|
||||||
|
|
||||||
var minimumStackMessage =
|
var minimumStackMessage =
|
||||||
|
@ -36,14 +36,11 @@ describe('evaluator', function() {
|
|||||||
new XrefMock(), new HandlerMock(),
|
new XrefMock(), new HandlerMock(),
|
||||||
'prefix');
|
'prefix');
|
||||||
var stream = new StringStream('qTT');
|
var stream = new StringStream('qTT');
|
||||||
var promise = evaluator.getOperatorList(stream, new ResourcesMock());
|
var result = evaluator.getOperatorList(stream, new ResourcesMock());
|
||||||
promise.then(function(data) {
|
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
|
||||||
var result = data.queue;
|
expect(result.fnArray.length).toEqual(1);
|
||||||
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
|
expect(result.fnArray[0]).toEqual('save');
|
||||||
expect(result.fnArray.length).toEqual(1);
|
expect(result.argsArray[0].length).toEqual(0);
|
||||||
expect(result.fnArray[0]).toEqual('save');
|
|
||||||
expect(result.argsArray[0].length).toEqual(0);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle one operations', function() {
|
it('should handle one operations', function() {
|
||||||
@ -51,13 +48,10 @@ describe('evaluator', function() {
|
|||||||
new XrefMock(), new HandlerMock(),
|
new XrefMock(), new HandlerMock(),
|
||||||
'prefix');
|
'prefix');
|
||||||
var stream = new StringStream('Q');
|
var stream = new StringStream('Q');
|
||||||
var promise = evaluator.getOperatorList(stream, new ResourcesMock());
|
var result = evaluator.getOperatorList(stream, new ResourcesMock());
|
||||||
promise.then(function(data) {
|
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
|
||||||
var result = data.queue;
|
expect(result.fnArray.length).toEqual(1);
|
||||||
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
|
expect(result.fnArray[0]).toEqual('restore');
|
||||||
expect(result.fnArray.length).toEqual(1);
|
|
||||||
expect(result.fnArray[0]).toEqual('restore');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle two glued operations', function() {
|
it('should handle two glued operations', function() {
|
||||||
@ -67,14 +61,11 @@ describe('evaluator', function() {
|
|||||||
var resources = new ResourcesMock();
|
var resources = new ResourcesMock();
|
||||||
resources.Res1 = {};
|
resources.Res1 = {};
|
||||||
var stream = new StringStream('/Res1 DoQ');
|
var stream = new StringStream('/Res1 DoQ');
|
||||||
var promise = evaluator.getOperatorList(stream, resources);
|
var result = evaluator.getOperatorList(stream, resources);
|
||||||
promise.then(function(data) {
|
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
|
||||||
var result = data.queue;
|
expect(result.fnArray.length).toEqual(2);
|
||||||
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
|
expect(result.fnArray[0]).toEqual('paintXObject');
|
||||||
expect(result.fnArray.length).toEqual(2);
|
expect(result.fnArray[1]).toEqual('restore');
|
||||||
expect(result.fnArray[0]).toEqual('paintXObject');
|
|
||||||
expect(result.fnArray[1]).toEqual('restore');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle tree glued operations', function() {
|
it('should handle tree glued operations', function() {
|
||||||
@ -82,15 +73,12 @@ describe('evaluator', function() {
|
|||||||
new XrefMock(), new HandlerMock(),
|
new XrefMock(), new HandlerMock(),
|
||||||
'prefix');
|
'prefix');
|
||||||
var stream = new StringStream('qqq');
|
var stream = new StringStream('qqq');
|
||||||
var promise = evaluator.getOperatorList(stream, new ResourcesMock());
|
var result = evaluator.getOperatorList(stream, new ResourcesMock());
|
||||||
promise.then(function(data) {
|
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
|
||||||
var result = data.queue;
|
expect(result.fnArray.length).toEqual(3);
|
||||||
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
|
expect(result.fnArray[0]).toEqual('save');
|
||||||
expect(result.fnArray.length).toEqual(3);
|
expect(result.fnArray[1]).toEqual('save');
|
||||||
expect(result.fnArray[0]).toEqual('save');
|
expect(result.fnArray[2]).toEqual('save');
|
||||||
expect(result.fnArray[1]).toEqual('save');
|
|
||||||
expect(result.fnArray[2]).toEqual('save');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle three glued operations #2', function() {
|
it('should handle three glued operations #2', function() {
|
||||||
@ -100,15 +88,12 @@ describe('evaluator', function() {
|
|||||||
var resources = new ResourcesMock();
|
var resources = new ResourcesMock();
|
||||||
resources.Res1 = {};
|
resources.Res1 = {};
|
||||||
var stream = new StringStream('B*Bf*');
|
var stream = new StringStream('B*Bf*');
|
||||||
var promise = evaluator.getOperatorList(stream, resources);
|
var result = evaluator.getOperatorList(stream, resources);
|
||||||
promise.then(function(data) {
|
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
|
||||||
var result = data.queue;
|
expect(result.fnArray.length).toEqual(3);
|
||||||
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
|
expect(result.fnArray[0]).toEqual('eoFillStroke');
|
||||||
expect(result.fnArray.length).toEqual(3);
|
expect(result.fnArray[1]).toEqual('fillStroke');
|
||||||
expect(result.fnArray[0]).toEqual('eoFillStroke');
|
expect(result.fnArray[2]).toEqual('eoFill');
|
||||||
expect(result.fnArray[1]).toEqual('fillStroke');
|
|
||||||
expect(result.fnArray[2]).toEqual('eoFill');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle glued operations and operands', function() {
|
it('should handle glued operations and operands', function() {
|
||||||
@ -116,17 +101,14 @@ describe('evaluator', function() {
|
|||||||
new XrefMock(), new HandlerMock(),
|
new XrefMock(), new HandlerMock(),
|
||||||
'prefix');
|
'prefix');
|
||||||
var stream = new StringStream('q5 Ts');
|
var stream = new StringStream('q5 Ts');
|
||||||
var promise = evaluator.getOperatorList(stream, new ResourcesMock());
|
var result = evaluator.getOperatorList(stream, new ResourcesMock());
|
||||||
promise.then(function(data) {
|
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
|
||||||
var result = data.queue;
|
expect(result.fnArray.length).toEqual(2);
|
||||||
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
|
expect(result.fnArray[0]).toEqual('save');
|
||||||
expect(result.fnArray.length).toEqual(2);
|
expect(result.fnArray[1]).toEqual('setTextRise');
|
||||||
expect(result.fnArray[0]).toEqual('save');
|
expect(result.argsArray.length).toEqual(2);
|
||||||
expect(result.fnArray[1]).toEqual('setTextRise');
|
expect(result.argsArray[1].length).toEqual(1);
|
||||||
expect(result.argsArray.length).toEqual(2);
|
expect(result.argsArray[1][0]).toEqual(5);
|
||||||
expect(result.argsArray[1].length).toEqual(1);
|
|
||||||
expect(result.argsArray[1][0]).toEqual(5);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle glued operations and literals', function() {
|
it('should handle glued operations and literals', function() {
|
||||||
@ -134,21 +116,18 @@ describe('evaluator', function() {
|
|||||||
new XrefMock(), new HandlerMock(),
|
new XrefMock(), new HandlerMock(),
|
||||||
'prefix');
|
'prefix');
|
||||||
var stream = new StringStream('trueifalserinullq');
|
var stream = new StringStream('trueifalserinullq');
|
||||||
var promise = evaluator.getOperatorList(stream, new ResourcesMock());
|
var result = evaluator.getOperatorList(stream, new ResourcesMock());
|
||||||
promise.then(function(data) {
|
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
|
||||||
var result = data.queue;
|
expect(result.fnArray.length).toEqual(3);
|
||||||
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
|
expect(result.fnArray[0]).toEqual('setFlatness');
|
||||||
expect(result.fnArray.length).toEqual(3);
|
expect(result.fnArray[1]).toEqual('setRenderingIntent');
|
||||||
expect(result.fnArray[0]).toEqual('setFlatness');
|
expect(result.fnArray[2]).toEqual('save');
|
||||||
expect(result.fnArray[1]).toEqual('setRenderingIntent');
|
expect(result.argsArray.length).toEqual(3);
|
||||||
expect(result.fnArray[2]).toEqual('save');
|
expect(result.argsArray[0].length).toEqual(1);
|
||||||
expect(result.argsArray.length).toEqual(3);
|
expect(result.argsArray[0][0]).toEqual(true);
|
||||||
expect(result.argsArray[0].length).toEqual(1);
|
expect(result.argsArray[1].length).toEqual(1);
|
||||||
expect(result.argsArray[0][0]).toEqual(true);
|
expect(result.argsArray[1][0]).toEqual(false);
|
||||||
expect(result.argsArray[1].length).toEqual(1);
|
expect(result.argsArray[2].length).toEqual(0);
|
||||||
expect(result.argsArray[1][0]).toEqual(false);
|
|
||||||
expect(result.argsArray[2].length).toEqual(0);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -159,39 +138,30 @@ describe('evaluator', function() {
|
|||||||
'prefix');
|
'prefix');
|
||||||
var stream = new StringStream('5 1 d0');
|
var stream = new StringStream('5 1 d0');
|
||||||
console.log('here!');
|
console.log('here!');
|
||||||
var promise = evaluator.getOperatorList(stream, new ResourcesMock());
|
var result = evaluator.getOperatorList(stream, new ResourcesMock());
|
||||||
promise.then(function(data) {
|
expect(result.argsArray[0][0]).toEqual(5);
|
||||||
var result = data.queue;
|
expect(result.argsArray[0][1]).toEqual(1);
|
||||||
expect(result.argsArray[0][0]).toEqual(5);
|
expect(result.fnArray[0]).toEqual('setCharWidth');
|
||||||
expect(result.argsArray[0][1]).toEqual(1);
|
|
||||||
expect(result.fnArray[0]).toEqual('setCharWidth');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
it('should execute if too many arguments', function() {
|
it('should execute if too many arguments', function() {
|
||||||
var evaluator = new PartialEvaluator(new PdfManagerMock(),
|
var evaluator = new PartialEvaluator(new PdfManagerMock(),
|
||||||
new XrefMock(), new HandlerMock(),
|
new XrefMock(), new HandlerMock(),
|
||||||
'prefix');
|
'prefix');
|
||||||
var stream = new StringStream('5 1 4 d0');
|
var stream = new StringStream('5 1 4 d0');
|
||||||
var promise = evaluator.getOperatorList(stream, new ResourcesMock());
|
var result = evaluator.getOperatorList(stream, new ResourcesMock());
|
||||||
promise.then(function(data) {
|
expect(result.argsArray[0][0]).toEqual(5);
|
||||||
var result = data.queue;
|
expect(result.argsArray[0][1]).toEqual(1);
|
||||||
expect(result.argsArray[0][0]).toEqual(5);
|
expect(result.argsArray[0][2]).toEqual(4);
|
||||||
expect(result.argsArray[0][1]).toEqual(1);
|
expect(result.fnArray[0]).toEqual('setCharWidth');
|
||||||
expect(result.argsArray[0][2]).toEqual(4);
|
|
||||||
expect(result.fnArray[0]).toEqual('setCharWidth');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
it('should skip if too few arguments', function() {
|
it('should skip if too few arguments', function() {
|
||||||
var evaluator = new PartialEvaluator(new PdfManagerMock(),
|
var evaluator = new PartialEvaluator(new PdfManagerMock(),
|
||||||
new XrefMock(), new HandlerMock(),
|
new XrefMock(), new HandlerMock(),
|
||||||
'prefix');
|
'prefix');
|
||||||
var stream = new StringStream('5 d0');
|
var stream = new StringStream('5 d0');
|
||||||
var promise = evaluator.getOperatorList(stream, new ResourcesMock());
|
var result = evaluator.getOperatorList(stream, new ResourcesMock());
|
||||||
promise.then(function(data) {
|
expect(result.argsArray).toEqual([]);
|
||||||
var result = data.queue;
|
expect(result.fnArray).toEqual([]);
|
||||||
expect(result.argsArray).toEqual([]);
|
|
||||||
expect(result.fnArray).toEqual([]);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
<script type="text/javascript" src="../../src/chunked_stream.js"></script>
|
<script type="text/javascript" src="../../src/chunked_stream.js"></script>
|
||||||
<script type="text/javascript" src="../../src/pdf_manager.js"></script>
|
<script type="text/javascript" src="../../src/pdf_manager.js"></script>
|
||||||
<script type="text/javascript" src="../../src/core.js"></script>
|
<script type="text/javascript" src="../../src/core.js"></script>
|
||||||
<script type="text/javascript" src="../../src/api.js"></script>
|
|
||||||
<script type="text/javascript" src="../../src/util.js"></script>
|
<script type="text/javascript" src="../../src/util.js"></script>
|
||||||
|
<script type="text/javascript" src="../../src/api.js"></script>
|
||||||
<script type="text/javascript" src="../../src/canvas.js"></script>
|
<script type="text/javascript" src="../../src/canvas.js"></script>
|
||||||
<script type="text/javascript" src="../../src/obj.js"></script>
|
<script type="text/javascript" src="../../src/obj.js"></script>
|
||||||
<script type="text/javascript" src="../../src/annotation.js"></script>
|
<script type="text/javascript" src="../../src/annotation.js"></script>
|
||||||
|
@ -220,26 +220,26 @@ var StepperManager = (function StepperManagerClosure() {
|
|||||||
|
|
||||||
// The stepper for each page's IRQueue.
|
// The stepper for each page's IRQueue.
|
||||||
var Stepper = (function StepperClosure() {
|
var Stepper = (function StepperClosure() {
|
||||||
|
// Shorter way to create element and optionally set textContent.
|
||||||
|
function c(tag, textContent) {
|
||||||
|
var d = document.createElement(tag);
|
||||||
|
if (textContent)
|
||||||
|
d.textContent = textContent;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
function Stepper(panel, pageIndex, initialBreakPoints) {
|
function Stepper(panel, pageIndex, initialBreakPoints) {
|
||||||
this.panel = panel;
|
this.panel = panel;
|
||||||
this.len = 0;
|
|
||||||
this.breakPoint = 0;
|
this.breakPoint = 0;
|
||||||
this.nextBreakPoint = null;
|
this.nextBreakPoint = null;
|
||||||
this.pageIndex = pageIndex;
|
this.pageIndex = pageIndex;
|
||||||
this.breakPoints = initialBreakPoints;
|
this.breakPoints = initialBreakPoints;
|
||||||
this.currentIdx = -1;
|
this.currentIdx = -1;
|
||||||
|
this.operatorListIdx = 0;
|
||||||
}
|
}
|
||||||
Stepper.prototype = {
|
Stepper.prototype = {
|
||||||
init: function init(IRQueue) {
|
init: function init() {
|
||||||
// Shorter way to create element and optionally set textContent.
|
|
||||||
function c(tag, textContent) {
|
|
||||||
var d = document.createElement(tag);
|
|
||||||
if (textContent)
|
|
||||||
d.textContent = textContent;
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
var panel = this.panel;
|
var panel = this.panel;
|
||||||
this.len = IRQueue.fnArray.length;
|
|
||||||
var content = c('div', 'c=continue, s=step');
|
var content = c('div', 'c=continue, s=step');
|
||||||
var table = c('table');
|
var table = c('table');
|
||||||
content.appendChild(table);
|
content.appendChild(table);
|
||||||
@ -250,15 +250,18 @@ var Stepper = (function StepperClosure() {
|
|||||||
headerRow.appendChild(c('th', 'Idx'));
|
headerRow.appendChild(c('th', 'Idx'));
|
||||||
headerRow.appendChild(c('th', 'fn'));
|
headerRow.appendChild(c('th', 'fn'));
|
||||||
headerRow.appendChild(c('th', 'args'));
|
headerRow.appendChild(c('th', 'args'));
|
||||||
|
panel.appendChild(content);
|
||||||
|
this.table = table;
|
||||||
|
},
|
||||||
|
updateOperatorList: function updateOperatorList(operatorList) {
|
||||||
var self = this;
|
var self = this;
|
||||||
for (var i = 0; i < IRQueue.fnArray.length; i++) {
|
for (var i = this.operatorListIdx; i < operatorList.fnArray.length; i++) {
|
||||||
var line = c('tr');
|
var line = c('tr');
|
||||||
line.className = 'line';
|
line.className = 'line';
|
||||||
line.dataset.idx = i;
|
line.dataset.idx = i;
|
||||||
table.appendChild(line);
|
this.table.appendChild(line);
|
||||||
var checked = this.breakPoints.indexOf(i) != -1;
|
var checked = this.breakPoints.indexOf(i) != -1;
|
||||||
var args = IRQueue.argsArray[i] ? IRQueue.argsArray[i] : [];
|
var args = operatorList.argsArray[i] ? operatorList.argsArray[i] : [];
|
||||||
|
|
||||||
var breakCell = c('td');
|
var breakCell = c('td');
|
||||||
var cbox = c('input');
|
var cbox = c('input');
|
||||||
@ -278,11 +281,9 @@ var Stepper = (function StepperClosure() {
|
|||||||
breakCell.appendChild(cbox);
|
breakCell.appendChild(cbox);
|
||||||
line.appendChild(breakCell);
|
line.appendChild(breakCell);
|
||||||
line.appendChild(c('td', i.toString()));
|
line.appendChild(c('td', i.toString()));
|
||||||
line.appendChild(c('td', IRQueue.fnArray[i]));
|
line.appendChild(c('td', operatorList.fnArray[i]));
|
||||||
line.appendChild(c('td', args.join(', ')));
|
line.appendChild(c('td', args.join(', ')));
|
||||||
}
|
}
|
||||||
panel.appendChild(content);
|
|
||||||
var self = this;
|
|
||||||
},
|
},
|
||||||
getNextBreakPoint: function getNextBreakPoint() {
|
getNextBreakPoint: function getNextBreakPoint() {
|
||||||
this.breakPoints.sort(function(a, b) { return a - b; });
|
this.breakPoints.sort(function(a, b) { return a - b; });
|
||||||
|
@ -1553,8 +1553,12 @@ var PageView = function pageView(container, id, scale,
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.update = function pageViewUpdate(scale, rotation) {
|
this.update = function pageViewUpdate(scale, rotation) {
|
||||||
this.renderingState = RenderingStates.INITIAL;
|
if (this.renderTask) {
|
||||||
|
this.renderTask.cancel();
|
||||||
|
this.renderTask = null;
|
||||||
|
}
|
||||||
this.resume = null;
|
this.resume = null;
|
||||||
|
this.renderingState = RenderingStates.INITIAL;
|
||||||
|
|
||||||
if (typeof rotation !== 'undefined') {
|
if (typeof rotation !== 'undefined') {
|
||||||
this.rotation = rotation;
|
this.rotation = rotation;
|
||||||
@ -1818,13 +1822,9 @@ var PageView = function pageView(container, id, scale,
|
|||||||
// Rendering area
|
// Rendering area
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
var renderingWasReset = false;
|
|
||||||
function pageViewDrawCallback(error) {
|
function pageViewDrawCallback(error) {
|
||||||
if (renderingWasReset) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.renderingState = RenderingStates.FINISHED;
|
self.renderingState = RenderingStates.FINISHED;
|
||||||
|
self.renderTask = null;
|
||||||
|
|
||||||
if (self.loadingIconDiv) {
|
if (self.loadingIconDiv) {
|
||||||
div.removeChild(self.loadingIconDiv);
|
div.removeChild(self.loadingIconDiv);
|
||||||
@ -1874,12 +1874,6 @@ var PageView = function pageView(container, id, scale,
|
|||||||
viewport: this.viewport,
|
viewport: this.viewport,
|
||||||
textLayer: textLayer,
|
textLayer: textLayer,
|
||||||
continueCallback: function pdfViewcContinueCallback(cont) {
|
continueCallback: function pdfViewcContinueCallback(cont) {
|
||||||
if (self.renderingState === RenderingStates.INITIAL) {
|
|
||||||
// The page update() was called, we just need to abort any rendering.
|
|
||||||
renderingWasReset = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PDFView.highestPriorityPage !== 'page' + self.id) {
|
if (PDFView.highestPriorityPage !== 'page' + self.id) {
|
||||||
self.renderingState = RenderingStates.PAUSED;
|
self.renderingState = RenderingStates.PAUSED;
|
||||||
self.resume = function resumeCallback() {
|
self.resume = function resumeCallback() {
|
||||||
@ -1891,7 +1885,9 @@ var PageView = function pageView(container, id, scale,
|
|||||||
cont();
|
cont();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.pdfPage.render(renderContext).then(
|
this.renderTask = this.pdfPage.render(renderContext);
|
||||||
|
|
||||||
|
this.renderTask.then(
|
||||||
function pdfPageRenderCallback() {
|
function pdfPageRenderCallback() {
|
||||||
pageViewDrawCallback(null);
|
pageViewDrawCallback(null);
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user