diff --git a/Makefile b/Makefile
index fe5a3fc42..eaaa3e81f 100644
--- a/Makefile
+++ b/Makefile
@@ -211,6 +211,7 @@ EXTENSION_WEB_FILES = \
web/images \
web/viewer.css \
web/viewer.js \
+ web/viewer.html \
web/viewer-production.html \
$(NULL)
@@ -249,7 +250,18 @@ extension: | production
# Copy a standalone version of pdf.js inside the content directory
@cp $(BUILD_TARGET) $(FIREFOX_BUILD_CONTENT)/$(BUILD_DIR)/
@cp -r $(EXTENSION_WEB_FILES) $(FIREFOX_BUILD_CONTENT)/web/
- @mv -f $(FIREFOX_BUILD_CONTENT)/web/viewer-production.html $(FIREFOX_BUILD_CONTENT)/web/viewer.html
+ @rm $(FIREFOX_BUILD_CONTENT)/web/viewer-production.html
+ # Copy over the firefox extension snippet so we can inline pdf.js in it
+ cp web/viewer-snippet-firefox-extension.html $(FIREFOX_BUILD_CONTENT)/web/
+ # Modify the viewer so it does all the extension only stuff.
+ cd $(FIREFOX_BUILD_CONTENT)/web; \
+ sed -i.bak '/PDFJSSCRIPT_INCLUDE_BUNDLE/ r ../build/pdf.js' viewer-snippet-firefox-extension.html; \
+ sed -i.bak '/PDFJSSCRIPT_REMOVE/d' viewer.html; \
+ sed -i.bak '/PDFJSSCRIPT_REMOVE_FIREFOX_EXTENSION/d' viewer.html; \
+ sed -i.bak '/PDFJSSCRIPT_INCLUDE_FIREFOX_EXTENSION/ r viewer-snippet-firefox-extension.html' viewer.html; \
+ rm -f *.bak;
+ # We don't need pdf.js anymore since its inlined
+ rm -Rf $(FIREFOX_BUILD_CONTENT)/$(BUILD_DIR)/;
# Update the build version number
@sed -i.bak "s/PDFJSSCRIPT_BUILD/$(BUILD_NUMBER)/" $(FIREFOX_BUILD_DIR)/install.rdf
@sed -i.bak "s/PDFJSSCRIPT_BUILD/$(BUILD_NUMBER)/" $(FIREFOX_BUILD_DIR)/update.rdf
diff --git a/extensions/firefox/bootstrap.js b/extensions/firefox/bootstrap.js
index e51df28f8..bbc53195e 100644
--- a/extensions/firefox/bootstrap.js
+++ b/extensions/firefox/bootstrap.js
@@ -34,13 +34,10 @@ function shutdown(aData, aReason) {
}
function install(aData, aReason) {
- let url = 'chrome://pdf.js/content/web/viewer.html?file=%s';
- Services.prefs.setCharPref('extensions.pdf.js.url', url);
Services.prefs.setBoolPref('extensions.pdf.js.active', false);
}
function uninstall(aData, aReason) {
- Services.prefs.clearUserPref('extensions.pdf.js.url');
Services.prefs.clearUserPref('extensions.pdf.js.active');
}
diff --git a/extensions/firefox/chrome.manifest b/extensions/firefox/chrome.manifest
index d7db20b38..ec7c9a964 100644
--- a/extensions/firefox/chrome.manifest
+++ b/extensions/firefox/chrome.manifest
@@ -1,5 +1,5 @@
-content pdf.js content/
+resource pdf.js content/
component {2278dfd0-b75c-11e0-8257-1ba3d93c9f1a} components/pdfContentHandler.js
-contract @mozilla.org/uriloader/content-handler;1?type=application/pdf {2278dfd0-b75c-11e0-8257-1ba3d93c9f1a}
+contract @mozilla.org/streamconv;1?from=application/pdf&to=*/* {2278dfd0-b75c-11e0-8257-1ba3d93c9f1a}
diff --git a/extensions/firefox/components/pdfContentHandler.js b/extensions/firefox/components/pdfContentHandler.js
index 67459b759..fa9f329fc 100644
--- a/extensions/firefox/components/pdfContentHandler.js
+++ b/extensions/firefox/components/pdfContentHandler.js
@@ -21,47 +21,74 @@ function log(aMsg) {
}
const NS_ERROR_WONT_HANDLE_CONTENT = 0x805d0001;
+
function pdfContentHandler() {
-}
+};
pdfContentHandler.prototype = {
- handleContent: function handleContent(aMimetype, aContext, aRequest) {
- if (aMimetype != PDF_CONTENT_TYPE)
- throw NS_ERROR_WONT_HANDLE_CONTENT;
- if (!(aRequest instanceof Ci.nsIChannel))
- throw NS_ERROR_WONT_HANDLE_CONTENT;
+ // properties required for XPCOM registration:
+ classID: Components.ID('{2278dfd0-b75c-11e0-8257-1ba3d93c9f1a}'),
+ classDescription: 'pdf.js Component',
+ contractID: '@mozilla.org/streamconv;1?from=application/pdf&to=*/*',
+
+ QueryInterface: XPCOMUtils.generateQI([
+ Ci.nsISupports,
+ Ci.nsIStreamConverter,
+ Ci.nsIStreamListener,
+ Ci.nsIRequestObserver
+ ]),
- if (!Services.prefs.getBoolPref('extensions.pdf.js.active'))
- throw NS_ERROR_WONT_HANDLE_CONTENT;
+ /*
+ * This component works as such:
+ * 1. asyncConvertData stores the listener
+ * 2. onStartRequest creates a new channel, streams the viewer and cancels
+ * the request so pdf.js can do the request
+ * Since the request is cancelled onDataAvailable should not be called. The
+ * onStopRequest does nothing. The convert function just returns the stream,
+ * it's just the synchronous version of asyncConvertData.
+ */
- let window = null;
- let callbacks = aRequest.notificationCallbacks ||
- aRequest.loadGroup.notificationCallbacks;
- if (!callbacks)
- return;
-
- window = callbacks.getInterface(Ci.nsIDOMWindow);
-
- let url = null;
- try {
- url = Services.prefs.getCharPref('extensions.pdf.js.url');
- } catch (e) {
- log('Error retrieving the pdf.js base url - ' + e);
- throw NS_ERROR_WONT_HANDLE_CONTENT;
- }
-
- let targetUrl = aRequest.URI.spec;
- if (targetUrl.indexOf('#pdfjs.action=download') >= 0)
- throw NS_ERROR_WONT_HANDLE_CONTENT;
-
- aRequest.cancel(Cr.NS_BINDING_ABORTED);
- window.location = url.replace('%s', encodeURIComponent(targetUrl));
+ // nsIStreamConverter::convert
+ convert: function (aFromStream, aFromType, aToType, aCtxt) {
+ return aFromStream;
},
- classID: Components.ID('{2278dfd0-b75c-11e0-8257-1ba3d93c9f1a}'),
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentHandler])
+ // nsIStreamConverter::asyncConvertData
+ asyncConvertData: function (aFromType, aToType, aListener, aCtxt) {
+ // Store the listener passed to us
+ this.listener = aListener;
+ },
+
+ // nsIStreamListener::onDataAvailable
+ onDataAvailable: function (aRequest, aContext, aInputStream, aOffset, aCount) {
+ // Do nothing since all the data loading is handled by the viewer.
+ log("SANITY CHECK: onDataAvailable SHOULD NOT BE CALLED!");
+ },
+
+ // nsIRequestObserver::onStartRequest
+ onStartRequest: function (aRequest, aContext) {
+ // Setup the request so we can use it below.
+ aRequest.QueryInterface(Ci.nsIChannel);
+
+ // Create a new channel that is viewer loaded as a resource.
+ var ioService = Cc["@mozilla.org/network/io-service;1"]
+ .getService(Ci.nsIIOService);
+ var channel = ioService.newChannel(
+ 'resource://pdf.js/web/viewer.html', null, null);
+ // Keep the URL the same so the browser sees it as the same.
+ channel.originalURI = aRequest.originalURI;
+ channel.asyncOpen(this.listener, aContext);
+
+ // Cancel the request so the viewer can handle it.
+ aRequest.cancel(Cr.NS_BINDING_ABORTED);
+ },
+
+ // nsIRequestObserver::onStopRequest
+ onStopRequest: function (aRequest, aContext, aStatusCode) {
+ // Do nothing.
+ return;
+ }
};
var NSGetFactory = XPCOMUtils.generateNSGetFactory([pdfContentHandler]);
-
diff --git a/src/core.js b/src/core.js
index 7a9f3ee03..3e3d991a9 100644
--- a/src/core.js
+++ b/src/core.js
@@ -624,9 +624,19 @@ var PDFDoc = (function PDFDocClosure() {
}
try {
- // Some versions of FF can't create a worker on localhost, see:
- // https://bugzilla.mozilla.org/show_bug.cgi?id=683280
- var worker = new Worker(workerSrc);
+ var worker;
+ if (PDFJS.isFirefoxExtension) {
+ // The firefox extension can't load the worker from the resource://
+ // url so we have to inline the script and then use the blob loader.
+ var bb = new MozBlobBuilder();
+ bb.append(document.querySelector('#PDFJS_SCRIPT_TAG').textContent);
+ var blobUrl = window.URL.createObjectURL(bb.getBlob());
+ worker = new Worker(blobUrl);
+ } else {
+ // Some versions of FF can't create a worker on localhost, see:
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=683280
+ worker = new Worker(workerSrc);
+ }
var messageHandler = new MessageHandler('main', worker);
@@ -645,7 +655,9 @@ var PDFDoc = (function PDFDocClosure() {
// serializing the typed array.
messageHandler.send('test', testObj);
return;
- } catch (e) {}
+ } catch (e) {
+ warn('The worker has been disabled.')
+ }
}
// Either workers are disabled, not supported or have thrown an exception.
// Thus, we fallback to a faked worker.
diff --git a/web/viewer-snippet-firefox-extension.html b/web/viewer-snippet-firefox-extension.html
new file mode 100644
index 000000000..a3d3502a8
--- /dev/null
+++ b/web/viewer-snippet-firefox-extension.html
@@ -0,0 +1,14 @@
+
+