From fca6f352e4a73b26b17244d66d53145cf7668281 Mon Sep 17 00:00:00 2001
From: Brendan Dahl <brendan.dahl@gmail.com>
Date: Thu, 10 May 2012 15:54:58 -0700
Subject: [PATCH 01/10] Add firefox ui fallback on error/unsupported feature.

---
 .../firefox/components/PdfStreamConverter.js  | 39 ++++++++++++++++++-
 l10n/en-US/viewer.properties                  |  3 ++
 web/viewer.js                                 |  5 +++
 3 files changed, 45 insertions(+), 2 deletions(-)

diff --git a/extensions/firefox/components/PdfStreamConverter.js b/extensions/firefox/components/PdfStreamConverter.js
index 49fd134ae..57647d67e 100644
--- a/extensions/firefox/components/PdfStreamConverter.js
+++ b/extensions/firefox/components/PdfStreamConverter.js
@@ -11,12 +11,14 @@ const Cr = Components.results;
 const Cu = Components.utils;
 const PDFJS_EVENT_ID = 'pdf.js.message';
 const PDF_CONTENT_TYPE = 'application/pdf';
-const EXT_PREFIX = 'extensions.uriloader@pdf.js';
+const EXT_ID = 'uriloader@pdf.js';
+const EXT_PREFIX = 'extensions.' + EXT_ID;
 const MAX_DATABASE_LENGTH = 4096;
 
 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 privateBrowsing = Cc['@mozilla.org/privatebrowsing;1']
                         .getService(Ci.nsIPrivateBrowsingService);
@@ -59,6 +61,13 @@ function getDOMWindow(aChannel) {
   return win;
 }
 
+// Fake l10n until we get the real l10n sorted out.
+var mozL10n = {
+  get: function(key, args, fallback) {
+    return fallback;
+  }
+};
+
 // All the priviledged actions.
 function ChromeActions() {
   this.inPrivateBrowswing = privateBrowsing.privateBrowsingEnabled;
@@ -115,10 +124,36 @@ ChromeActions.prototype = {
   },
   pdfBugEnabled: function() {
     return getBoolPref(EXT_PREFIX + '.pdfBugEnabled', false);
+  },
+  fallback: function(url) {
+    var self = this;
+    var message = mozL10n.get('unsupported_feature', null,
+                  'An unsupported feature was detected in this PDF document.');
+    var win = Services.wm.getMostRecentWindow('navigator:browser');
+    var notificationBox = win.gBrowser.getNotificationBox();
+    var buttons = [{
+      label: mozL10n.get('download_document', null, 'Download Document'),
+      accessKey: null,
+      callback: function() {
+        self.download(url);
+      }
+    }, {
+      label: mozL10n.get('disable_pdfjs', null,
+                         'Disable Mozilla PDF Viewer'),
+      accessKey: null,
+      callback: function() {
+        AddonManager.getAddonByID(EXT_ID, function(aAddon) {
+          aAddon.userDisabled = true;
+          win.gBrowser.contentWindow.location.reload();
+        });
+      }
+    }];
+    notificationBox.appendNotification(message, 'pdfjs-fallback', null,
+                                       notificationBox.PRIORITY_WARNING_LOW,
+                                       buttons);
   }
 };
 
-
 // Event listener to trigger chrome privedged code.
 function RequestListener(actions) {
   this.actions = actions;
diff --git a/l10n/en-US/viewer.properties b/l10n/en-US/viewer.properties
index c8dbe4aba..c1617b0bd 100644
--- a/l10n/en-US/viewer.properties
+++ b/l10n/en-US/viewer.properties
@@ -42,3 +42,6 @@ zoom_in_label=Zoom In
 zoom.title=Zoom
 thumb_page_title=Page {{page}}
 thumb_page_canvas=Thumbnail of Page {{page}}
+unsupported_feature=An unsupported feature was detected in this PDF document.
+download_document=Download Document
+disable_pdfjs=Disable Mozilla PDF Viewer
diff --git a/web/viewer.js b/web/viewer.js
index dcbfcf14e..d700e11f3 100644
--- a/web/viewer.js
+++ b/web/viewer.js
@@ -374,6 +374,11 @@ var PDFView = {
     }
   },
 
