Merge pull request #1701 from brendandahl/fallback-ui

Fallback UI for Extension
This commit is contained in:
Artur Adib 2012-05-29 08:43:31 -07:00
commit f991af003d
13 changed files with 190 additions and 68 deletions

View File

@ -19,6 +19,7 @@ const SEAMONKEY_ID = '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}';
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/NetUtil.jsm');
Cu.import('resource://gre/modules/AddonManager.jsm');
let appInfo = Cc['@mozilla.org/xre/app-info;1']
.getService(Ci.nsIXULAppInfo);
@ -91,9 +92,15 @@ function getLocalizedStrings(path) {
}
return map;
}
function getLocalizedString(strings, id) {
if (id in strings)
return strings[id]['textContent'];
return id;
}
// All the priviledged actions.
function ChromeActions() {
function ChromeActions(domWindow) {
this.domWindow = domWindow;
}
ChromeActions.prototype = {
@ -161,10 +168,30 @@ ChromeActions.prototype = {
},
pdfBugEnabled: function() {
return getBoolPref(PREF_PREFIX + '.pdfBugEnabled', false);
},
fallback: function(url) {
var self = this;
var domWindow = this.domWindow;
var strings = getLocalizedStrings('chrome.properties');
var message = getLocalizedString(strings, 'unsupported_feature');
var win = Services.wm.getMostRecentWindow('navigator:browser');
var browser = win.gBrowser.getBrowserForDocument(domWindow.top.document);
var notificationBox = win.gBrowser.getNotificationBox(browser);
var buttons = [{
label: getLocalizedString(strings, 'open_with_different_viewer'),
accessKey: null,
callback: function() {
self.download(url);
}
}];
notificationBox.appendNotification(message, 'pdfjs-fallback', null,
notificationBox.PRIORITY_WARNING_LOW,
buttons);
}
};
// Event listener to trigger chrome privedged code.
function RequestListener(actions) {
this.actions = actions;
@ -267,7 +294,8 @@ PdfStreamConverter.prototype = {
var domWindow = getDOMWindow(channel);
// Double check the url is still the correct one.
if (domWindow.document.documentURIObject.equals(aRequest.URI)) {
let requestListener = new RequestListener(new ChromeActions);
let requestListener = new RequestListener(
new ChromeActions(domWindow));
domWindow.addEventListener(PDFJS_EVENT_ID, function(event) {
requestListener.receive(event);
}, false, true);

View File

@ -0,0 +1,2 @@
unsupported_feature=This PDF document might not be displayed correctly.
open_with_different_viewer=Open With Different Viewer

View File

@ -110,6 +110,10 @@ target.locale = function() {
cp(path + '/viewer.properties', EXTENSION_LOCALE_OUTPUT + '/' + locale);
}
if (test('-f', path + '/chrome.properties')) {
cp(path + '/chrome.properties', EXTENSION_LOCALE_OUTPUT + '/' + locale);
}
if (test('-f', path + '/metadata.inc')) {
var metadata = cat(path + '/metadata.inc');
metadataContent += metadata;
@ -398,7 +402,8 @@ target.mozcentral = function() {
'components',
'../../LICENSE'],
DEFAULT_LOCALE_FILES =
[LOCALE_SRC_DIR + 'en-US/viewer.properties'],
[LOCALE_SRC_DIR + 'en-US/viewer.properties',
LOCALE_SRC_DIR + 'en-US/chrome.properties'],
FIREFOX_MC_EXTENSION_FILES =
['chrome.manifest',
'components',

View File

@ -452,7 +452,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.

View File

@ -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');
}
}

View File

@ -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;

View File

@ -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

View File

@ -418,6 +418,18 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
value[1]
]);
break;
case 'BM':
// We support the default so don't trigger the TODO.
if (!isName(value) || value.name != 'Normal')
TODO('graphic state operator ' + key);
break;
case 'SMask':
// We support the default so don't trigger the TODO.
if (!isName(value) || value.name != 'None')
TODO('graphic state operator ' + key);
break;
// Only generate info log messages for the following since
// they are unlikey to have a big impact on the rendering.
case 'OP':
case 'op':
case 'OPM':
@ -430,14 +442,13 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
case 'HT':
case 'SM':
case 'SA':
case 'BM':
case 'SMask':
case 'AIS':
case 'TK':
TODO('graphic state operator ' + key);
// TODO implement these operators.
info('graphic state operator ' + key);
break;
default:
warn('Unknown graphic state operator ' + key);
info('Unknown graphic state operator ' + key);
break;
}
}

View File

@ -3648,7 +3648,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;
}

View File

@ -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;
};

View File

@ -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,

View File

@ -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) {
@ -244,6 +247,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);
}

View File

@ -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');
@ -390,6 +391,18 @@ var PDFView = {
}
},
fallback: function pdfViewFallback() {
if (!PDFJS.isFirefoxExtension)
return;
// 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);
},
navigateTo: function pdfViewNavigateTo(dest) {
if (typeof dest === 'string')
dest = this.destinations[dest];
@ -452,6 +465,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');
@ -478,32 +519,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) {
@ -916,6 +934,9 @@ var PageView = function pageView(container, pdfPage, id, scale,
if (comment)
div.appendChild(comment);
break;
case 'Widget':
TODO('support forms');
break;
}
}
});
@ -1397,6 +1418,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);