From c131715a2fb7253a50baffb514efa6ed9af01751 Mon Sep 17 00:00:00 2001 From: Tim de Koning Date: Tue, 26 Jun 2012 10:12:10 +0200 Subject: [PATCH 1/7] Make web workers debuggable! This way an error can be caught in the browser when the web worker throws an error. See http://www.nczonline.net/blog/2009/08/25/web-workers-errors-and-debugging/ --- src/worker.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/worker.js b/src/worker.js index c1dfa79af..161814f69 100644 --- a/src/worker.js +++ b/src/worker.js @@ -20,6 +20,10 @@ function MessageHandler(name, comObj) { warn(data); }]; + comObj.onerror = function(event){ + throw new Error(event.message + " (" + event.filename + ":" + event.lineno + ")"); + }; + comObj.onmessage = function messageHandlerComObjOnMessage(event) { var data = event.data; if (data.isReply) { From 0c33615301e6ccb024e897c9a08e4015a6f61ed6 Mon Sep 17 00:00:00 2001 From: Tim de Koning Date: Tue, 26 Jun 2012 23:07:37 +0200 Subject: [PATCH 2/7] Fixing web worker feature detection for Safari --- src/api.js | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/api.js b/src/api.js index 7d65f96b4..88cc6e288 100644 --- a/src/api.js +++ b/src/api.js @@ -18,7 +18,7 @@ * @return {Promise} A promise that is resolved with {PDFDocumentProxy} object. */ PDFJS.getDocument = function getDocument(source) { - var url, data, headers, password, parameters = {}; + var url, data, headers, password, parameters = {}, workerInitializedPromise, workerReadyPromise, transport; if (typeof source === 'string') { url = source; } else if (isArrayBuffer(source)) { @@ -37,8 +37,9 @@ PDFJS.getDocument = function getDocument(source) { 'string or a parameter object'); } - var promise = new PDFJS.Promise(); - var transport = new WorkerTransport(promise); + workerInitializedPromise = new PDFJS.Promise(); + workerReadyPromise = new PDFJS.Promise(); + transport = new WorkerTransport(workerInitializedPromise, workerReadyPromise); if (data) { // assuming the data is array, instantiating directly from it transport.sendData(data, parameters); @@ -49,23 +50,26 @@ PDFJS.getDocument = function getDocument(source) { url: url, progress: function getPDFProgress(evt) { if (evt.lengthComputable) - promise.progress({ + workerReadyPromise.progress({ loaded: evt.loaded, total: evt.total }); }, error: function getPDFError(e) { - promise.reject('Unexpected server response of ' + + workerReadyPromise.reject('Unexpected server response of ' + e.target.status + '.'); }, headers: headers }, function getPDFLoad(data) { - transport.sendData(data, parameters); + //we have to wait for the WorkerTransport to finalize worker-support detection! This may take a while... + workerInitializedPromise.then(function () { + transport.sendData(data, parameters); + }); }); } - return promise; + return workerReadyPromise; }; /** @@ -414,8 +418,8 @@ var PDFPageProxy = (function PDFPageProxyClosure() { * For internal use only. */ var WorkerTransport = (function WorkerTransportClosure() { - function WorkerTransport(promise) { - this.workerReadyPromise = promise; + function WorkerTransport(workerInitializedPromise, workerReadyPromise) { + this.workerReadyPromise = workerReadyPromise; this.objs = new PDFObjects(); this.pageCache = []; @@ -459,6 +463,7 @@ var WorkerTransport = (function WorkerTransportClosure() { globalScope.PDFJS.disableWorker = true; this.setupFakeWorker(); } + workerInitializedPromise.resolve(); }.bind(this)); var testObj = new Uint8Array(1); @@ -474,6 +479,7 @@ var WorkerTransport = (function WorkerTransportClosure() { // Thus, we fallback to a faked worker. globalScope.PDFJS.disableWorker = true; this.setupFakeWorker(); + workerInitializedPromise.resolve(); } WorkerTransport.prototype = { destroy: function WorkerTransport_destroy() { From 823db83b1989a07ff3640b8d9c837dd08997132a Mon Sep 17 00:00:00 2001 From: Tim de Koning Date: Wed, 27 Jun 2012 11:05:17 +0200 Subject: [PATCH 3/7] Fixed Safari / Iphone / Ipad support further --- web/compatibility.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/web/compatibility.js b/web/compatibility.js index 528841bb6..39580ef2a 100644 --- a/web/compatibility.js +++ b/web/compatibility.js @@ -6,6 +6,16 @@ // Checking if the typed arrays are supported (function checkTypedArrayCompatibility() { if (typeof Uint8Array !== 'undefined') { + // some mobile versions do not support subarray (e.g. safari 5 / iPhone / iPad) + if (typeof Uint8Array.prototype.subarray === 'undefined') { + Uint8Array.prototype.subarray = function subarray(start, end) { + return new Uint8Array(this.slice(start, end)); + } + Float32Array.prototype.subarray = function subarray(start, end) { + return new Float32Array(this.slice(start, end)); + } + } + // some mobile version might not support Float64Array if (typeof Float64Array === 'undefined') window.Float64Array = Float32Array; @@ -69,7 +79,8 @@ // Object.defineProperty() ? (function checkObjectDefinePropertyCompatibility() { - if (typeof Object.defineProperty !== 'undefined') + // safari 5 cannot use this on DOM objects and thus is unusable, see http://kangax.github.com/es5-compat-table/ + if ((typeof Object.defineProperty !== 'undefined') && /Safari\/5/.test(navigator.userAgent)) return; Object.defineProperty = function objectDefineProperty(obj, name, def) { From 17c1018eefec2c00b01106b80bf3897b2a005634 Mon Sep 17 00:00:00 2001 From: Tim de Koning Date: Wed, 27 Jun 2012 11:14:14 +0200 Subject: [PATCH 4/7] lint compliance --- src/api.js | 24 +++++++++++++++--------- src/worker.js | 4 ---- web/compatibility.js | 9 +++++---- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/api.js b/src/api.js index 88cc6e288..1d166f066 100644 --- a/src/api.js +++ b/src/api.js @@ -18,7 +18,9 @@ * @return {Promise} A promise that is resolved with {PDFDocumentProxy} object. */ PDFJS.getDocument = function getDocument(source) { - var url, data, headers, password, parameters = {}, workerInitializedPromise, workerReadyPromise, transport; + var url, data, headers, password, parameters = {}, workerInitializedPromise, + workerReadyPromise, transport; + if (typeof source === 'string') { url = source; } else if (isArrayBuffer(source)) { @@ -49,23 +51,27 @@ PDFJS.getDocument = function getDocument(source) { { url: url, progress: function getPDFProgress(evt) { - if (evt.lengthComputable) - workerReadyPromise.progress({ + if (evt.lengthComputable) { + workerReadyPromise.progress({ loaded: evt.loaded, total: evt.total }); + } }, error: function getPDFError(e) { - workerReadyPromise.reject('Unexpected server response of ' + + workerReadyPromise.reject('Unexpected server response of ' + e.target.status + '.'); }, headers: headers }, function getPDFLoad(data) { - //we have to wait for the WorkerTransport to finalize worker-support detection! This may take a while... - workerInitializedPromise.then(function () { - transport.sendData(data, parameters); - }); + // sometimes the pdf has finished downloading before the web worker-test + // has finished. In that case the rendering of the final pdf would cause + // errors. We have to wait for the WorkerTransport to finalize worker- + // support detection + workerInitializedPromise.then(function workerInitialized() { + transport.sendData(data, parameters); + }); }); } @@ -479,7 +485,7 @@ var WorkerTransport = (function WorkerTransportClosure() { // Thus, we fallback to a faked worker. globalScope.PDFJS.disableWorker = true; this.setupFakeWorker(); - workerInitializedPromise.resolve(); + workerInitializedPromise.resolve(); } WorkerTransport.prototype = { destroy: function WorkerTransport_destroy() { diff --git a/src/worker.js b/src/worker.js index 161814f69..c1dfa79af 100644 --- a/src/worker.js +++ b/src/worker.js @@ -20,10 +20,6 @@ function MessageHandler(name, comObj) { warn(data); }]; - comObj.onerror = function(event){ - throw new Error(event.message + " (" + event.filename + ":" + event.lineno + ")"); - }; - comObj.onmessage = function messageHandlerComObjOnMessage(event) { var data = event.data; if (data.isReply) { diff --git a/web/compatibility.js b/web/compatibility.js index 39580ef2a..ed4fae338 100644 --- a/web/compatibility.js +++ b/web/compatibility.js @@ -6,7 +6,7 @@ // Checking if the typed arrays are supported (function checkTypedArrayCompatibility() { if (typeof Uint8Array !== 'undefined') { - // some mobile versions do not support subarray (e.g. safari 5 / iPhone / iPad) + // some mobile versions do not support subarray (e.g. safari 5 / iOS) if (typeof Uint8Array.prototype.subarray === 'undefined') { Uint8Array.prototype.subarray = function subarray(start, end) { return new Uint8Array(this.slice(start, end)); @@ -79,9 +79,10 @@ // Object.defineProperty() ? (function checkObjectDefinePropertyCompatibility() { - // safari 5 cannot use this on DOM objects and thus is unusable, see http://kangax.github.com/es5-compat-table/ - if ((typeof Object.defineProperty !== 'undefined') && /Safari\/5/.test(navigator.userAgent)) - return; + // safari 5 cannot use this on DOM objects and thus is unusable, + // see http://kangax.github.com/es5-compat-table/ + if ((typeof Object.defineProperty !== 'undefined') && + /Safari\/5/.test(navigator.userAgent)) return; Object.defineProperty = function objectDefineProperty(obj, name, def) { delete obj[name]; From d70e6ab40c34d0ab737f11c65124a4d3b39df0df Mon Sep 17 00:00:00 2001 From: Tim de Koning Date: Wed, 27 Jun 2012 17:01:05 +0200 Subject: [PATCH 5/7] Bug, seen by @yurydelendik, thanx! --- web/compatibility.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/web/compatibility.js b/web/compatibility.js index ed4fae338..540dff0b1 100644 --- a/web/compatibility.js +++ b/web/compatibility.js @@ -79,10 +79,9 @@ // Object.defineProperty() ? (function checkObjectDefinePropertyCompatibility() { - // safari 5 cannot use this on DOM objects and thus is unusable, - // see http://kangax.github.com/es5-compat-table/ + // safari 5 and 6 cannot use this on DOM objects and thus it's unusable, if ((typeof Object.defineProperty !== 'undefined') && - /Safari\/5/.test(navigator.userAgent)) return; + !/Safari/.test(navigator.userAgent)) return; Object.defineProperty = function objectDefineProperty(obj, name, def) { delete obj[name]; From 44d0802700b92d3623bfdd9976099a974d8050c8 Mon Sep 17 00:00:00 2001 From: Tim de Koning Date: Wed, 27 Jun 2012 18:30:43 +0200 Subject: [PATCH 6/7] We should use feature detection. Thanks @brendandahl --- web/compatibility.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/web/compatibility.js b/web/compatibility.js index 540dff0b1..56a0ba43a 100644 --- a/web/compatibility.js +++ b/web/compatibility.js @@ -79,9 +79,16 @@ // Object.defineProperty() ? (function checkObjectDefinePropertyCompatibility() { - // safari 5 and 6 cannot use this on DOM objects and thus it's unusable, - if ((typeof Object.defineProperty !== 'undefined') && - !/Safari/.test(navigator.userAgent)) return; + if (typeof Object.defineProperty !== 'undefined') { + // Some browsers (e.g. safari) cannot use this on DOM objects + var definePropertyPossible = true; + try { + Object.defineProperty(new Image(), 'id', { value: 'test' }); + } catch (e) { + definePropertyPossible = false; + } + if (definePropertyPossible) return true; + } Object.defineProperty = function objectDefineProperty(obj, name, def) { delete obj[name]; From a30199527e1f2c83ce7e81d7cb8b3d5612fc38ad Mon Sep 17 00:00:00 2001 From: Tim de Koning Date: Wed, 27 Jun 2012 18:30:43 +0200 Subject: [PATCH 7/7] We should use feature detection. Thanks @brendandahl --- web/compatibility.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/web/compatibility.js b/web/compatibility.js index 540dff0b1..825dce647 100644 --- a/web/compatibility.js +++ b/web/compatibility.js @@ -10,10 +10,10 @@ if (typeof Uint8Array.prototype.subarray === 'undefined') { Uint8Array.prototype.subarray = function subarray(start, end) { return new Uint8Array(this.slice(start, end)); - } + }; Float32Array.prototype.subarray = function subarray(start, end) { return new Float32Array(this.slice(start, end)); - } + }; } // some mobile version might not support Float64Array @@ -79,9 +79,17 @@ // Object.defineProperty() ? (function checkObjectDefinePropertyCompatibility() { - // safari 5 and 6 cannot use this on DOM objects and thus it's unusable, - if ((typeof Object.defineProperty !== 'undefined') && - !/Safari/.test(navigator.userAgent)) return; + if (typeof Object.defineProperty !== 'undefined') { + // some browsers (e.g. safari) cannot use defineProperty() on DOM objects + // and thus the native version is not sufficient + var definePropertyPossible = true; + try { + Object.defineProperty(new Image(), 'id', { value: 'test' }); + } catch (e) { + definePropertyPossible = false; + } + if (definePropertyPossible) return; + } Object.defineProperty = function objectDefineProperty(obj, name, def) { delete obj[name];