+  fallback: function pdfViewDownload() {
+    var url = this.url.split('#')[0];
+    FirefoxCom.request('fallback', url);
+  },
+
   navigateTo: function pdfViewNavigateTo(dest) {
     if (typeof dest === 'string')
       dest = this.destinations[dest];

From 034583e1a151bc35aa1680e3cf5833c20c303cf3 Mon Sep 17 00:00:00 2001
From: Brendan Dahl <brendan.dahl@gmail.com>
Date: Mon, 14 May 2012 17:19:09 -0700
Subject: [PATCH 02/10] Add new severity log info(). Change severity of some
 log messages. Trigger fallback on errors and warnings for extension.

---
 .../firefox/components/PdfStreamConverter.js  |  2 +-
 src/api.js                                    |  2 +-
 src/canvas.js                                 |  9 ++-
 src/colorspace.js                             |  4 +-
 src/core.js                                   |  2 +-
 src/evaluator.js                              |  2 +-
 src/fonts.js                                  |  2 +-
 src/stream.js                                 | 16 ++---
 src/util.js                                   | 64 ++++++++++++-----
 src/worker.js                                 | 18 ++++-
 web/viewer.js                                 | 69 ++++++++++++-------
 11 files changed, 128 insertions(+), 62 deletions(-)

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

From 03032d21c40a50ff75fd7c4cf3e046c447d44a90 Mon Sep 17 00:00:00 2001
From: Brendan Dahl <brendan.dahl@gmail.com>
Date: Tue, 15 May 2012 11:38:38 -0700
Subject: [PATCH 03/10] Add chrome.properties for moz central build.

---
 make.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/make.js b/make.js
index e166b6b96..955c94b07 100755
--- a/make.js
+++ b/make.js
@@ -395,7 +395,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 =
         ['bootstrap.js',
          'icon.png',

From e962d93946a88726ce53bde96e709c754cc4bf1b Mon Sep 17 00:00:00 2001
From: Brendan Dahl <brendan.dahl@gmail.com>
Date: Tue, 15 May 2012 16:05:45 -0700
Subject: [PATCH 04/10] Change to info for most gstate settings.

---
 src/evaluator.js | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/src/evaluator.js b/src/evaluator.js
index b0408998e..8d5e8ba5a 100644
--- a/src/evaluator.js
+++ b/src/evaluator.js
@@ -456,6 +456,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':
@@ -468,11 +480,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
                     case 'HT':
                     case 'SM':
                     case 'SA':
-                    case 'BM':
-                    case 'SMask':
                     case 'AIS':
                     case 'TK':
-                      TODO('graphic state operator ' + key);
+                      info('graphic state operator ' + key);
                       break;
                     default:
                       info('Unknown graphic state operator ' + key);

From ee54c0bfe4c80faa99f09efeb00f072a7e3b3492 Mon Sep 17 00:00:00 2001
From: Brendan Dahl <brendan.dahl@gmail.com>
Date: Wed, 23 May 2012 16:16:48 -0700
Subject: [PATCH 05/10] Remove disable option. Change download wording to open.

---
 extensions/firefox/components/PdfStreamConverter.js | 11 +----------
 l10n/en-US/chrome.properties                        |  3 +--
 2 files changed, 2 insertions(+), 12 deletions(-)

diff --git a/extensions/firefox/components/PdfStreamConverter.js b/extensions/firefox/components/PdfStreamConverter.js
index ced6b1048..d4a375ccc 100644
--- a/extensions/firefox/components/PdfStreamConverter.js
+++ b/extensions/firefox/components/PdfStreamConverter.js
@@ -176,20 +176,11 @@ ChromeActions.prototype = {
     var win = Services.wm.getMostRecentWindow('navigator:browser');
     var notificationBox = win.gBrowser.getNotificationBox();
     var buttons = [{
-      label: getLocalizedString(strings, 'download_document'),
+      label: getLocalizedString(strings, 'open_with_different_viewer'),
       accessKey: null,
       callback: function() {
         self.download(url);
       }
-    }, {
-      label: getLocalizedString(strings, 'disable_viewer'),
-      accessKey: null,
-      callback: function() {
-        AddonManager.getAddonByID(EXT_ID, function(aAddon) {
-          aAddon.userDisabled = true;
-          win.gBrowser.contentWindow.location.reload();
-        });
-      }
     }];
     notificationBox.appendNotification(message, 'pdfjs-fallback', null,
                                        notificationBox.PRIORITY_WARNING_LOW,
diff --git a/l10n/en-US/chrome.properties b/l10n/en-US/chrome.properties
index f0f4bcb88..26e46bac2 100644
--- a/l10n/en-US/chrome.properties
+++ b/l10n/en-US/chrome.properties
@@ -1,3 +1,2 @@
 unsupported_feature=An unsupported feature was detected in this PDF document.
-download_document=Download Document
-disable_viewer=Disable Mozilla PDF Viewer
+open_with_different_viewer=Open With Different Viewer

From 5d67183b4d251d929752b2b39377c94fd7f9c07f Mon Sep 17 00:00:00 2001
From: Brendan Dahl <brendan.dahl@gmail.com>
Date: Wed, 23 May 2012 16:54:55 -0700
Subject: [PATCH 06/10] Fix notification from showing up in wrong window.

---
 .../firefox/components/PdfStreamConverter.js       | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/extensions/firefox/components/PdfStreamConverter.js b/extensions/firefox/components/PdfStreamConverter.js
index d4a375ccc..550fbf271 100644
--- a/extensions/firefox/components/PdfStreamConverter.js
+++ b/extensions/firefox/components/PdfStreamConverter.js
@@ -100,7 +100,8 @@ function getLocalizedString(strings, id) {
 }
 
 // All the priviledged actions.
-function ChromeActions() {
+function ChromeActions(domWindow) {
+  this.domWindow = domWindow;
 }
 
 ChromeActions.prototype = {
@@ -170,11 +171,15 @@ ChromeActions.prototype = {
     return getBoolPref(EXT_PREFIX + '.pdfBugEnabled', false);
   },
   fallback: function(url) {
-    var strings = getLocalizedStrings('chrome.properties');
     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 notificationBox = win.gBrowser.getNotificationBox();
+    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,
@@ -290,7 +295,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);

From 7ea8caeb18457bc569c4aabeb748e1554d9fc329 Mon Sep 17 00:00:00 2001
From: Brendan Dahl <brendan.dahl@gmail.com>
Date: Fri, 25 May 2012 13:03:13 -0700
Subject: [PATCH 07/10] Change unsupported feature message.

---
 l10n/en-US/chrome.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/l10n/en-US/chrome.properties b/l10n/en-US/chrome.properties
index 26e46bac2..467d5920b 100644
--- a/l10n/en-US/chrome.properties
+++ b/l10n/en-US/chrome.properties
@@ -1,2 +1,2 @@
-unsupported_feature=An unsupported feature was detected in this PDF document.
+unsupported_feature=This PDF document might not be displayed correctly.
 open_with_different_viewer=Open With Different Viewer

From 5416b92392f38412960f08fc58ea6c75e56efaf4 Mon Sep 17 00:00:00 2001
From: Brendan Dahl <brendan.dahl@gmail.com>
Date: Fri, 25 May 2012 13:07:07 -0700
Subject: [PATCH 08/10] Add todo comment.

---
 src/evaluator.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/evaluator.js b/src/evaluator.js
index 128b82381..55af857e5 100644
--- a/src/evaluator.js
+++ b/src/evaluator.js
@@ -444,6 +444,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
                     case 'SA':
                     case 'AIS':
                     case 'TK':
+                      // TODO implement these operators.
                       info('graphic state operator ' + key);
                       break;
                     default:

From b1bf3ae56a5494cf3e65ffa8c1019240e2110fc8 Mon Sep 17 00:00:00 2001
From: Brendan Dahl <brendan.dahl@gmail.com>
Date: Fri, 25 May 2012 13:22:43 -0700
Subject: [PATCH 09/10] Trigger todo on forms.

---
 web/viewer.js | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/web/viewer.js b/web/viewer.js
index 0dfc678f9..d88e16e4e 100644
--- a/web/viewer.js
+++ b/web/viewer.js
@@ -932,6 +932,9 @@ var PageView = function pageView(container, pdfPage, id, scale,
             if (comment)
               div.appendChild(comment);
             break;
+          case 'Widget':
+            TODO('support forms');
+            break;
         }
       }
     });

From c0cfb486213d37820327f9c8042ca8d36e157fd9 Mon Sep 17 00:00:00 2001
From: Brendan Dahl <brendan.dahl@gmail.com>
Date: Fri, 25 May 2012 14:52:00 -0700
Subject: [PATCH 10/10] Prevent fallback when not ff extension.

---
 web/viewer.js | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/web/viewer.js b/web/viewer.js
index d88e16e4e..2b9067719 100644
--- a/web/viewer.js
+++ b/web/viewer.js
@@ -391,7 +391,9 @@ var PDFView = {
     }
   },
 
-  fallback: function pdfViewDownload() {
+  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)