Adds peer communication between MessageHandlers.
This commit is contained in:
parent
4b243cdd89
commit
acdd49f480
@ -51,12 +51,49 @@ var WorkerTask = (function WorkerTaskClosure() {
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
|
var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
|
||||||
setup: function wphSetup(handler) {
|
setup: function wphSetup(handler, port) {
|
||||||
|
handler.on('test', function wphSetupTest(data) {
|
||||||
|
// check if Uint8Array can be sent to worker
|
||||||
|
if (!(data instanceof Uint8Array)) {
|
||||||
|
handler.send('test', 'main', false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// making sure postMessage transfers are working
|
||||||
|
var supportTransfers = data[0] === 255;
|
||||||
|
handler.postMessageTransfers = supportTransfers;
|
||||||
|
// check if the response property is supported by xhr
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
var responseExists = 'response' in xhr;
|
||||||
|
// check if the property is actually implemented
|
||||||
|
try {
|
||||||
|
var dummy = xhr.responseType;
|
||||||
|
} catch (e) {
|
||||||
|
responseExists = false;
|
||||||
|
}
|
||||||
|
if (!responseExists) {
|
||||||
|
handler.send('test', false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handler.send('test', {
|
||||||
|
supportTypedArray: true,
|
||||||
|
supportTransfers: supportTransfers
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
handler.on('GetDocRequest', function wphSetupDoc(data) {
|
||||||
|
return WorkerMessageHandler.createDocumentHandler(data, port);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
createDocumentHandler: function wphCreateDocumentHandler(data, port) {
|
||||||
var pdfManager;
|
var pdfManager;
|
||||||
var terminated = false;
|
var terminated = false;
|
||||||
var cancelXHRs = null;
|
var cancelXHRs = null;
|
||||||
var WorkerTasks = [];
|
var WorkerTasks = [];
|
||||||
|
|
||||||
|
var mainHandlerName = data.docId;
|
||||||
|
var workerHandlerName = data.docId + '_worker';
|
||||||
|
var handler = new MessageHandler(workerHandlerName, mainHandlerName, port);
|
||||||
|
|
||||||
function ensureNotTerminated() {
|
function ensureNotTerminated() {
|
||||||
if (terminated) {
|
if (terminated) {
|
||||||
throw new Error('Worker was terminated');
|
throw new Error('Worker was terminated');
|
||||||
@ -262,35 +299,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
|
|||||||
return pdfManagerCapability.promise;
|
return pdfManagerCapability.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
handler.on('test', function wphSetupTest(data) {
|
var setupDoc = function(data) {
|
||||||
// check if Uint8Array can be sent to worker
|
|
||||||
if (!(data instanceof Uint8Array)) {
|
|
||||||
handler.send('test', false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// making sure postMessage transfers are working
|
|
||||||
var supportTransfers = data[0] === 255;
|
|
||||||
handler.postMessageTransfers = supportTransfers;
|
|
||||||
// check if the response property is supported by xhr
|
|
||||||
var xhr = new XMLHttpRequest();
|
|
||||||
var responseExists = 'response' in xhr;
|
|
||||||
// check if the property is actually implemented
|
|
||||||
try {
|
|
||||||
var dummy = xhr.responseType;
|
|
||||||
} catch (e) {
|
|
||||||
responseExists = false;
|
|
||||||
}
|
|
||||||
if (!responseExists) {
|
|
||||||
handler.send('test', false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
handler.send('test', {
|
|
||||||
supportTypedArray: true,
|
|
||||||
supportTransfers: supportTransfers
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
handler.on('GetDocRequest', function wphSetupDoc(data) {
|
|
||||||
var onSuccess = function(doc) {
|
var onSuccess = function(doc) {
|
||||||
ensureNotTerminated();
|
ensureNotTerminated();
|
||||||
handler.send('GetDoc', { pdfInfo: doc });
|
handler.send('GetDoc', { pdfInfo: doc });
|
||||||
@ -366,7 +375,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
|
|||||||
});
|
});
|
||||||
}, onFailure);
|
}, onFailure);
|
||||||
}, onFailure);
|
}, onFailure);
|
||||||
});
|
};
|
||||||
|
|
||||||
handler.on('GetPage', function wphSetupGetPage(data) {
|
handler.on('GetPage', function wphSetupGetPage(data) {
|
||||||
return pdfManager.getPage(data.pageIndex).then(function(page) {
|
return pdfManager.getPage(data.pageIndex).then(function(page) {
|
||||||
@ -548,6 +557,9 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
|
|||||||
|
|
||||||
return Promise.all(waitOn).then(function () {});
|
return Promise.all(waitOn).then(function () {});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
setupDoc(data);
|
||||||
|
return workerHandlerName;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -557,6 +569,7 @@ var workerConsole = {
|
|||||||
log: function log() {
|
log: function log() {
|
||||||
var args = Array.prototype.slice.call(arguments);
|
var args = Array.prototype.slice.call(arguments);
|
||||||
globalScope.postMessage({
|
globalScope.postMessage({
|
||||||
|
targetName: 'main',
|
||||||
action: 'console_log',
|
action: 'console_log',
|
||||||
data: args
|
data: args
|
||||||
});
|
});
|
||||||
@ -565,6 +578,7 @@ var workerConsole = {
|
|||||||
error: function error() {
|
error: function error() {
|
||||||
var args = Array.prototype.slice.call(arguments);
|
var args = Array.prototype.slice.call(arguments);
|
||||||
globalScope.postMessage({
|
globalScope.postMessage({
|
||||||
|
targetName: 'main',
|
||||||
action: 'console_error',
|
action: 'console_error',
|
||||||
data: args
|
data: args
|
||||||
});
|
});
|
||||||
@ -594,11 +608,12 @@ if (typeof window === 'undefined') {
|
|||||||
// Listen for unsupported features so we can pass them on to the main thread.
|
// Listen for unsupported features so we can pass them on to the main thread.
|
||||||
PDFJS.UnsupportedManager.listen(function (msg) {
|
PDFJS.UnsupportedManager.listen(function (msg) {
|
||||||
globalScope.postMessage({
|
globalScope.postMessage({
|
||||||
|
targetName: 'main',
|
||||||
action: '_unsupported_feature',
|
action: '_unsupported_feature',
|
||||||
data: msg
|
data: msg
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
var handler = new MessageHandler('worker_processor', this);
|
var handler = new MessageHandler('worker', 'main', this);
|
||||||
WorkerMessageHandler.setup(handler);
|
WorkerMessageHandler.setup(handler, this);
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
Promise, PasswordResponses, PasswordException, InvalidPDFException,
|
Promise, PasswordResponses, PasswordException, InvalidPDFException,
|
||||||
MissingPDFException, UnknownErrorException, FontFaceObject,
|
MissingPDFException, UnknownErrorException, FontFaceObject,
|
||||||
loadJpegStream, createScratchCanvas, CanvasGraphics, stringToBytes,
|
loadJpegStream, createScratchCanvas, CanvasGraphics, stringToBytes,
|
||||||
UnexpectedResponseException, deprecated */
|
UnexpectedResponseException, deprecated, UnsupportedManager */
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@ -353,6 +353,12 @@ var PDFDocumentLoadingTask = (function PDFDocumentLoadingTaskClosure() {
|
|||||||
this._capability = createPromiseCapability();
|
this._capability = createPromiseCapability();
|
||||||
this._transport = null;
|
this._transport = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows if loading task is destroyed.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
this.destroyed = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback to request a password if wrong or no password was provided.
|
* Callback to request a password if wrong or no password was provided.
|
||||||
* The callback receives two parameters: function that needs to be called
|
* The callback receives two parameters: function that needs to be called
|
||||||
@ -383,6 +389,10 @@ var PDFDocumentLoadingTask = (function PDFDocumentLoadingTaskClosure() {
|
|||||||
* is completed.
|
* is completed.
|
||||||
*/
|
*/
|
||||||
destroy: function () {
|
destroy: function () {
|
||||||
|
this.destroyed = true;
|
||||||
|
if (!this._transport) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
return this._transport.destroy();
|
return this._transport.destroy();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1042,8 +1052,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
|
|||||||
// Some versions of FF can't create a worker on localhost, see:
|
// Some versions of FF can't create a worker on localhost, see:
|
||||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=683280
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=683280
|
||||||
var worker = new Worker(workerSrc);
|
var worker = new Worker(workerSrc);
|
||||||
var messageHandler = new MessageHandler('main', worker);
|
var messageHandler = new MessageHandler('main', 'worker', worker);
|
||||||
this.messageHandler = messageHandler;
|
|
||||||
|
|
||||||
messageHandler.on('test', function transportTest(data) {
|
messageHandler.on('test', function transportTest(data) {
|
||||||
var supportTypedArray = data && data.supportTypedArray;
|
var supportTypedArray = data && data.supportTypedArray;
|
||||||
@ -1052,13 +1061,23 @@ var WorkerTransport = (function WorkerTransportClosure() {
|
|||||||
if (!data.supportTransfers) {
|
if (!data.supportTransfers) {
|
||||||
PDFJS.postMessageTransfers = false;
|
PDFJS.postMessageTransfers = false;
|
||||||
}
|
}
|
||||||
this.setupMessageHandler(messageHandler);
|
this.setupMainMessageHandler(messageHandler, worker);
|
||||||
workerInitializedCapability.resolve();
|
workerInitializedCapability.resolve();
|
||||||
} else {
|
} else {
|
||||||
this.setupFakeWorker();
|
this.setupFakeWorker();
|
||||||
}
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
|
messageHandler.on('console_log', function (data) {
|
||||||
|
console.log.apply(console, data);
|
||||||
|
});
|
||||||
|
messageHandler.on('console_error', function (data) {
|
||||||
|
console.error.apply(console, data);
|
||||||
|
});
|
||||||
|
messageHandler.on('_unsupported_feature', function (data) {
|
||||||
|
UnsupportedManager.notify(data);
|
||||||
|
});
|
||||||
|
|
||||||
var testObj = new Uint8Array([PDFJS.postMessageTransfers ? 255 : 0]);
|
var testObj = new Uint8Array([PDFJS.postMessageTransfers ? 255 : 0]);
|
||||||
// Some versions of Opera throw a DATA_CLONE_ERR on serializing the
|
// Some versions of Opera throw a DATA_CLONE_ERR on serializing the
|
||||||
// typed array. Also, checking if we can use transfers.
|
// typed array. Also, checking if we can use transfers.
|
||||||
@ -1141,23 +1160,41 @@ var WorkerTransport = (function WorkerTransportClosure() {
|
|||||||
warn('Setting up fake worker.');
|
warn('Setting up fake worker.');
|
||||||
// If we don't use a worker, just post/sendMessage to the main thread.
|
// If we don't use a worker, just post/sendMessage to the main thread.
|
||||||
var fakeWorker = {
|
var fakeWorker = {
|
||||||
|
_listeners: [],
|
||||||
postMessage: function WorkerTransport_postMessage(obj) {
|
postMessage: function WorkerTransport_postMessage(obj) {
|
||||||
fakeWorker.onmessage({data: obj});
|
var e = {data: obj};
|
||||||
|
this._listeners.forEach(function (listener) {
|
||||||
|
listener.call(this, e);
|
||||||
|
}, this);
|
||||||
|
},
|
||||||
|
addEventListener: function (name, listener) {
|
||||||
|
this._listeners.push(listener);
|
||||||
|
},
|
||||||
|
removeEventListener: function (name, listener) {
|
||||||
|
var i = this._listeners.indexOf(listener);
|
||||||
|
this._listeners.splice(i, 1);
|
||||||
},
|
},
|
||||||
terminate: function WorkerTransport_terminate() {}
|
terminate: function WorkerTransport_terminate() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
var messageHandler = new MessageHandler('main', fakeWorker);
|
var messageHandler = new MessageHandler('main', 'worker', fakeWorker);
|
||||||
this.setupMessageHandler(messageHandler);
|
this.setupMainMessageHandler(messageHandler, fakeWorker);
|
||||||
|
|
||||||
// If the main thread is our worker, setup the handling for the messages
|
// If the main thread is our worker, setup the handling for the messages
|
||||||
// the main thread sends to it self.
|
// the main thread sends to it self.
|
||||||
PDFJS.WorkerMessageHandler.setup(messageHandler);
|
var workerHandler = new MessageHandler('worker', 'main', fakeWorker);
|
||||||
|
PDFJS.WorkerMessageHandler.setup(workerHandler, fakeWorker);
|
||||||
|
|
||||||
this.workerInitializedCapability.resolve();
|
this.workerInitializedCapability.resolve();
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setupMainMessageHandler:
|
||||||
|
function WorkerTransport_setupMainMessageHandler(messageHandler, port) {
|
||||||
|
this.mainMessageHandler = messageHandler;
|
||||||
|
this.port = port;
|
||||||
|
},
|
||||||
|
|
||||||
setupMessageHandler:
|
setupMessageHandler:
|
||||||
function WorkerTransport_setupMessageHandler(messageHandler) {
|
function WorkerTransport_setupMessageHandler(messageHandler) {
|
||||||
this.messageHandler = messageHandler;
|
this.messageHandler = messageHandler;
|
||||||
@ -1441,7 +1478,9 @@ var WorkerTransport = (function WorkerTransportClosure() {
|
|||||||
source.length = this.pdfDataRangeTransport.length;
|
source.length = this.pdfDataRangeTransport.length;
|
||||||
source.initialData = this.pdfDataRangeTransport.initialData;
|
source.initialData = this.pdfDataRangeTransport.initialData;
|
||||||
}
|
}
|
||||||
this.messageHandler.send('GetDocRequest', {
|
var docId = 'doc';
|
||||||
|
this.mainMessageHandler.sendWithPromise('GetDocRequest', {
|
||||||
|
docId: docId,
|
||||||
source: source,
|
source: source,
|
||||||
disableRange: PDFJS.disableRange,
|
disableRange: PDFJS.disableRange,
|
||||||
maxImageSize: PDFJS.maxImageSize,
|
maxImageSize: PDFJS.maxImageSize,
|
||||||
@ -1450,7 +1489,16 @@ var WorkerTransport = (function WorkerTransportClosure() {
|
|||||||
disableFontFace: PDFJS.disableFontFace,
|
disableFontFace: PDFJS.disableFontFace,
|
||||||
disableCreateObjectURL: PDFJS.disableCreateObjectURL,
|
disableCreateObjectURL: PDFJS.disableCreateObjectURL,
|
||||||
verbosity: PDFJS.verbosity
|
verbosity: PDFJS.verbosity
|
||||||
});
|
}).then(function (workerId) {
|
||||||
|
if (this.destroyed) {
|
||||||
|
loadingTask._capability.reject(new Error('Loading aborted'));
|
||||||
|
this.destroyCapability.resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var messageHandler = new MessageHandler(docId, workerId, this.port);
|
||||||
|
this.setupMessageHandler(messageHandler);
|
||||||
|
}.bind(this), loadingTask._capability.reject);
|
||||||
},
|
},
|
||||||
|
|
||||||
getData: function WorkerTransport_getData() {
|
getData: function WorkerTransport_getData() {
|
||||||
|
@ -1518,26 +1518,20 @@ PDFJS.createObjectURL = (function createObjectURLClosure() {
|
|||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
function MessageHandler(name, comObj) {
|
function MessageHandler(sourceName, targetName, comObj) {
|
||||||
this.name = name;
|
this.sourceName = sourceName;
|
||||||
|
this.targetName = targetName;
|
||||||
this.comObj = comObj;
|
this.comObj = comObj;
|
||||||
this.callbackIndex = 1;
|
this.callbackIndex = 1;
|
||||||
this.postMessageTransfers = true;
|
this.postMessageTransfers = true;
|
||||||
var callbacksCapabilities = this.callbacksCapabilities = {};
|
var callbacksCapabilities = this.callbacksCapabilities = {};
|
||||||
var ah = this.actionHandler = {};
|
var ah = this.actionHandler = {};
|
||||||
|
|
||||||
ah['console_log'] = [function ahConsoleLog(data) {
|
this._onComObjOnMessage = function messageHandlerComObjOnMessage(event) {
|
||||||
console.log.apply(console, data);
|
|
||||||
}];
|
|
||||||
ah['console_error'] = [function ahConsoleError(data) {
|
|
||||||
console.error.apply(console, data);
|
|
||||||
}];
|
|
||||||
ah['_unsupported_feature'] = [function ah_unsupportedFeature(data) {
|
|
||||||
UnsupportedManager.notify(data);
|
|
||||||
}];
|
|
||||||
|
|
||||||
comObj.onmessage = function messageHandlerComObjOnMessage(event) {
|
|
||||||
var data = event.data;
|
var data = event.data;
|
||||||
|
if (data.targetName !== this.sourceName) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (data.isReply) {
|
if (data.isReply) {
|
||||||
var callbackId = data.callbackId;
|
var callbackId = data.callbackId;
|
||||||
if (data.callbackId in callbacksCapabilities) {
|
if (data.callbackId in callbacksCapabilities) {
|
||||||
@ -1554,10 +1548,14 @@ function MessageHandler(name, comObj) {
|
|||||||
} else if (data.action in ah) {
|
} else if (data.action in ah) {
|
||||||
var action = ah[data.action];
|
var action = ah[data.action];
|
||||||
if (data.callbackId) {
|
if (data.callbackId) {
|
||||||
|
var sourceName = this.sourceName;
|
||||||
|
var targetName = data.sourceName;
|
||||||
Promise.resolve().then(function () {
|
Promise.resolve().then(function () {
|
||||||
return action[0].call(action[1], data.data);
|
return action[0].call(action[1], data.data);
|
||||||
}).then(function (result) {
|
}).then(function (result) {
|
||||||
comObj.postMessage({
|
comObj.postMessage({
|
||||||
|
sourceName: sourceName,
|
||||||
|
targetName: targetName,
|
||||||
isReply: true,
|
isReply: true,
|
||||||
callbackId: data.callbackId,
|
callbackId: data.callbackId,
|
||||||
data: result
|
data: result
|
||||||
@ -1568,6 +1566,8 @@ function MessageHandler(name, comObj) {
|
|||||||
reason = reason + '';
|
reason = reason + '';
|
||||||
}
|
}
|
||||||
comObj.postMessage({
|
comObj.postMessage({
|
||||||
|
sourceName: sourceName,
|
||||||
|
targetName: targetName,
|
||||||
isReply: true,
|
isReply: true,
|
||||||
callbackId: data.callbackId,
|
callbackId: data.callbackId,
|
||||||
error: reason
|
error: reason
|
||||||
@ -1579,7 +1579,8 @@ function MessageHandler(name, comObj) {
|
|||||||
} else {
|
} else {
|
||||||
error('Unknown action from worker: ' + data.action);
|
error('Unknown action from worker: ' + data.action);
|
||||||
}
|
}
|
||||||
};
|
}.bind(this);
|
||||||
|
comObj.addEventListener('message', this._onComObjOnMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageHandler.prototype = {
|
MessageHandler.prototype = {
|
||||||
@ -1598,6 +1599,8 @@ MessageHandler.prototype = {
|
|||||||
*/
|
*/
|
||||||
send: function messageHandlerSend(actionName, data, transfers) {
|
send: function messageHandlerSend(actionName, data, transfers) {
|
||||||
var message = {
|
var message = {
|
||||||
|
sourceName: this.sourceName,
|
||||||
|
targetName: this.targetName,
|
||||||
action: actionName,
|
action: actionName,
|
||||||
data: data
|
data: data
|
||||||
};
|
};
|
||||||
@ -1615,6 +1618,8 @@ MessageHandler.prototype = {
|
|||||||
function messageHandlerSendWithPromise(actionName, data, transfers) {
|
function messageHandlerSendWithPromise(actionName, data, transfers) {
|
||||||
var callbackId = this.callbackIndex++;
|
var callbackId = this.callbackIndex++;
|
||||||
var message = {
|
var message = {
|
||||||
|
sourceName: this.sourceName,
|
||||||
|
targetName: this.targetName,
|
||||||
action: actionName,
|
action: actionName,
|
||||||
data: data,
|
data: data,
|
||||||
callbackId: callbackId
|
callbackId: callbackId
|
||||||
@ -1640,6 +1645,10 @@ MessageHandler.prototype = {
|
|||||||
} else {
|
} else {
|
||||||
this.comObj.postMessage(message);
|
this.comObj.postMessage(message);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function () {
|
||||||
|
this.comObj.removeEventListener('message', this._onComObjOnMessage);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user