Merge pull request #10033 from timvandermeij/permissions-api

[api-minor] Implement a permissions API
This commit is contained in:
Tim van der Meij 2018-09-02 21:38:29 +02:00 committed by GitHub
commit af89ec271d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 840 additions and 812 deletions

View File

@ -15,9 +15,9 @@
import { import {
bytesToString, createPromiseCapability, createValidAbsoluteUrl, FormatError, bytesToString, createPromiseCapability, createValidAbsoluteUrl, FormatError,
info, InvalidPDFException, isBool, isString, MissingDataException, shadow, info, InvalidPDFException, isBool, isNum, isString, MissingDataException,
stringToPDFString, stringToUTF8String, toRomanNumerals, unreachable, warn, PermissionFlag, shadow, stringToPDFString, stringToUTF8String,
XRefParseException toRomanNumerals, unreachable, warn, XRefParseException
} from '../shared/util'; } from '../shared/util';
import { import {
Dict, isCmd, isDict, isName, isRef, isRefsEqual, isStream, Ref, RefSet, Dict, isCmd, isDict, isName, isRef, isRefsEqual, isStream, Ref, RefSet,
@ -177,6 +177,48 @@ class Catalog {
return (root.items.length > 0 ? root.items : null); return (root.items.length > 0 ? root.items : null);
} }
get permissions() {
let permissions = null;
try {
permissions = this._readPermissions();
} catch (ex) {
if (ex instanceof MissingDataException) {
throw ex;
}
warn('Unable to read permissions.');
}
return shadow(this, 'permissions', permissions);
}
/**
* @private
*/
_readPermissions() {
const encrypt = this.xref.trailer.get('Encrypt');
if (!isDict(encrypt)) {
return null;
}
let flags = encrypt.get('P');
if (!isNum(flags)) {
return null;
}
// PDF integer objects are represented internally in signed 2's complement
// form. Therefore, convert the signed decimal integer to a signed 2's
// complement binary integer so we can use regular bitwise operations on it.
flags += 2 ** 32;
const permissions = [];
for (const key in PermissionFlag) {
const value = PermissionFlag[key];
if (flags & value) {
permissions.push(value);
}
}
return permissions;
}
get numPages() { get numPages() {
const obj = this.toplevelPagesDict.get('Count'); const obj = this.toplevelPagesDict.get('Count');
if (!Number.isInteger(obj)) { if (!Number.isInteger(obj)) {

View File

@ -703,6 +703,10 @@ var WorkerMessageHandler = {
} }
); );
handler.on('GetPermissions', function(data) {
return pdfManager.ensureCatalog('permissions');
});
handler.on('GetMetadata', handler.on('GetMetadata',
function wphSetupGetMetadata(data) { function wphSetupGetMetadata(data) {
return Promise.all([pdfManager.ensureDoc('documentInfo'), return Promise.all([pdfManager.ensureDoc('documentInfo'),

View File

@ -577,92 +577,100 @@ var PDFDataRangeTransport = (function pdfDataRangeTransportClosure() {
/** /**
* Proxy to a PDFDocument in the worker thread. Also, contains commonly used * Proxy to a PDFDocument in the worker thread. Also, contains commonly used
* properties that can be read synchronously. * properties that can be read synchronously.
* @class
* @alias PDFDocumentProxy
*/ */
var PDFDocumentProxy = (function PDFDocumentProxyClosure() { class PDFDocumentProxy {
function PDFDocumentProxy(pdfInfo, transport, loadingTask) { constructor(pdfInfo, transport, loadingTask) {
this._pdfInfo = pdfInfo;
this.transport = transport;
this.loadingTask = loadingTask; this.loadingTask = loadingTask;
this._pdfInfo = pdfInfo;
this._transport = transport;
} }
PDFDocumentProxy.prototype = /** @lends PDFDocumentProxy.prototype */ {
/** /**
* @return {number} Total number of pages the PDF contains. * @return {number} Total number of pages the PDF contains.
*/ */
get numPages() { get numPages() {
return this._pdfInfo.numPages; return this._pdfInfo.numPages;
}, }
/** /**
* @return {string} A unique ID to identify a PDF. Not guaranteed to be * @return {string} A (not guaranteed to be) unique ID to identify a PDF.
* unique.
*/ */
get fingerprint() { get fingerprint() {
return this._pdfInfo.fingerprint; return this._pdfInfo.fingerprint;
}, }
/** /**
* @param {number} pageNumber The page number to get. The first page is 1. * @param {number} pageNumber - The page number to get. The first page is 1.
* @return {Promise} A promise that is resolved with a {@link PDFPageProxy} * @return {Promise} A promise that is resolved with a {@link PDFPageProxy}
* object. * object.
*/ */
getPage(pageNumber) { getPage(pageNumber) {
return this.transport.getPage(pageNumber); return this._transport.getPage(pageNumber);
}, }
/** /**
* @param {{num: number, gen: number}} ref The page reference. Must have * @param {{num: number, gen: number}} ref - The page reference. Must have
* the 'num' and 'gen' properties. * the `num` and `gen` properties.
* @return {Promise} A promise that is resolved with the page index that is * @return {Promise} A promise that is resolved with the page index that is
* associated with the reference. * associated with the reference.
*/ */
getPageIndex: function PDFDocumentProxy_getPageIndex(ref) { getPageIndex(ref) {
return this.transport.getPageIndex(ref); return this._transport.getPageIndex(ref);
}, }
/** /**
* @return {Promise} A promise that is resolved with a lookup table for * @return {Promise} A promise that is resolved with a lookup table for
* mapping named destinations to reference numbers. * mapping named destinations to reference numbers.
* *
* This can be slow for large documents: use getDestination instead * This can be slow for large documents. Use `getDestination` instead.
*/ */
getDestinations: function PDFDocumentProxy_getDestinations() { getDestinations() {
return this.transport.getDestinations(); return this._transport.getDestinations();
}, }
/** /**
* @param {string} id - The named destination to get. * @param {string} id - The named destination to get.
* @return {Promise} A promise that is resolved with all information * @return {Promise} A promise that is resolved with all information
* of the given named destination. * of the given named destination.
*/ */
getDestination: function PDFDocumentProxy_getDestination(id) { getDestination(id) {
return this.transport.getDestination(id); return this._transport.getDestination(id);
}, }
/** /**
* @return {Promise} A promise that is resolved with: * @return {Promise} A promise that is resolved with an {Array} containing
* an Array containing the pageLabels that correspond to the pageIndexes, * the page labels that correspond to the page indexes, or `null` when
* or `null` when no pageLabels are present in the PDF file. * no page labels are present in the PDF file.
*/ */
getPageLabels: function PDFDocumentProxy_getPageLabels() { getPageLabels() {
return this.transport.getPageLabels(); return this._transport.getPageLabels();
}, }
/** /**
* @return {Promise} A promise that is resolved with a {string} containing * @return {Promise} A promise that is resolved with a {string} containing
* the PageMode name. * the page mode name.
*/ */
getPageMode() { getPageMode() {
return this.transport.getPageMode(); return this._transport.getPageMode();
}, }
/** /**
* @return {Promise} A promise that is resolved with a lookup table for * @return {Promise} A promise that is resolved with a lookup table for
* mapping named attachments to their content. * mapping named attachments to their content.
*/ */
getAttachments: function PDFDocumentProxy_getAttachments() { getAttachments() {
return this.transport.getAttachments(); return this._transport.getAttachments();
}, }
/** /**
* @return {Promise} A promise that is resolved with an {Array} of all the * @return {Promise} A promise that is resolved with an {Array} of all the
* JavaScript strings in the name tree, or `null` if no JavaScript exists. * JavaScript strings in the name tree, or `null` if no JavaScript exists.
*/ */
getJavaScript() { getJavaScript() {
return this.transport.getJavaScript(); return this._transport.getJavaScript();
}, }
/** /**
* @return {Promise} A promise that is resolved with an {Array} that is a * @return {Promise} A promise that is resolved with an {Array} that is a
* tree outline (if it has one) of the PDF. The tree is in the format of: * tree outline (if it has one) of the PDF. The tree is in the format of:
@ -677,54 +685,70 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
* items: array of more items like this * items: array of more items like this
* }, * },
* ... * ...
* ]. * ]
*/ */
getOutline: function PDFDocumentProxy_getOutline() { getOutline() {
return this.transport.getOutline(); return this._transport.getOutline();
}, }
/**
* @return {Promise} A promise that is resolved with an {Array} that contains
* the permission flags for the PDF document, or `null` when
* no permissions are present in the PDF file.
*/
getPermissions() {
return this._transport.getPermissions();
}
/** /**
* @return {Promise} A promise that is resolved with an {Object} that has * @return {Promise} A promise that is resolved with an {Object} that has
* info and metadata properties. Info is an {Object} filled with anything * `info` and `metadata` properties. `info` is an {Object} filled with
* available in the information dictionary and similarly metadata is a * anything available in the information dictionary and similarly
* {Metadata} object with information from the metadata section of the PDF. * `metadata` is a {Metadata} object with information from the metadata
* section of the PDF.
*/ */
getMetadata: function PDFDocumentProxy_getMetadata() { getMetadata() {
return this.transport.getMetadata(); return this._transport.getMetadata();
}, }
/** /**
* @return {Promise} A promise that is resolved with a TypedArray that has * @return {Promise} A promise that is resolved with a {TypedArray} that has
* the raw data from the PDF. * the raw data from the PDF.
*/ */
getData: function PDFDocumentProxy_getData() { getData() {
return this.transport.getData(); return this._transport.getData();
}, }
/** /**
* @return {Promise} A promise that is resolved when the document's data * @return {Promise} A promise that is resolved when the document's data
* is loaded. It is resolved with an {Object} that contains the length * is loaded. It is resolved with an {Object} that contains the `length`
* property that indicates size of the PDF data in bytes. * property that indicates size of the PDF data in bytes.
*/ */
getDownloadInfo: function PDFDocumentProxy_getDownloadInfo() { getDownloadInfo() {
return this.transport.downloadInfoCapability.promise; return this._transport.downloadInfoCapability.promise;
}, }
/** /**
* @return {Promise} A promise this is resolved with current stats about * @return {Promise} A promise this is resolved with current statistics about
* document structures (see {@link PDFDocumentStats}). * document structures (see {@link PDFDocumentStats}).
*/ */
getStats: function PDFDocumentProxy_getStats() { getStats() {
return this.transport.getStats(); return this._transport.getStats();
}, }
/** /**
* Cleans up resources allocated by the document, e.g. created @font-face. * Cleans up resources allocated by the document, e.g. created `@font-face`.
*/ */
cleanup: function PDFDocumentProxy_cleanup() { cleanup() {
this.transport.startCleanup(); this._transport.startCleanup();
}, }
/** /**
* Destroys current document instance and terminates worker. * Destroys the current document instance and terminates the worker.
*/ */
destroy: function PDFDocumentProxy_destroy() { destroy() {
return this.loadingTask.destroy(); return this.loadingTask.destroy();
}, }
/** /**
* @return {Object} A subset of the current {DocumentInitParameters}, * @return {Object} A subset of the current {DocumentInitParameters},
@ -732,11 +756,9 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
* may be affected by the `apiCompatibilityParams`. * may be affected by the `apiCompatibilityParams`.
*/ */
get loadingParams() { get loadingParams() {
return this.transport.loadingParams; return this._transport.loadingParams;
}, }
}; }
return PDFDocumentProxy;
})();
/** /**
* Page getTextContent parameters. * Page getTextContent parameters.
@ -1616,8 +1638,8 @@ var PDFWorker = (function PDFWorkerClosure() {
* For internal use only. * For internal use only.
* @ignore * @ignore
*/ */
var WorkerTransport = (function WorkerTransportClosure() { class WorkerTransport {
function WorkerTransport(messageHandler, loadingTask, networkStream, params) { constructor(messageHandler, loadingTask, networkStream, params) {
this.messageHandler = messageHandler; this.messageHandler = messageHandler;
this.loadingTask = loadingTask; this.loadingTask = loadingTask;
this.commonObjs = new PDFObjects(); this.commonObjs = new PDFObjects();
@ -1642,8 +1664,8 @@ var WorkerTransport = (function WorkerTransportClosure() {
this.setupMessageHandler(); this.setupMessageHandler();
} }
WorkerTransport.prototype = {
destroy: function WorkerTransport_destroy() { destroy() {
if (this.destroyCapability) { if (this.destroyCapability) {
return this.destroyCapability.promise; return this.destroyCapability.promise;
} }
@ -1656,10 +1678,10 @@ var WorkerTransport = (function WorkerTransportClosure() {
new Error('Worker was destroyed during onPassword callback')); new Error('Worker was destroyed during onPassword callback'));
} }
var waitOn = []; const waitOn = [];
// We need to wait for all renderings to be completed, e.g. // We need to wait for all renderings to be completed, e.g.
// timeout/rAF can take a long time. // timeout/rAF can take a long time.
this.pageCache.forEach(function (page) { this.pageCache.forEach(function(page) {
if (page) { if (page) {
waitOn.push(page._destroy()); waitOn.push(page._destroy());
} }
@ -1667,7 +1689,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
this.pageCache = []; this.pageCache = [];
this.pagePromises = []; this.pagePromises = [];
// We also need to wait for the worker to finish its long running tasks. // We also need to wait for the worker to finish its long running tasks.
var terminated = this.messageHandler.sendWithPromise('Terminate', null); const terminated = this.messageHandler.sendWithPromise('Terminate', null);
waitOn.push(terminated); waitOn.push(terminated);
Promise.all(waitOn).then(() => { Promise.all(waitOn).then(() => {
this.fontLoader.clear(); this.fontLoader.clear();
@ -1682,11 +1704,10 @@ var WorkerTransport = (function WorkerTransportClosure() {
this.destroyCapability.resolve(); this.destroyCapability.resolve();
}, this.destroyCapability.reject); }, this.destroyCapability.reject);
return this.destroyCapability.promise; return this.destroyCapability.promise;
}, }
setupMessageHandler: function WorkerTransport_setupMessageHandler() { setupMessageHandler() {
var messageHandler = this.messageHandler; const { messageHandler, loadingTask, } = this;
var loadingTask = this.loadingTask;
messageHandler.on('GetReader', function(data, sink) { messageHandler.on('GetReader', function(data, sink) {
assert(this._networkStream); assert(this._networkStream);
@ -1718,21 +1739,19 @@ var WorkerTransport = (function WorkerTransportClosure() {
}, this); }, this);
messageHandler.on('ReaderHeadersReady', function(data) { messageHandler.on('ReaderHeadersReady', function(data) {
let headersCapability = createPromiseCapability(); const headersCapability = createPromiseCapability();
let fullReader = this._fullReader; const fullReader = this._fullReader;
fullReader.headersReady.then(() => { fullReader.headersReady.then(() => {
// If stream or range are disabled, it's our only way to report // If stream or range are disabled, it's our only way to report
// loading progress. // loading progress.
if (!fullReader.isStreamingSupported || if (!fullReader.isStreamingSupported ||
!fullReader.isRangeSupported) { !fullReader.isRangeSupported) {
if (this._lastProgress) { if (this._lastProgress) {
let loadingTask = this.loadingTask;
if (loadingTask.onProgress) { if (loadingTask.onProgress) {
loadingTask.onProgress(this._lastProgress); loadingTask.onProgress(this._lastProgress);
} }
} }
fullReader.onProgress = (evt) => { fullReader.onProgress = (evt) => {
let loadingTask = this.loadingTask;
if (loadingTask.onProgress) { if (loadingTask.onProgress) {
loadingTask.onProgress({ loadingTask.onProgress({
loaded: evt.loaded, loaded: evt.loaded,
@ -1754,11 +1773,11 @@ var WorkerTransport = (function WorkerTransportClosure() {
messageHandler.on('GetRangeReader', function(data, sink) { messageHandler.on('GetRangeReader', function(data, sink) {
assert(this._networkStream); assert(this._networkStream);
let _rangeReader = const rangeReader =
this._networkStream.getRangeReader(data.begin, data.end); this._networkStream.getRangeReader(data.begin, data.end);
sink.onPull = () => { sink.onPull = () => {
_rangeReader.read().then(function({ value, done, }) { rangeReader.read().then(function({ value, done, }) {
if (done) { if (done) {
sink.close(); sink.close();
return; return;
@ -1771,24 +1790,21 @@ var WorkerTransport = (function WorkerTransportClosure() {
}; };
sink.onCancel = (reason) => { sink.onCancel = (reason) => {
_rangeReader.cancel(reason); rangeReader.cancel(reason);
}; };
}, this); }, this);
messageHandler.on('GetDoc', function transportDoc({ pdfInfo, }) { messageHandler.on('GetDoc', function({ pdfInfo, }) {
this.numPages = pdfInfo.numPages; this.numPages = pdfInfo.numPages;
var loadingTask = this.loadingTask; this.pdfDocument = new PDFDocumentProxy(pdfInfo, this, loadingTask);
var pdfDocument = new PDFDocumentProxy(pdfInfo, this, loadingTask); loadingTask._capability.resolve(this.pdfDocument);
this.pdfDocument = pdfDocument;
loadingTask._capability.resolve(pdfDocument);
}, this); }, this);
messageHandler.on('PasswordRequest', messageHandler.on('PasswordRequest', function(exception) {
function transportPasswordRequest(exception) {
this._passwordCapability = createPromiseCapability(); this._passwordCapability = createPromiseCapability();
if (loadingTask.onPassword) { if (loadingTask.onPassword) {
var updatePassword = (password) => { const updatePassword = (password) => {
this._passwordCapability.resolve({ this._passwordCapability.resolve({
password, password,
}); });
@ -1805,80 +1821,76 @@ var WorkerTransport = (function WorkerTransportClosure() {
return this._passwordCapability.promise; return this._passwordCapability.promise;
}, this); }, this);
messageHandler.on('PasswordException', messageHandler.on('PasswordException', function(exception) {
function transportPasswordException(exception) {
loadingTask._capability.reject( loadingTask._capability.reject(
new PasswordException(exception.message, exception.code)); new PasswordException(exception.message, exception.code));
}, this); }, this);
messageHandler.on('InvalidPDF', function transportInvalidPDF(exception) { messageHandler.on('InvalidPDF', function(exception) {
this.loadingTask._capability.reject( loadingTask._capability.reject(
new InvalidPDFException(exception.message)); new InvalidPDFException(exception.message));
}, this); }, this);
messageHandler.on('MissingPDF', function transportMissingPDF(exception) { messageHandler.on('MissingPDF', function(exception) {
this.loadingTask._capability.reject( loadingTask._capability.reject(
new MissingPDFException(exception.message)); new MissingPDFException(exception.message));
}, this); }, this);
messageHandler.on('UnexpectedResponse', messageHandler.on('UnexpectedResponse', function(exception) {
function transportUnexpectedResponse(exception) { loadingTask._capability.reject(
this.loadingTask._capability.reject(
new UnexpectedResponseException(exception.message, exception.status)); new UnexpectedResponseException(exception.message, exception.status));
}, this); }, this);
messageHandler.on('UnknownError', messageHandler.on('UnknownError', function(exception) {
function transportUnknownError(exception) { loadingTask._capability.reject(
this.loadingTask._capability.reject(
new UnknownErrorException(exception.message, exception.details)); new UnknownErrorException(exception.message, exception.details));
}, this); }, this);
messageHandler.on('DataLoaded', function transportPage(data) { messageHandler.on('DataLoaded', function(data) {
this.downloadInfoCapability.resolve(data); this.downloadInfoCapability.resolve(data);
}, this); }, this);
messageHandler.on('StartRenderPage', function transportRender(data) { messageHandler.on('StartRenderPage', function(data) {
if (this.destroyed) { if (this.destroyed) {
return; // Ignore any pending requests if the worker was terminated. return; // Ignore any pending requests if the worker was terminated.
} }
var page = this.pageCache[data.pageIndex];
const page = this.pageCache[data.pageIndex];
page._stats.timeEnd('Page Request'); page._stats.timeEnd('Page Request');
page._startRenderPage(data.transparency, data.intent); page._startRenderPage(data.transparency, data.intent);
}, this); }, this);
messageHandler.on('RenderPageChunk', function transportRender(data) { messageHandler.on('RenderPageChunk', function(data) {
if (this.destroyed) { if (this.destroyed) {
return; // Ignore any pending requests if the worker was terminated. return; // Ignore any pending requests if the worker was terminated.
} }
var page = this.pageCache[data.pageIndex];
const page = this.pageCache[data.pageIndex];
page._renderPageChunk(data.operatorList, data.intent); page._renderPageChunk(data.operatorList, data.intent);
}, this); }, this);
messageHandler.on('commonobj', function transportObj(data) { messageHandler.on('commonobj', function(data) {
if (this.destroyed) { if (this.destroyed) {
return; // Ignore any pending requests if the worker was terminated. return; // Ignore any pending requests if the worker was terminated.
} }
var id = data[0]; const [id, type, exportedData] = data;
var type = data[1];
if (this.commonObjs.hasData(id)) { if (this.commonObjs.hasData(id)) {
return; return;
} }
switch (type) { switch (type) {
case 'Font': case 'Font':
var exportedData = data[2]; const params = this._params;
let params = this._params;
if ('error' in exportedData) { if ('error' in exportedData) {
var exportedError = exportedData.error; const exportedError = exportedData.error;
warn('Error during font loading: ' + exportedError); warn(`Error during font loading: ${exportedError}`);
this.commonObjs.resolve(id, exportedError); this.commonObjs.resolve(id, exportedError);
break; break;
} }
var fontRegistry = null;
let fontRegistry = null;
if (params.pdfBug && globalScope.FontInspector && if (params.pdfBug && globalScope.FontInspector &&
globalScope.FontInspector.enabled) { globalScope.FontInspector.enabled) {
fontRegistry = { fontRegistry = {
@ -1887,44 +1899,40 @@ var WorkerTransport = (function WorkerTransportClosure() {
}, },
}; };
} }
var font = new FontFaceObject(exportedData, { const font = new FontFaceObject(exportedData, {
isEvalSupported: params.isEvalSupported, isEvalSupported: params.isEvalSupported,
disableFontFace: params.disableFontFace, disableFontFace: params.disableFontFace,
ignoreErrors: params.ignoreErrors, ignoreErrors: params.ignoreErrors,
onUnsupportedFeature: this._onUnsupportedFeature.bind(this), onUnsupportedFeature: this._onUnsupportedFeature.bind(this),
fontRegistry, fontRegistry,
}); });
var fontReady = (fontObjs) => { const fontReady = (fontObjs) => {
this.commonObjs.resolve(id, font); this.commonObjs.resolve(id, font);
}; };
this.fontLoader.bind([font], fontReady); this.fontLoader.bind([font], fontReady);
break; break;
case 'FontPath': case 'FontPath':
this.commonObjs.resolve(id, data[2]); this.commonObjs.resolve(id, exportedData);
break; break;
default: default:
throw new Error(`Got unknown common object type ${type}`); throw new Error(`Got unknown common object type ${type}`);
} }
}, this); }, this);
messageHandler.on('obj', function transportObj(data) { messageHandler.on('obj', function(data) {
if (this.destroyed) { if (this.destroyed) {
return; // Ignore any pending requests if the worker was terminated. return; // Ignore any pending requests if the worker was terminated.
} }
var id = data[0]; const [id, pageIndex, type, imageData] = data;
var pageIndex = data[1]; const pageProxy = this.pageCache[pageIndex];
var type = data[2];
var pageProxy = this.pageCache[pageIndex];
var imageData;
if (pageProxy.objs.hasData(id)) { if (pageProxy.objs.hasData(id)) {
return; return;
} }
switch (type) { switch (type) {
case 'JpegStream': case 'JpegStream':
imageData = data[3];
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const img = new Image(); const img = new Image();
img.onload = function() { img.onload = function() {
@ -1942,11 +1950,10 @@ var WorkerTransport = (function WorkerTransportClosure() {
pageProxy.objs.resolve(id, img); pageProxy.objs.resolve(id, img);
}); });
case 'Image': case 'Image':
imageData = data[3];
pageProxy.objs.resolve(id, imageData); pageProxy.objs.resolve(id, imageData);
// heuristics that will allow not to store large data // Heuristic that will allow us not to store large data.
var MAX_IMAGE_SIZE_TO_STORE = 8000000; const MAX_IMAGE_SIZE_TO_STORE = 8000000;
if (imageData && 'data' in imageData && if (imageData && 'data' in imageData &&
imageData.data.length > MAX_IMAGE_SIZE_TO_STORE) { imageData.data.length > MAX_IMAGE_SIZE_TO_STORE) {
pageProxy.cleanupAfterRender = true; pageProxy.cleanupAfterRender = true;
@ -1957,12 +1964,11 @@ var WorkerTransport = (function WorkerTransportClosure() {
} }
}, this); }, this);
messageHandler.on('DocProgress', function transportDocProgress(data) { messageHandler.on('DocProgress', function(data) {
if (this.destroyed) { if (this.destroyed) {
return; // Ignore any pending requests if the worker was terminated. return; // Ignore any pending requests if the worker was terminated.
} }
var loadingTask = this.loadingTask;
if (loadingTask.onProgress) { if (loadingTask.onProgress) {
loadingTask.onProgress({ loadingTask.onProgress({
loaded: data.loaded, loaded: data.loaded,
@ -1971,13 +1977,13 @@ var WorkerTransport = (function WorkerTransportClosure() {
} }
}, this); }, this);
messageHandler.on('PageError', function transportError(data) { messageHandler.on('PageError', function(data) {
if (this.destroyed) { if (this.destroyed) {
return; // Ignore any pending requests if the worker was terminated. return; // Ignore any pending requests if the worker was terminated.
} }
var page = this.pageCache[data.pageNum - 1]; const page = this.pageCache[data.pageNum - 1];
var intentState = page.intentStates[data.intent]; const intentState = page.intentStates[data.intent];
if (intentState.displayReadyCapability) { if (intentState.displayReadyCapability) {
intentState.displayReadyCapability.reject(data.error); intentState.displayReadyCapability.reject(data.error);
@ -1988,7 +1994,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
if (intentState.operatorList) { if (intentState.operatorList) {
// Mark operator list as complete. // Mark operator list as complete.
intentState.operatorList.lastChunk = true; intentState.operatorList.lastChunk = true;
for (var i = 0; i < intentState.renderTasks.length; i++) { for (let i = 0; i < intentState.renderTasks.length; i++) {
intentState.renderTasks[i].operatorListChanged(); intentState.renderTasks[i].operatorListChanged();
} }
} }
@ -2007,37 +2013,35 @@ var WorkerTransport = (function WorkerTransportClosure() {
return Promise.reject(new Error('"document" is not defined.')); return Promise.reject(new Error('"document" is not defined.'));
} }
var imageUrl = data[0]; const [imageUrl, components] = data;
var components = data[1];
if (components !== 3 && components !== 1) { if (components !== 3 && components !== 1) {
return Promise.reject( return Promise.reject(
new Error('Only 3 components or 1 component can be returned')); new Error('Only 3 components or 1 component can be returned'));
} }
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
var img = new Image(); const img = new Image();
img.onload = function () { img.onload = function () {
var width = img.width; const width = img.width;
var height = img.height; const height = img.height;
var size = width * height; const size = width * height;
var rgbaLength = size * 4; const rgbaLength = size * 4;
var buf = new Uint8ClampedArray(size * components); const buf = new Uint8ClampedArray(size * components);
var tmpCanvas = document.createElement('canvas'); const tmpCanvas = document.createElement('canvas');
tmpCanvas.width = width; tmpCanvas.width = width;
tmpCanvas.height = height; tmpCanvas.height = height;
var tmpCtx = tmpCanvas.getContext('2d'); const tmpCtx = tmpCanvas.getContext('2d');
tmpCtx.drawImage(img, 0, 0); tmpCtx.drawImage(img, 0, 0);
var data = tmpCtx.getImageData(0, 0, width, height).data; const data = tmpCtx.getImageData(0, 0, width, height).data;
var i, j;
if (components === 3) { if (components === 3) {
for (i = 0, j = 0; i < rgbaLength; i += 4, j += 3) { for (let i = 0, j = 0; i < rgbaLength; i += 4, j += 3) {
buf[j] = data[i]; buf[j] = data[i];
buf[j + 1] = data[i + 1]; buf[j + 1] = data[i + 1];
buf[j + 2] = data[i + 2]; buf[j + 2] = data[i + 2];
} }
} else if (components === 1) { } else if (components === 1) {
for (i = 0, j = 0; i < rgbaLength; i += 4, j++) { for (let i = 0, j = 0; i < rgbaLength; i += 4, j++) {
buf[j] = data[i]; buf[j] = data[i];
} }
} }
@ -2050,7 +2054,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
}); });
}, this); }, this);
messageHandler.on('FetchBuiltInCMap', function (data) { messageHandler.on('FetchBuiltInCMap', function(data) {
if (this.destroyed) { if (this.destroyed) {
return Promise.reject(new Error('Worker was destroyed')); return Promise.reject(new Error('Worker was destroyed'));
} }
@ -2058,21 +2062,20 @@ var WorkerTransport = (function WorkerTransportClosure() {
name: data.name, name: data.name,
}); });
}, this); }, this);
}, }
_onUnsupportedFeature({ featureId, }) { _onUnsupportedFeature({ featureId, }) {
if (this.destroyed) { if (this.destroyed) {
return; // Ignore any pending requests if the worker was terminated. return; // Ignore any pending requests if the worker was terminated.
} }
let loadingTask = this.loadingTask; if (this.loadingTask.onUnsupportedFeature) {
if (loadingTask.onUnsupportedFeature) { this.loadingTask.onUnsupportedFeature(featureId);
loadingTask.onUnsupportedFeature(featureId); }
} }
},
getData: function WorkerTransport_getData() { getData() {
return this.messageHandler.sendWithPromise('GetData', null); return this.messageHandler.sendWithPromise('GetData', null);
}, }
getPage(pageNumber) { getPage(pageNumber) {
if (!Number.isInteger(pageNumber) || if (!Number.isInteger(pageNumber) ||
@ -2080,74 +2083,78 @@ var WorkerTransport = (function WorkerTransportClosure() {
return Promise.reject(new Error('Invalid page request')); return Promise.reject(new Error('Invalid page request'));
} }
var pageIndex = pageNumber - 1; const pageIndex = pageNumber - 1;
if (pageIndex in this.pagePromises) { if (pageIndex in this.pagePromises) {
return this.pagePromises[pageIndex]; return this.pagePromises[pageIndex];
} }
var promise = this.messageHandler.sendWithPromise('GetPage', { const promise = this.messageHandler.sendWithPromise('GetPage', {
pageIndex, pageIndex,
}).then((pageInfo) => { }).then((pageInfo) => {
if (this.destroyed) { if (this.destroyed) {
throw new Error('Transport destroyed'); throw new Error('Transport destroyed');
} }
let page = new PDFPageProxy(pageIndex, pageInfo, this, const page = new PDFPageProxy(pageIndex, pageInfo, this,
this._params.pdfBug); this._params.pdfBug);
this.pageCache[pageIndex] = page; this.pageCache[pageIndex] = page;
return page; return page;
}); });
this.pagePromises[pageIndex] = promise; this.pagePromises[pageIndex] = promise;
return promise; return promise;
}, }
getPageIndex: function WorkerTransport_getPageIndexByRef(ref) { getPageIndex(ref) {
return this.messageHandler.sendWithPromise('GetPageIndex', { return this.messageHandler.sendWithPromise('GetPageIndex', {
ref, ref,
}).catch(function (reason) { }).catch(function(reason) {
return Promise.reject(new Error(reason)); return Promise.reject(new Error(reason));
}); });
}, }
getAnnotations: function WorkerTransport_getAnnotations(pageIndex, intent) { getAnnotations(pageIndex, intent) {
return this.messageHandler.sendWithPromise('GetAnnotations', { return this.messageHandler.sendWithPromise('GetAnnotations', {
pageIndex, pageIndex,
intent, intent,
}); });
}, }
getDestinations: function WorkerTransport_getDestinations() { getDestinations() {
return this.messageHandler.sendWithPromise('GetDestinations', null); return this.messageHandler.sendWithPromise('GetDestinations', null);
}, }
getDestination: function WorkerTransport_getDestination(id) { getDestination(id) {
if (typeof id !== 'string') { if (typeof id !== 'string') {
return Promise.reject(new Error('Invalid destination request.')); return Promise.reject(new Error('Invalid destination request.'));
} }
return this.messageHandler.sendWithPromise('GetDestination', { return this.messageHandler.sendWithPromise('GetDestination', {
id, id,
}); });
}, }
getPageLabels: function WorkerTransport_getPageLabels() { getPageLabels() {
return this.messageHandler.sendWithPromise('GetPageLabels', null); return this.messageHandler.sendWithPromise('GetPageLabels', null);
}, }
getPageMode() { getPageMode() {
return this.messageHandler.sendWithPromise('GetPageMode', null); return this.messageHandler.sendWithPromise('GetPageMode', null);
}, }
getAttachments: function WorkerTransport_getAttachments() { getAttachments() {
return this.messageHandler.sendWithPromise('GetAttachments', null); return this.messageHandler.sendWithPromise('GetAttachments', null);
}, }
getJavaScript: function WorkerTransport_getJavaScript() { getJavaScript() {
return this.messageHandler.sendWithPromise('GetJavaScript', null); return this.messageHandler.sendWithPromise('GetJavaScript', null);
}, }
getOutline: function WorkerTransport_getOutline() { getOutline() {
return this.messageHandler.sendWithPromise('GetOutline', null); return this.messageHandler.sendWithPromise('GetOutline', null);
}, }
getMetadata: function WorkerTransport_getMetadata() { getPermissions() {
return this.messageHandler.sendWithPromise('GetPermissions', null);
}
getMetadata() {
return this.messageHandler.sendWithPromise('GetMetadata', null). return this.messageHandler.sendWithPromise('GetMetadata', null).
then((results) => { then((results) => {
return { return {
@ -2157,16 +2164,16 @@ var WorkerTransport = (function WorkerTransportClosure() {
this._fullReader.filename : null), this._fullReader.filename : null),
}; };
}); });
}, }
getStats: function WorkerTransport_getStats() { getStats() {
return this.messageHandler.sendWithPromise('GetStats', null); return this.messageHandler.sendWithPromise('GetStats', null);
}, }
startCleanup: function WorkerTransport_startCleanup() { startCleanup() {
this.messageHandler.sendWithPromise('Cleanup', null).then(() => { this.messageHandler.sendWithPromise('Cleanup', null).then(() => {
for (var i = 0, ii = this.pageCache.length; i < ii; i++) { for (let i = 0, ii = this.pageCache.length; i < ii; i++) {
var page = this.pageCache[i]; const page = this.pageCache[i];
if (page) { if (page) {
page.cleanup(); page.cleanup();
} }
@ -2174,21 +2181,18 @@ var WorkerTransport = (function WorkerTransportClosure() {
this.commonObjs.clear(); this.commonObjs.clear();
this.fontLoader.clear(); this.fontLoader.clear();
}); });
}, }
get loadingParams() { get loadingParams() {
let params = this._params; const params = this._params;
return shadow(this, 'loadingParams', { return shadow(this, 'loadingParams', {
disableAutoFetch: params.disableAutoFetch, disableAutoFetch: params.disableAutoFetch,
disableCreateObjectURL: params.disableCreateObjectURL, disableCreateObjectURL: params.disableCreateObjectURL,
disableFontFace: params.disableFontFace, disableFontFace: params.disableFontFace,
nativeImageDecoderSupport: params.nativeImageDecoderSupport, nativeImageDecoderSupport: params.nativeImageDecoderSupport,
}); });
}, }
}; }
return WorkerTransport;
})();
/** /**
* A PDF document and page is built of many objects. E.g. there are objects * A PDF document and page is built of many objects. E.g. there are objects

View File

@ -25,6 +25,18 @@ const NativeImageDecoding = {
DISPLAY: 'display', DISPLAY: 'display',
}; };
// Permission flags from Table 22, Section 7.6.3.2 of the PDF specification.
const PermissionFlag = {
PRINT: 0x04,
MODIFY_CONTENTS: 0x08,
COPY: 0x10,
MODIFY_ANNOTATIONS: 0x20,
FILL_INTERACTIVE_FORMS: 0x100,
COPY_FOR_ACCESSIBILITY: 0x200,
ASSEMBLE: 0x400,
PRINT_HIGH_QUALITY: 0x800,
};
var TextRenderingMode = { var TextRenderingMode = {
FILL: 0, FILL: 0,
STROKE: 1, STROKE: 1,
@ -1014,6 +1026,7 @@ export {
NativeImageDecoding, NativeImageDecoding,
PasswordException, PasswordException,
PasswordResponses, PasswordResponses,
PermissionFlag,
StreamType, StreamType,
TextRenderingMode, TextRenderingMode,
UnexpectedResponseException, UnexpectedResponseException,

View File

@ -325,3 +325,6 @@
!transparent.pdf !transparent.pdf
!xobject-image.pdf !xobject-image.pdf
!ccitt_EndOfBlock_false.pdf !ccitt_EndOfBlock_false.pdf
!issue9972-1.pdf
!issue9972-2.pdf
!issue9972-3.pdf

BIN
test/pdfs/issue9972-1.pdf Normal file

Binary file not shown.

BIN
test/pdfs/issue9972-2.pdf Normal file

Binary file not shown.

BIN
test/pdfs/issue9972-3.pdf Normal file

Binary file not shown.

View File

@ -18,7 +18,8 @@ import {
} from './test_utils'; } from './test_utils';
import { import {
createPromiseCapability, FontType, InvalidPDFException, MissingPDFException, createPromiseCapability, FontType, InvalidPDFException, MissingPDFException,
OPS, PasswordException, PasswordResponses, StreamType, stringToBytes OPS, PasswordException, PasswordResponses, PermissionFlag, StreamType,
stringToBytes
} from '../../src/shared/util'; } from '../../src/shared/util';
import { import {
DOMCanvasFactory, RenderingCancelledException, StatTimer DOMCanvasFactory, RenderingCancelledException, StatTimer
@ -84,9 +85,7 @@ describe('api', function() {
expect(data[1] instanceof PDFDocumentProxy).toEqual(true); expect(data[1] instanceof PDFDocumentProxy).toEqual(true);
expect(loadingTask).toEqual(data[1].loadingTask); expect(loadingTask).toEqual(data[1].loadingTask);
loadingTask.destroy().then(done); loadingTask.destroy().then(done);
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('creates pdf doc from URL and aborts before worker initialized', it('creates pdf doc from URL and aborts before worker initialized',
function(done) { function(done) {
@ -111,9 +110,7 @@ describe('api', function() {
destroyed.then(function (data) { destroyed.then(function (data) {
expect(true).toEqual(true); expect(true).toEqual(true);
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('creates pdf doc from typed array', function(done) { it('creates pdf doc from typed array', function(done) {
var typedArrayPdf; var typedArrayPdf;
@ -149,9 +146,7 @@ describe('api', function() {
loadingTask.promise.then(function(data) { loadingTask.promise.then(function(data) {
expect(data instanceof PDFDocumentProxy).toEqual(true); expect(data instanceof PDFDocumentProxy).toEqual(true);
loadingTask.destroy().then(done); loadingTask.destroy().then(done);
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('creates pdf doc from invalid PDF file', function(done) { it('creates pdf doc from invalid PDF file', function(done) {
// A severely corrupt PDF file (even Adobe Reader fails to open it). // A severely corrupt PDF file (even Adobe Reader fails to open it).
@ -213,9 +208,7 @@ describe('api', function() {
Promise.all(promises).then(function (data) { Promise.all(promises).then(function (data) {
expect(data[2] instanceof PDFDocumentProxy).toEqual(true); expect(data[2] instanceof PDFDocumentProxy).toEqual(true);
loadingTask.destroy().then(done); loadingTask.destroy().then(done);
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('creates pdf doc from PDF file protected with only a user password', it('creates pdf doc from PDF file protected with only a user password',
function (done) { function (done) {
@ -257,9 +250,7 @@ describe('api', function() {
}); });
Promise.all([result1, result2, result3]).then(function () { Promise.all([result1, result2, result3]).then(function () {
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('creates pdf doc from password protected PDF file and aborts/throws ' + it('creates pdf doc from password protected PDF file and aborts/throws ' +
@ -309,9 +300,7 @@ describe('api', function() {
Promise.all([result1, result2]).then(function () { Promise.all([result1, result2]).then(function () {
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
}); });
@ -333,9 +322,7 @@ describe('api', function() {
expect(!!worker.port).toEqual(false); expect(!!worker.port).toEqual(false);
expect(worker.destroyed).toEqual(true); expect(worker.destroyed).toEqual(true);
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('worker created or destroyed by getDocument', function (done) { it('worker created or destroyed by getDocument', function (done) {
if (isNodeJS()) { if (isNodeJS()) {
@ -357,9 +344,7 @@ describe('api', function() {
expect(!!destroyedWorker).toEqual(false); expect(!!destroyedWorker).toEqual(false);
expect(worker.destroyed).toEqual(true); expect(worker.destroyed).toEqual(true);
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('worker created and can be used in getDocument', function (done) { it('worker created and can be used in getDocument', function (done) {
if (isNodeJS()) { if (isNodeJS()) {
@ -386,9 +371,7 @@ describe('api', function() {
expect(worker.destroyed).toEqual(false); expect(worker.destroyed).toEqual(false);
worker.destroy(); worker.destroy();
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('creates more than one worker', function (done) { it('creates more than one worker', function (done) {
if (isNodeJS()) { if (isNodeJS()) {
@ -408,9 +391,7 @@ describe('api', function() {
worker2.destroy(); worker2.destroy();
worker3.destroy(); worker3.destroy();
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets current workerSrc', function() { it('gets current workerSrc', function() {
if (isNodeJS()) { if (isNodeJS()) {
@ -452,9 +433,7 @@ describe('api', function() {
expect(data instanceof PDFPageProxy).toEqual(true); expect(data instanceof PDFPageProxy).toEqual(true);
expect(data.pageIndex).toEqual(0); expect(data.pageIndex).toEqual(0);
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets non-existent page', function(done) { it('gets non-existent page', function(done) {
var outOfRangePromise = doc.getPage(100); var outOfRangePromise = doc.getPage(100);
@ -480,9 +459,7 @@ describe('api', function() {
Promise.all([outOfRangePromise, nonIntegerPromise, nonNumberPromise]). Promise.all([outOfRangePromise, nonIntegerPromise, nonNumberPromise]).
then(function () { then(function () {
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets page index', function(done) { it('gets page index', function(done) {
// reference to second page // reference to second page
@ -491,9 +468,7 @@ describe('api', function() {
promise.then(function(pageIndex) { promise.then(function(pageIndex) {
expect(pageIndex).toEqual(1); expect(pageIndex).toEqual(1);
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets invalid page index', function (done) { it('gets invalid page index', function (done) {
var ref = { num: 3, gen: 0, }; // Reference to a font dictionary. var ref = { num: 3, gen: 0, }; // Reference to a font dictionary.
@ -513,9 +488,7 @@ describe('api', function() {
chapter1: [{ gen: 0, num: 17, }, { name: 'XYZ', }, 0, 841.89, null], chapter1: [{ gen: 0, num: 17, }, { name: 'XYZ', }, 0, 841.89, null],
}); });
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets a destination, from /Dests dictionary', function(done) { it('gets a destination, from /Dests dictionary', function(done) {
var promise = doc.getDestination('chapter1'); var promise = doc.getDestination('chapter1');
@ -523,9 +496,7 @@ describe('api', function() {
expect(data).toEqual([{ gen: 0, num: 17, }, { name: 'XYZ', }, expect(data).toEqual([{ gen: 0, num: 17, }, { name: 'XYZ', },
0, 841.89, null]); 0, 841.89, null]);
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets a non-existent destination, from /Dests dictionary', it('gets a non-existent destination, from /Dests dictionary',
function(done) { function(done) {
@ -533,9 +504,7 @@ describe('api', function() {
promise.then(function(data) { promise.then(function(data) {
expect(data).toEqual(null); expect(data).toEqual(null);
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets destinations, from /Names (NameTree) dictionary', function(done) { it('gets destinations, from /Names (NameTree) dictionary', function(done) {
@ -550,9 +519,7 @@ describe('api', function() {
}); });
loadingTask.destroy().then(done); loadingTask.destroy().then(done);
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets a destination, from /Names (NameTree) dictionary', function(done) { it('gets a destination, from /Names (NameTree) dictionary', function(done) {
var loadingTask = getDocument(buildGetDocumentParams('issue6204.pdf')); var loadingTask = getDocument(buildGetDocumentParams('issue6204.pdf'));
@ -564,9 +531,7 @@ describe('api', function() {
0, 375, null]); 0, 375, null]);
loadingTask.destroy().then(done); loadingTask.destroy().then(done);
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets a non-existent destination, from /Names (NameTree) dictionary', it('gets a non-existent destination, from /Names (NameTree) dictionary',
function(done) { function(done) {
@ -578,9 +543,7 @@ describe('api', function() {
expect(destination).toEqual(null); expect(destination).toEqual(null);
loadingTask.destroy().then(done); loadingTask.destroy().then(done);
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets non-string destination', function(done) { it('gets non-string destination', function(done) {
@ -614,9 +577,7 @@ describe('api', function() {
promise.then(function (data) { promise.then(function (data) {
expect(data).toEqual(null); expect(data).toEqual(null);
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets page labels', function (done) { it('gets page labels', function (done) {
// PageLabels with Roman/Arabic numerals. // PageLabels with Roman/Arabic numerals.
@ -657,9 +618,7 @@ describe('api', function() {
loadingTask2.destroy(), loadingTask2.destroy(),
loadingTask3.destroy() loadingTask3.destroy()
]).then(done); ]).then(done);
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets default page mode', function(done) { it('gets default page mode', function(done) {
@ -671,17 +630,13 @@ describe('api', function() {
expect(mode).toEqual('UseNone'); expect(mode).toEqual('UseNone');
loadingTask.destroy().then(done); loadingTask.destroy().then(done);
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets non-default page mode', function(done) { it('gets non-default page mode', function(done) {
doc.getPageMode().then(function(mode) { doc.getPageMode().then(function(mode) {
expect(mode).toEqual('UseOutlines'); expect(mode).toEqual('UseOutlines');
done(); done();
}).catch(function(reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets non-existent attachments', function(done) { it('gets non-existent attachments', function(done) {
@ -689,9 +644,7 @@ describe('api', function() {
promise.then(function (data) { promise.then(function (data) {
expect(data).toEqual(null); expect(data).toEqual(null);
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets attachments', function(done) { it('gets attachments', function(done) {
if (isNodeJS()) { // The PDF file used is a linked test-case. if (isNodeJS()) { // The PDF file used is a linked test-case.
@ -708,9 +661,7 @@ describe('api', function() {
expect(attachment.content.length).toEqual(30098); expect(attachment.content.length).toEqual(30098);
loadingTask.destroy().then(done); loadingTask.destroy().then(done);
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets javascript', function(done) { it('gets javascript', function(done) {
@ -718,9 +669,7 @@ describe('api', function() {
promise.then(function (data) { promise.then(function (data) {
expect(data).toEqual(null); expect(data).toEqual(null);
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
// Keep this in sync with the pattern in viewer.js. The pattern is used to // Keep this in sync with the pattern in viewer.js. The pattern is used to
// detect whether or not to automatically start printing. // detect whether or not to automatically start printing.
@ -736,9 +685,7 @@ describe('api', function() {
expect(data).toEqual(['print({});']); expect(data).toEqual(['print({});']);
expect(data[0]).toMatch(viewerPrintRegExp); expect(data[0]).toMatch(viewerPrintRegExp);
loadingTask.destroy().then(done); loadingTask.destroy().then(done);
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets javascript with printing instructions (JS action)', it('gets javascript with printing instructions (JS action)',
function(done) { function(done) {
@ -752,9 +699,7 @@ describe('api', function() {
['this.print({bUI:true,bSilent:false,bShrinkToFit:true});']); ['this.print({bUI:true,bSilent:false,bShrinkToFit:true});']);
expect(data[0]).toMatch(viewerPrintRegExp); expect(data[0]).toMatch(viewerPrintRegExp);
loadingTask.destroy().then(done); loadingTask.destroy().then(done);
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets non-existent outline', function(done) { it('gets non-existent outline', function(done) {
var loadingTask = getDocument(buildGetDocumentParams('tracemonkey.pdf')); var loadingTask = getDocument(buildGetDocumentParams('tracemonkey.pdf'));
@ -766,9 +711,7 @@ describe('api', function() {
expect(outline).toEqual(null); expect(outline).toEqual(null);
loadingTask.destroy().then(done); loadingTask.destroy().then(done);
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets outline', function(done) { it('gets outline', function(done) {
var promise = doc.getOutline(); var promise = doc.getOutline();
@ -791,9 +734,7 @@ describe('api', function() {
expect(outlineItem.items.length).toEqual(1); expect(outlineItem.items.length).toEqual(1);
expect(outlineItem.items[0].title).toEqual('Paragraph 1.1'); expect(outlineItem.items[0].title).toEqual('Paragraph 1.1');
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets outline containing a url', function(done) { it('gets outline containing a url', function(done) {
var loadingTask = getDocument(buildGetDocumentParams('issue3214.pdf')); var loadingTask = getDocument(buildGetDocumentParams('issue3214.pdf'));
@ -818,10 +759,61 @@ describe('api', function() {
loadingTask.destroy().then(done); loadingTask.destroy().then(done);
}); });
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
}); });
it('gets non-existent permissions', function(done) {
doc.getPermissions().then(function(permissions) {
expect(permissions).toEqual(null);
done();
}).catch(done.fail);
}); });
it('gets permissions', function (done) {
// Editing not allowed.
const loadingTask0 =
getDocument(buildGetDocumentParams('issue9972-1.pdf'));
const promise0 = loadingTask0.promise.then(function(pdfDocument) {
return pdfDocument.getPermissions();
});
// Printing not allowed.
const loadingTask1 =
getDocument(buildGetDocumentParams('issue9972-2.pdf'));
const promise1 = loadingTask1.promise.then(function(pdfDocument) {
return pdfDocument.getPermissions();
});
// Copying not allowed.
const loadingTask2 =
getDocument(buildGetDocumentParams('issue9972-3.pdf'));
const promise2 = loadingTask2.promise.then(function(pdfDocument) {
return pdfDocument.getPermissions();
});
const totalPermissionCount = Object.keys(PermissionFlag).length;
Promise.all([promise0, promise1, promise2]).then(function(permissions) {
expect(permissions[0].length).toEqual(totalPermissionCount - 1);
expect(permissions[0].includes(PermissionFlag.MODIFY_CONTENTS))
.toBeFalsy();
expect(permissions[1].length).toEqual(totalPermissionCount - 2);
expect(permissions[1].includes(PermissionFlag.PRINT)).toBeFalsy();
expect(permissions[1].includes(PermissionFlag.PRINT_HIGH_QUALITY))
.toBeFalsy();
expect(permissions[2].length).toEqual(totalPermissionCount - 1);
expect(permissions[2].includes(PermissionFlag.COPY)).toBeFalsy();
Promise.all([
loadingTask0.destroy(),
loadingTask1.destroy(),
loadingTask2.destroy(),
]).then(done);
}).catch(done.fail);
});
it('gets metadata', function(done) { it('gets metadata', function(done) {
var promise = doc.getMetadata(); var promise = doc.getMetadata();
promise.then(function({ info, metadata, contentDispositionFilename, }) { promise.then(function({ info, metadata, contentDispositionFilename, }) {
@ -837,9 +829,7 @@ describe('api', function() {
expect(contentDispositionFilename).toEqual(null); expect(contentDispositionFilename).toEqual(null);
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets data', function(done) { it('gets data', function(done) {
var promise = doc.getData(); var promise = doc.getData();
@ -847,27 +837,21 @@ describe('api', function() {
expect(data instanceof Uint8Array).toEqual(true); expect(data instanceof Uint8Array).toEqual(true);
expect(data.length).toEqual(basicApiFileLength); expect(data.length).toEqual(basicApiFileLength);
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets download info', function(done) { it('gets download info', function(done) {
var promise = doc.getDownloadInfo(); var promise = doc.getDownloadInfo();
promise.then(function (data) { promise.then(function (data) {
expect(data).toEqual({ length: basicApiFileLength, }); expect(data).toEqual({ length: basicApiFileLength, });
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets document stats', function(done) { it('gets document stats', function(done) {
var promise = doc.getStats(); var promise = doc.getStats();
promise.then(function (stats) { promise.then(function (stats) {
expect(stats).toEqual({ streamTypes: [], fontTypes: [], }); expect(stats).toEqual({ streamTypes: [], fontTypes: [], });
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('checks that fingerprints are unique', function(done) { it('checks that fingerprints are unique', function(done) {
@ -892,9 +876,7 @@ describe('api', function() {
loadingTask1.destroy(), loadingTask1.destroy(),
loadingTask2.destroy() loadingTask2.destroy()
]).then(done); ]).then(done);
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
describe('Cross-origin', function() { describe('Cross-origin', function() {
@ -988,9 +970,7 @@ describe('api', function() {
page = data; page = data;
done(); done();
}); });
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
afterAll(function(done) { afterAll(function(done) {
@ -1050,9 +1030,7 @@ describe('api', function() {
Promise.all([defaultPromise, displayPromise, printPromise]).then( Promise.all([defaultPromise, displayPromise, printPromise]).then(
function () { function () {
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets annotations containing relative URLs (bug 766086)', it('gets annotations containing relative URLs (bug 766086)',
@ -1112,9 +1090,7 @@ describe('api', function() {
docBaseUrlLoadingTask.destroy(), docBaseUrlLoadingTask.destroy(),
invalidDocBaseUrlLoadingTask.destroy() invalidDocBaseUrlLoadingTask.destroy()
]).then(done); ]).then(done);
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets text content', function (done) { it('gets text content', function (done) {
@ -1136,9 +1112,7 @@ describe('api', function() {
// A simple check that ensures the two `textContent` object match. // A simple check that ensures the two `textContent` object match.
expect(JSON.stringify(data[0])).toEqual(JSON.stringify(data[1])); expect(JSON.stringify(data[0])).toEqual(JSON.stringify(data[1]));
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets operator list', function(done) { it('gets operator list', function(done) {
var promise = page.getOperatorList(); var promise = page.getOperatorList();
@ -1147,9 +1121,7 @@ describe('api', function() {
expect(!!oplist.argsArray).toEqual(true); expect(!!oplist.argsArray).toEqual(true);
expect(oplist.lastChunk).toEqual(true); expect(oplist.lastChunk).toEqual(true);
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets operatorList with JPEG image (issue 4888)', function(done) { it('gets operatorList with JPEG image (issue 4888)', function(done) {
let loadingTask = getDocument(buildGetDocumentParams('cmykjpeg.pdf')); let loadingTask = getDocument(buildGetDocumentParams('cmykjpeg.pdf'));
@ -1166,9 +1138,7 @@ describe('api', function() {
done(); done();
}); });
}); });
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets document stats after parsing page', function(done) { it('gets document stats after parsing page', function(done) {
var promise = page.getOperatorList().then(function () { var promise = page.getOperatorList().then(function () {
@ -1184,9 +1154,7 @@ describe('api', function() {
expect(stats).toEqual({ streamTypes: expectedStreamTypes, expect(stats).toEqual({ streamTypes: expectedStreamTypes,
fontTypes: expectedFontTypes, }); fontTypes: expectedFontTypes, });
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('gets page stats after parsing page, without `pdfBug` set', it('gets page stats after parsing page, without `pdfBug` set',
@ -1420,9 +1388,7 @@ describe('api', function() {
}); });
promiseDone.then(function() { promiseDone.then(function() {
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
}); });
describe('PDFDataRangeTransport', function () { describe('PDFDataRangeTransport', function () {
@ -1479,9 +1445,7 @@ describe('api', function() {
expect(page.rotate).toEqual(0); expect(page.rotate).toEqual(0);
expect(fetches).toBeGreaterThan(2); expect(fetches).toBeGreaterThan(2);
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
it('should fetch document info and page using range and streaming', it('should fetch document info and page using range and streaming',
function (done) { function (done) {
@ -1520,9 +1484,7 @@ describe('api', function() {
expect(page.rotate).toEqual(0); expect(page.rotate).toEqual(0);
expect(fetches).toEqual(1); expect(fetches).toEqual(1);
done(); done();
}).catch(function (reason) { }).catch(done.fail);
done.fail(reason);
});
}); });
}); });
}); });