diff --git a/extensions/firefox/components/PdfStreamConverter.js b/extensions/firefox/components/PdfStreamConverter.js index 57647d67e..9f5cc6bee 100644 --- a/extensions/firefox/components/PdfStreamConverter.js +++ b/extensions/firefox/components/PdfStreamConverter.js @@ -138,7 +138,7 @@ ChromeActions.prototype = { self.download(url); } }, { - label: mozL10n.get('disable_pdfjs', null, + label: mozL10n.get('disable_viewer', null, 'Disable Mozilla PDF Viewer'), accessKey: null, callback: function() { diff --git a/src/api.js b/src/api.js index bbab680ce..0e76a17ae 100644 --- a/src/api.js +++ b/src/api.js @@ -420,7 +420,7 @@ var WorkerTransport = (function WorkerTransportClosure() { messageHandler.send('test', testObj); return; } catch (e) { - warn('The worker has been disabled.'); + info('The worker has been disabled.'); } } // Either workers are disabled, not supported or have thrown an exception. diff --git a/src/canvas.js b/src/canvas.js index 9d470fbec..85e82aaa5 100644 --- a/src/canvas.js +++ b/src/canvas.js @@ -343,10 +343,13 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { this.ctx.webkitLineDashOffset = dashPhase; }, setRenderingIntent: function CanvasGraphics_setRenderingIntent(intent) { - TODO('set rendering intent: ' + intent); + // Maybe if we one day fully support color spaces this will be important + // for now we can ignore. + // TODO set rendering intent? }, setFlatness: function CanvasGraphics_setFlatness(flatness) { - TODO('set flatness: ' + flatness); + // There's no way to control this with canvas, but we can safely ignore. + // TODO set flatness? }, setGState: function CanvasGraphics_setGState(states) { for (var i = 0, ii = states.length; i < ii; i++) { @@ -841,7 +844,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { text.length += shownText.length; } } else { - malformed('TJ array element ' + e + ' is not string or num'); + error('TJ array element ' + e + ' is not string or num'); } } diff --git a/src/colorspace.js b/src/colorspace.js index 8d8290109..26e7c1f0f 100644 --- a/src/colorspace.js +++ b/src/colorspace.js @@ -451,12 +451,12 @@ var LabCS = (function LabCSClosure() { error('Invalid WhitePoint components, no fallback available'); if (this.XB < 0 || this.YB < 0 || this.ZB < 0) { - warn('Invalid BlackPoint, falling back to default'); + info('Invalid BlackPoint, falling back to default'); this.XB = this.YB = this.ZB = 0; } if (this.amin > this.amax || this.bmin > this.bmax) { - warn('Invalid Range, falling back to defaults'); + info('Invalid Range, falling back to defaults'); this.amin = -100; this.amax = 100; this.bmin = -100; diff --git a/src/core.js b/src/core.js index 6a5ec275c..13e14c702 100644 --- a/src/core.js +++ b/src/core.js @@ -7,7 +7,7 @@ var globalScope = (typeof window === 'undefined') ? this : window; var isWorker = (typeof window == 'undefined'); -var ERRORS = 0, WARNINGS = 1, TODOS = 5; +var ERRORS = 0, WARNINGS = 1, INFOS = 5; var verbosity = WARNINGS; // The global PDFJS object exposes the API diff --git a/src/evaluator.js b/src/evaluator.js index 23c9d1f65..d2ca8cfdb 100644 --- a/src/evaluator.js +++ b/src/evaluator.js @@ -453,7 +453,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { TODO('graphic state operator ' + key); break; default: - warn('Unknown graphic state operator ' + key); + info('Unknown graphic state operator ' + key); break; } } diff --git a/src/fonts.js b/src/fonts.js index 22037e724..b64ecefac 100644 --- a/src/fonts.js +++ b/src/fonts.js @@ -3633,7 +3633,7 @@ var CFFParser = (function CFFParserClosure() { ++offset; if (offset != 0) { - warn('cff data is shifted'); + info('cff data is shifted'); bytes = bytes.subarray(offset); this.bytes = bytes; } diff --git a/src/stream.js b/src/stream.js index 48c462fb2..b0e1beb34 100644 --- a/src/stream.js +++ b/src/stream.js @@ -1687,7 +1687,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() { if (a1 > codingLine[codingPos]) { if (a1 > this.columns) { - warn('row is wrong length'); + info('row is wrong length'); this.err = true; a1 = this.columns; } @@ -1707,7 +1707,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() { if (a1 > codingLine[codingPos]) { if (a1 > this.columns) { - warn('row is wrong length'); + info('row is wrong length'); this.err = true; a1 = this.columns; } @@ -1717,7 +1717,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() { codingLine[codingPos] = a1; } else if (a1 < codingLine[codingPos]) { if (a1 < 0) { - warn('invalid code'); + info('invalid code'); this.err = true; a1 = 0; } @@ -1879,7 +1879,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() { this.eof = true; break; default: - warn('bad 2d code'); + info('bad 2d code'); this.addPixels(columns, 0); this.err = true; } @@ -1942,7 +1942,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() { for (var i = 0; i < 4; ++i) { code1 = this.lookBits(12); if (code1 != 1) - warn('bad rtc code: ' + code1); + info('bad rtc code: ' + code1); this.eatBits(12); if (this.encoding > 0) { this.lookBits(1); @@ -2065,7 +2065,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() { if (result[0] && result[2]) return result[1]; } - warn('Bad two dim code'); + info('Bad two dim code'); return EOF; }; @@ -2098,7 +2098,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() { if (result[0]) return result[1]; } - warn('bad white code'); + info('bad white code'); this.eatBits(1); return 1; }; @@ -2135,7 +2135,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() { if (result[0]) return result[1]; } - warn('bad black code'); + info('bad black code'); this.eatBits(1); return 1; }; diff --git a/src/util.js b/src/util.js index 140b18cf1..bf5b11391 100644 --- a/src/util.js +++ b/src/util.js @@ -3,6 +3,8 @@ 'use strict'; +// Use only for debugging purposes. This should not be used in any code that is +// in mozilla master. function log(msg) { if (console && console.log) console.log(msg); @@ -10,9 +12,36 @@ function log(msg) { print(msg); } +// A notice for devs that will not trigger the fallback UI. These are good +// for things that are helpful to devs, such as warning that Workers were +// disabled, which is important to devs but not end users. +function info(msg) { + if (verbosity >= INFOS) { + log('Info: ' + msg); + PDFJS.LogManager.notify('info', msg); + } +} + +// Non-fatal warnings that should trigger the fallback UI. function warn(msg) { - if (verbosity >= WARNINGS) + if (verbosity >= WARNINGS) { log('Warning: ' + msg); + PDFJS.LogManager.notify('warn', msg); + } +} + +// Fatal errors that should trigger the fallback UI and halt execution by +// throwing an exception. +function error(msg) { + log('Error: ' + msg); + log(backtrace()); + PDFJS.LogManager.notify('error', msg); + throw new Error(msg); +} + +// Missing features that should trigger the fallback UI. +function TODO(what) { + warn('TODO: ' + what); } function backtrace() { @@ -23,21 +52,6 @@ function backtrace() { } } -function error(msg) { - log('Error: ' + msg); - log(backtrace()); - throw new Error(msg); -} - -function TODO(what) { - if (verbosity >= TODOS) - log('TODO: ' + what); -} - -function malformed(msg) { - error('Malformed PDF: ' + msg); -} - function assert(cond, msg) { if (!cond) error(msg); @@ -47,9 +61,25 @@ function assert(cond, msg) { // behavior is undefined. function assertWellFormed(cond, msg) { if (!cond) - malformed(msg); + error(msg); } +var LogManager = PDFJS.LogManager = (function LogManagerClosure() { + var loggers = []; + return { + addLogger: function logManager_addLogger(logger) { + loggers.push(logger); + }, + notify: function(type, message) { + for (var i = 0, ii = loggers.length; i < ii; i++) { + var logger = loggers[i]; + if (logger[type]) + logger[type](message); + } + } + }; +})(); + function shadow(obj, prop, value) { Object.defineProperty(obj, prop, { value: value, enumerable: true, diff --git a/src/worker.js b/src/worker.js index 25f3f52cd..780eff8f3 100644 --- a/src/worker.js +++ b/src/worker.js @@ -11,10 +11,13 @@ function MessageHandler(name, comObj) { var ah = this.actionHandler = {}; ah['console_log'] = [function ahConsoleLog(data) { - console.log.apply(console, data); + console.log.apply(console, data); }]; ah['console_error'] = [function ahConsoleError(data) { - console.error.apply(console, data); + console.error.apply(console, data); + }]; + ah['_warn'] = [function ah_Warn(data) { + warn(data); }]; comObj.onmessage = function messageHandlerComObjOnMessage(event) { @@ -223,6 +226,17 @@ var workerConsole = { if (typeof window === 'undefined') { globalScope.console = workerConsole; + // Add a logger so we can pass warnings on to the main thread, errors will + // throw an exception which will be forwarded on automatically. + PDFJS.LogManager.addLogger({ + warn: function(msg) { + postMessage({ + action: '_warn', + data: msg + }); + } + }); + var handler = new MessageHandler('worker_processor', this); WorkerMessageHandler.setup(handler); } diff --git a/web/viewer.js b/web/viewer.js index d700e11f3..34118e2aa 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -221,6 +221,7 @@ var PDFView = { initialBookmark: document.location.hash.substring(1), container: null, initialized: false, + fellback: false, // called once when the document is loaded initialize: function pdfViewInitialize() { this.container = document.getElementById('viewerContainer'); @@ -375,6 +376,11 @@ var PDFView = { }, fallback: function pdfViewDownload() { + // Only trigger the fallback once so we don't spam the user with messages + // for one PDF. + if (this.fellback) + return; + this.fellback = true; var url = this.url.split('#')[0]; FirefoxCom.request('fallback', url); }, @@ -441,6 +447,34 @@ var PDFView = { * and optionally a 'stack' property. */ error: function pdfViewError(message, moreInfo) { + var moreInfoText = mozL10n.get('error_build', {build: PDFJS.build}, + 'PDF.JS Build: {{build}}') + '\n'; + if (moreInfo) { + moreInfoText += + mozL10n.get('error_message', {message: moreInfo.message}, + 'Message: {{message}}'); + if (moreInfo.stack) { + moreInfoText += '\n' + + mozL10n.get('error_stack', {stack: moreInfo.stack}, + 'Stack: {{stack}}'); + } else { + if (moreInfo.filename) { + moreInfoText += '\n' + + mozL10n.get('error_file', {file: moreInfo.filename}, + 'File: {{file}}'); + } + if (moreInfo.lineNumber) { + moreInfoText += '\n' + + mozL10n.get('error_line', {line: moreInfo.lineNumber}, + 'Line: {{line}}'); + } + } + } + if (PDFJS.isFirefoxExtension) { + console.error(message + '\n' + moreInfoText); + this.fallback(); + return; + } var errorWrapper = document.getElementById('errorWrapper'); errorWrapper.removeAttribute('hidden'); @@ -467,32 +501,9 @@ var PDFView = { }; moreInfoButton.removeAttribute('hidden'); lessInfoButton.setAttribute('hidden', 'true'); - errorMoreInfo.value = - mozL10n.get('error_build', {build: PDFJS.build}, - 'PDF.JS Build: {{build}}') + '\n'; + errorMoreInfo.value = moreInfoText; - if (moreInfo) { - errorMoreInfo.value += - mozL10n.get('error_message', {message: moreInfo.message}, - 'Message: {{message}}'); - if (moreInfo.stack) { - errorMoreInfo.value += '\n' + - mozL10n.get('error_stack', {stack: moreInfo.stack}, - 'Stack: {{stack}}'); - } else { - if (moreInfo.filename) { - errorMoreInfo.value += '\n' + - mozL10n.get('error_file', {file: moreInfo.filename}, - 'File: {{file}}'); - } - if (moreInfo.lineNumber) { - errorMoreInfo.value += '\n' + - mozL10n.get('error_line', {line: moreInfo.lineNumber}, - 'Line: {{line}}'); - } - } - } - errorMoreInfo.rows = errorMoreInfo.value.split('\n').length - 1; + errorMoreInfo.rows = moreInfoText.split('\n').length - 1; }, progress: function pdfViewProgress(level) { @@ -1385,6 +1396,14 @@ window.addEventListener('load', function webViewerLoad(evt) { PDFBug.init(); } + // Listen for warnings to trigger the fallback UI. Errors should be caught + // and call PDFView.error() so we don't need to listen for those. + PDFJS.LogManager.addLogger({ + warn: function() { + PDFView.fallback(); + } + }); + var thumbsView = document.getElementById('thumbnailView'); thumbsView.addEventListener('scroll', updateThumbViewArea, true);