Skip to content

Commit

Permalink
Uses postMessage transfers
Browse files Browse the repository at this point in the history
  • Loading branch information
yurydelendik authored and Yury committed Nov 14, 2013
1 parent 945e370 commit 4ce6cb8
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 12 deletions.
27 changes: 23 additions & 4 deletions src/core/evaluator.js
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {

PDFImage.buildImage(function(imageObj) {
var imgData = imageObj.getImageData();
self.handler.send('obj', [objId, self.pageIndex, 'Image', imgData]);
self.handler.send('obj', [objId, self.pageIndex, 'Image', imgData],
null, [imgData.data.buffer]);
}, self.handler, self.xref, resources, image, inline);

operatorList.addOp(OPS.paintImageXObject, args);
Expand Down Expand Up @@ -1457,14 +1458,30 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}
};


return PartialEvaluator;
})();

var OperatorList = (function OperatorListClosure() {
var CHUNK_SIZE = 100;

function OperatorList(messageHandler, pageIndex) {
function getTransfers(queue) {
var transfers = [];
var fnArray = queue.fnArray, argsArray = queue.argsArray;
for (var i = 0, ii = queue.length; i < ii; i++) {
switch (fnArray[i]) {
case OPS.paintInlineImageXObject:
case OPS.paintInlineImageXObjectGroup:
case OPS.paintImageMaskXObject:
var arg = argsArray[i][0]; // first param in imgData
transfers.push(arg.data.buffer);
break;
}
}
return transfers;
}


function OperatorList(messageHandler, pageIndex) {
this.messageHandler = messageHandler;
// When there isn't a message handler the fn array needs to be able to grow
// since we can't flush the operators.
Expand Down Expand Up @@ -1529,6 +1546,7 @@ var OperatorList = (function OperatorListClosure() {

flush: function(lastChunk) {
PartialEvaluator.optimizeQueue(this);
var transfers = getTransfers(this);
this.messageHandler.send('RenderPageChunk', {
operatorList: {
fnArray: this.fnArray,
Expand All @@ -1537,7 +1555,7 @@ var OperatorList = (function OperatorListClosure() {
length: this.length
},
pageIndex: this.pageIndex
});
}, null, transfers);
this.dependencies = [];
this.fnIndex = 0;
this.argsArray = [];
Expand All @@ -1546,6 +1564,7 @@ var OperatorList = (function OperatorListClosure() {

return OperatorList;
})();

var TextState = (function TextStateClosure() {
function TextState() {
this.fontSize = 0;
Expand Down
8 changes: 7 additions & 1 deletion src/core/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
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;
Expand All @@ -186,7 +189,10 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
handler.send('test', false);
return;
}
handler.send('test', true);
handler.send('test', {
supportTypedArray: true,
supportTransfers: supportTransfers
});
});

handler.on('GetDocRequest', function wphSetupDoc(data) {
Expand Down
26 changes: 21 additions & 5 deletions src/display/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ PDFJS.disableAutoFetch = PDFJS.disableAutoFetch === undefined ?
*/
PDFJS.pdfBug = PDFJS.pdfBug === undefined ? false : PDFJS.pdfBug;

/**
* Enables transfer usage in postMessage for ArrayBuffers.
* @var {boolean}
*/
PDFJS.postMessageTransfers = PDFJS.postMessageTransfers === undefined ?
true : PDFJS.postMessageTransfers;
/**
* This is the main entry point for loading a PDF and interacting with it.
* NOTE: If a URL is used to fetch the PDF data a standard XMLHttpRequest(XHR)
Expand Down Expand Up @@ -544,9 +550,13 @@ var WorkerTransport = (function WorkerTransportClosure() {
var messageHandler = new MessageHandler('main', worker);
this.messageHandler = messageHandler;

messageHandler.on('test', function transportTest(supportTypedArray) {
messageHandler.on('test', function transportTest(data) {
var supportTypedArray = data && data.supportTypedArray;
if (supportTypedArray) {
this.worker = worker;
if (!data.supportTransfers) {
PDFJS.postMessageTransfers = false;
}
this.setupMessageHandler(messageHandler);
workerInitializedPromise.resolve();
} else {
Expand All @@ -558,10 +568,16 @@ var WorkerTransport = (function WorkerTransportClosure() {
}
}.bind(this));

var testObj = new Uint8Array(1);
// Some versions of Opera throw a DATA_CLONE_ERR on
// serializing the typed array.
messageHandler.send('test', testObj);
var testObj = new Uint8Array([PDFJS.postMessageTransfers ? 255 : 0]);
// Some versions of Opera throw a DATA_CLONE_ERR on serializing the
// typed array. Also, checking if we can use transfers.
try {
messageHandler.send('test', testObj, null, [testObj.buffer]);
} catch (ex) {
info('Cannot use postMessage transfers');
testObj[0] = 0;
messageHandler.send('test', testObj);
}
return;
} catch (e) {
info('The worker has been disabled.');
Expand Down
10 changes: 8 additions & 2 deletions src/shared/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -1104,6 +1104,7 @@ function MessageHandler(name, comObj) {
this.name = name;
this.comObj = comObj;
this.callbackIndex = 1;
this.postMessageTransfers = true;
var callbacks = this.callbacks = {};
var ah = this.actionHandler = {};

Expand Down Expand Up @@ -1170,8 +1171,9 @@ MessageHandler.prototype = {
* @param {String} actionName Action to call.
* @param {JSON} data JSON data to send.
* @param {function} [callback] Optional callback that will handle a reply.
* @param {Array} [transfers] Optional list of transfers/ArrayBuffers
*/
send: function messageHandlerSend(actionName, data, callback) {
send: function messageHandlerSend(actionName, data, callback, transfers) {
var message = {
action: actionName,
data: data
Expand All @@ -1181,7 +1183,11 @@ MessageHandler.prototype = {
this.callbacks[callbackId] = callback;
message.callbackId = callbackId;
}
this.comObj.postMessage(message);
if (transfers && this.postMessageTransfers) {
this.comObj.postMessage(message, transfers);
} else {
this.comObj.postMessage(message);
}
}
};

Expand Down
33 changes: 33 additions & 0 deletions test/features/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,39 @@ var tests = [
impact: 'Important',
area: 'Core'
},
{
id: 'Worker-transfers',
name: 'Worker can use transfers for postMessage',
run: function () {
if (typeof Worker == 'undefined')
return { output: 'Skipped', emulated: '' };

try {
var worker = new Worker('worker-stub.js');

var promise = new Promise();
var timeout = setTimeout(function () {
promise.resolve({ output: 'Failed', emulated: '?' });
}, 5000);

worker.addEventListener('message', function (e) {
var data = e.data;
if (data.action == 'test-transfers' && data.result)
promise.resolve({ output: 'Success', emulated: '' });
else
promise.resolve({ output: 'Failed', emulated: 'Yes' });
}, false);
var testObj = new Uint8Array([255]);
worker.postMessage({action: 'test-transfers',
data: testObj}, [testObj.buffer]);
return promise;
} catch (e) {
return { output: 'Failed', emulated: 'Yes' };
}
},
impact: 'Normal',
area: 'Core'
},
{
id: 'Worker-xhr-response',
name: 'XMLHttpRequest supports the reponse property in web workers',
Expand Down
3 changes: 3 additions & 0 deletions test/features/worker-stub.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ onmessage = function (e) {
case 'test':
postMessage({action: 'test', result: data.data instanceof Uint8Array});
break;
case 'test-transfers':
postMessage({action: 'test-transfers', result: data.data[0] === 255});
break;
case 'xhr':
var xhr = new XMLHttpRequest();
var responseExists = 'response' in xhr;
Expand Down

0 comments on commit 4ce6cb8

Please sign in to comment.