pdf.js/extensions/firefox/components/PdfStreamConverter.js

245 lines
7.9 KiB
JavaScript
Raw Normal View History

2011-09-28 04:15:06 +09:00
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
'use strict';
2012-02-08 09:39:07 +09:00
var EXPORTED_SYMBOLS = ['PdfStreamConverter'];
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;
const PDFJS_EVENT_ID = 'pdf.js.message';
2011-09-28 04:15:06 +09:00
const PDF_CONTENT_TYPE = 'application/pdf';
const EXT_PREFIX = 'extensions.uriloader@pdf.js';
const MAX_DATABASE_LENGTH = 4096;
2011-09-28 04:15:06 +09:00
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
2012-05-09 05:05:33 +09:00
Cu.import('resource://gre/modules/NetUtil.jsm');
2012-03-21 01:39:33 +09:00
let privateBrowsing = Cc['@mozilla.org/privatebrowsing;1']
.getService(Ci.nsIPrivateBrowsingService);
let inPrivateBrowswing = privateBrowsing.privateBrowsingEnabled;
2012-05-11 02:05:24 +09:00
function getBoolPref(pref, def) {
2012-05-10 09:04:52 +09:00
try {
return Services.prefs.getBoolPref(pref);
} catch (ex) {
2012-05-11 02:05:24 +09:00
return def;
2012-05-10 09:04:52 +09:00
}
}
function setStringPref(pref, value) {
2012-05-11 02:05:24 +09:00
let str = Cc['@mozilla.org/supports-string;1']
2012-05-10 09:04:52 +09:00
.createInstance(Ci.nsISupportsString);
str.data = value;
Services.prefs.setComplexValue(pref, Ci.nsISupportsString, str);
}
2012-05-11 02:05:24 +09:00
function getStringPref(pref, def) {
2012-05-10 09:04:52 +09:00
try {
return Services.prefs.getComplexValue(pref, Ci.nsISupportsString).data;
} catch (ex) {
2012-05-11 02:05:24 +09:00
return def;
2012-05-10 09:04:52 +09:00
}
}
function log(aMsg) {
2012-05-10 09:04:52 +09:00
if (!getBoolPref(EXT_PREFIX + '.pdfBugEnabled', false))
2012-03-21 01:39:33 +09:00
return;
let msg = 'PdfStreamConverter.js: ' + (aMsg.join ? aMsg.join('') : aMsg);
2012-02-04 09:49:44 +09:00
Services.console.logStringMessage(msg);
2011-09-28 04:15:06 +09:00
dump(msg + '\n');
}
function getDOMWindow(aChannel) {
var requestor = aChannel.notificationCallbacks;
var win = requestor.getInterface(Components.interfaces.nsIDOMWindow);
return win;
2012-02-08 10:54:40 +09:00
}
// All the priviledged actions.
function ChromeActions() {
this.inPrivateBrowswing = privateBrowsing.privateBrowsingEnabled;
}
ChromeActions.prototype = {
download: function(data) {
2012-05-09 05:05:33 +09:00
let mimeService = Cc['@mozilla.org/mime;1'].getService(Ci.nsIMIMEService);
var handlerInfo = mimeService.
getFromTypeAndExtension('application/pdf', 'pdf');
var uri = NetUtil.newURI(data);
var extHelperAppSvc =
Cc['@mozilla.org/uriloader/external-helper-app-service;1'].
getService(Ci.nsIExternalHelperAppService);
var frontWindow = Cc['@mozilla.org/embedcomp/window-watcher;1'].
getService(Ci.nsIWindowWatcher).activeWindow;
var ioService = Services.io;
var channel = ioService.newChannel(data, null, null);
var listener = {
extListener: null,
onStartRequest: function(aRequest, aContext) {
this.extListener = extHelperAppSvc.doContent('application/pdf',
aRequest, frontWindow, false);
this.extListener.onStartRequest(aRequest, aContext);
},
onStopRequest: function(aRequest, aContext, aStatusCode) {
if (this.extListener)
this.extListener.onStopRequest(aRequest, aContext, aStatusCode);
},
onDataAvailable: function(aRequest, aContext, aInputStream, aOffset,
aCount) {
this.extListener.onDataAvailable(aRequest, aContext, aInputStream,
aOffset, aCount);
2012-05-09 05:05:33 +09:00
}
};
channel.asyncOpen(listener, null);
},
2012-02-01 10:53:42 +09:00
setDatabase: function(data) {
if (this.inPrivateBrowswing)
return;
// Protect against something sending tons of data to setDatabase.
if (data.length > MAX_DATABASE_LENGTH)
return;
2012-05-10 09:04:52 +09:00
setStringPref(EXT_PREFIX + '.database', data);
},
getDatabase: function() {
if (this.inPrivateBrowswing)
return '{}';
2012-05-10 09:04:52 +09:00
return getStringPref(EXT_PREFIX + '.database', '{}');
},
getLocale: function() {
2012-05-10 09:04:52 +09:00
return getStringPref('general.useragent.locale', 'en-US');
},
pdfBugEnabled: function() {
2012-05-10 09:04:52 +09:00
return getBoolPref(EXT_PREFIX + '.pdfBugEnabled', false);
}
};
// Event listener to trigger chrome privedged code.
function RequestListener(actions) {
this.actions = actions;
}
2012-02-01 10:53:42 +09:00
// Receive an event and synchronously responds.
RequestListener.prototype.receive = function(event) {
var message = event.target;
var action = message.getUserData('action');
var data = message.getUserData('data');
var actions = this.actions;
if (!(action in actions)) {
log('Unknown action: ' + action);
return;
}
var response = actions[action].call(this.actions, data);
message.setUserData('response', response, null);
};
function PdfStreamConverter() {
2012-01-24 10:52:53 +09:00
}
PdfStreamConverter.prototype = {
// properties required for XPCOM registration:
classID: Components.ID('{6457a96b-2d68-439a-bcfa-44465fbcdbb1}'),
classDescription: 'pdf.js Component',
contractID: '@mozilla.org/streamconv;1?from=application/pdf&to=*/*',
2012-01-24 10:52:53 +09:00
QueryInterface: XPCOMUtils.generateQI([
Ci.nsISupports,
Ci.nsIStreamConverter,
Ci.nsIStreamListener,
Ci.nsIRequestObserver
]),
/*
* 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.
*/
// nsIStreamConverter::convert
2012-01-24 10:52:53 +09:00
convert: function(aFromStream, aFromType, aToType, aCtxt) {
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
},
// nsIStreamConverter::asyncConvertData
2012-01-24 10:52:53 +09:00
asyncConvertData: function(aFromType, aToType, aListener, aCtxt) {
// Ignoring HTTP POST requests -- pdf.js has to repeat the request.
var skipConversion = false;
try {
var request = aCtxt;
request.QueryInterface(Ci.nsIHttpChannel);
2012-03-15 08:43:20 +09:00
skipConversion = (request.requestMethod !== 'GET');
} catch (e) {
// Non-HTTP request... continue normally.
}
if (skipConversion)
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
// Store the listener passed to us
this.listener = aListener;
},
// nsIStreamListener::onDataAvailable
2012-01-24 10:52:53 +09:00
onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, aCount) {
// Do nothing since all the data loading is handled by the viewer.
2012-01-24 10:52:53 +09:00
log('SANITY CHECK: onDataAvailable SHOULD NOT BE CALLED!');
},
// nsIRequestObserver::onStartRequest
2012-01-24 10:52:53 +09:00
onStartRequest: function(aRequest, aContext) {
// Setup the request so we can use it below.
aRequest.QueryInterface(Ci.nsIChannel);
2012-01-25 14:33:03 +09:00
// Cancel the request so the viewer can handle it.
aRequest.cancel(Cr.NS_BINDING_ABORTED);
// Create a new channel that is viewer loaded as a resource.
2012-02-04 09:49:44 +09:00
var ioService = Services.io;
var channel = ioService.newChannel(
'resource://pdf.js/web/viewer.html', null, null);
var listener = this.listener;
2012-04-17 06:33:11 +09:00
// Proxy all the request observer calls, when it gets to onStopRequest
// we can get the dom window.
var proxy = {
onStartRequest: function() {
listener.onStartRequest.apply(listener, arguments);
},
onDataAvailable: function() {
listener.onDataAvailable.apply(listener, arguments);
},
onStopRequest: function() {
var domWindow = getDOMWindow(channel);
2012-03-24 06:48:50 +09:00
// Double check the url is still the correct one.
if (domWindow.document.documentURIObject.equals(aRequest.URI)) {
let requestListener = new RequestListener(new ChromeActions);
domWindow.addEventListener(PDFJS_EVENT_ID, function(event) {
requestListener.receive(event);
}, false, true);
}
listener.onStopRequest.apply(listener, arguments);
}
};
// Keep the URL the same so the browser sees it as the same.
channel.originalURI = aRequest.URI;
channel.asyncOpen(proxy, aContext);
},
// nsIRequestObserver::onStopRequest
2012-01-24 10:52:53 +09:00
onStopRequest: function(aRequest, aContext, aStatusCode) {
// Do nothing.
}
};
var NSGetFactory = XPCOMUtils.generateNSGetFactory([PdfStreamConverter]);