|
|
@ -14,6 +14,7 @@ const MOZ_CENTRAL = PDFJSSCRIPT_MOZ_CENTRAL; |
|
|
|
const PDFJS_EVENT_ID = 'pdf.js.message'; |
|
|
|
const PDFJS_EVENT_ID = 'pdf.js.message'; |
|
|
|
const PDF_CONTENT_TYPE = 'application/pdf'; |
|
|
|
const PDF_CONTENT_TYPE = 'application/pdf'; |
|
|
|
const PREF_PREFIX = 'PDFJSSCRIPT_PREF_PREFIX'; |
|
|
|
const PREF_PREFIX = 'PDFJSSCRIPT_PREF_PREFIX'; |
|
|
|
|
|
|
|
const PDF_VIEWER_WEB_PAGE = 'resource://pdf.js/web/viewer.html'; |
|
|
|
const MAX_DATABASE_LENGTH = 4096; |
|
|
|
const MAX_DATABASE_LENGTH = 4096; |
|
|
|
const FIREFOX_ID = '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}'; |
|
|
|
const FIREFOX_ID = '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}'; |
|
|
|
const SEAMONKEY_ID = '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}'; |
|
|
|
const SEAMONKEY_ID = '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}'; |
|
|
@ -122,9 +123,39 @@ function getLocalizedString(strings, id, property) { |
|
|
|
return id; |
|
|
|
return id; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// PDF data storage
|
|
|
|
|
|
|
|
function PdfDataListener(length) { |
|
|
|
|
|
|
|
this.length = length; |
|
|
|
|
|
|
|
this.data = new Uint8Array(length); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PdfDataListener.prototype = { |
|
|
|
|
|
|
|
set: function PdfDataListener_set(chunk, offset) { |
|
|
|
|
|
|
|
this.data.set(chunk, offset); |
|
|
|
|
|
|
|
var loaded = offset + chunk.length; |
|
|
|
|
|
|
|
this.onprogress(loaded, this.length); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
finish: function PdfDataListener_finish() { |
|
|
|
|
|
|
|
this.isDataReady = true; |
|
|
|
|
|
|
|
if (this.oncompleteCallback) { |
|
|
|
|
|
|
|
this.oncompleteCallback(this.data); |
|
|
|
|
|
|
|
delete this.data; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
onprogress: function() {}, |
|
|
|
|
|
|
|
set oncomplete(value) { |
|
|
|
|
|
|
|
this.oncompleteCallback = value; |
|
|
|
|
|
|
|
if (this.isDataReady) { |
|
|
|
|
|
|
|
value(this.data); |
|
|
|
|
|
|
|
delete this.data; // releasing temporary storage
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// All the priviledged actions.
|
|
|
|
// All the priviledged actions.
|
|
|
|
function ChromeActions(domWindow) { |
|
|
|
function ChromeActions(domWindow, dataListener) { |
|
|
|
this.domWindow = domWindow; |
|
|
|
this.domWindow = domWindow; |
|
|
|
|
|
|
|
this.dataListener = dataListener; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ChromeActions.prototype = { |
|
|
|
ChromeActions.prototype = { |
|
|
@ -194,6 +225,36 @@ ChromeActions.prototype = { |
|
|
|
getLocale: function() { |
|
|
|
getLocale: function() { |
|
|
|
return getStringPref('general.useragent.locale', 'en-US'); |
|
|
|
return getStringPref('general.useragent.locale', 'en-US'); |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
getLoadingType: function() { |
|
|
|
|
|
|
|
return this.dataListener ? 'passive' : 'active'; |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
initPassiveLoading: function() { |
|
|
|
|
|
|
|
if (!this.dataListener) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var domWindow = this.domWindow; |
|
|
|
|
|
|
|
this.dataListener.onprogress = |
|
|
|
|
|
|
|
function ChromeActions_dataListenerProgress(loaded, total) { |
|
|
|
|
|
|
|
domWindow.postMessage({ |
|
|
|
|
|
|
|
pdfjsLoadAction: 'progress', |
|
|
|
|
|
|
|
loaded: loaded, |
|
|
|
|
|
|
|
total: total |
|
|
|
|
|
|
|
}, '*'); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.dataListener.oncomplete = |
|
|
|
|
|
|
|
function ChromeActions_dataListenerComplete(data) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
domWindow.postMessage({ |
|
|
|
|
|
|
|
pdfjsLoadAction: 'complete', |
|
|
|
|
|
|
|
data: data |
|
|
|
|
|
|
|
}, '*'); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
delete this.dataListener; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
}, |
|
|
|
getStrings: function(data) { |
|
|
|
getStrings: function(data) { |
|
|
|
try { |
|
|
|
try { |
|
|
|
// Lazy initialization of localizedStrings
|
|
|
|
// Lazy initialization of localizedStrings
|
|
|
@ -324,6 +385,9 @@ PdfStreamConverter.prototype = { |
|
|
|
asyncConvertData: function(aFromType, aToType, aListener, aCtxt) { |
|
|
|
asyncConvertData: function(aFromType, aToType, aListener, aCtxt) { |
|
|
|
if (!isEnabled()) |
|
|
|
if (!isEnabled()) |
|
|
|
throw Cr.NS_ERROR_NOT_IMPLEMENTED; |
|
|
|
throw Cr.NS_ERROR_NOT_IMPLEMENTED; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var useFetchByChrome = getBoolPref(PREF_PREFIX + '.fetchByChrome', true); |
|
|
|
|
|
|
|
if (!useFetchByChrome) { |
|
|
|
// Ignoring HTTP POST requests -- pdf.js has to repeat the request.
|
|
|
|
// Ignoring HTTP POST requests -- pdf.js has to repeat the request.
|
|
|
|
var skipConversion = false; |
|
|
|
var skipConversion = false; |
|
|
|
try { |
|
|
|
try { |
|
|
@ -335,6 +399,7 @@ PdfStreamConverter.prototype = { |
|
|
|
} |
|
|
|
} |
|
|
|
if (skipConversion) |
|
|
|
if (skipConversion) |
|
|
|
throw Cr.NS_ERROR_NOT_IMPLEMENTED; |
|
|
|
throw Cr.NS_ERROR_NOT_IMPLEMENTED; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Store the listener passed to us
|
|
|
|
// Store the listener passed to us
|
|
|
|
this.listener = aListener; |
|
|
|
this.listener = aListener; |
|
|
@ -342,8 +407,14 @@ PdfStreamConverter.prototype = { |
|
|
|
|
|
|
|
|
|
|
|
// nsIStreamListener::onDataAvailable
|
|
|
|
// nsIStreamListener::onDataAvailable
|
|
|
|
onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, aCount) { |
|
|
|
onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, aCount) { |
|
|
|
|
|
|
|
if (!this.dataListener) { |
|
|
|
// Do nothing since all the data loading is handled by the viewer.
|
|
|
|
// Do nothing since all the data loading is handled by the viewer.
|
|
|
|
log('SANITY CHECK: onDataAvailable SHOULD NOT BE CALLED!'); |
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var binaryStream = this.binaryStream; |
|
|
|
|
|
|
|
binaryStream.setInputStream(aInputStream); |
|
|
|
|
|
|
|
this.dataListener.set(binaryStream.readByteArray(aCount), aOffset); |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
// nsIRequestObserver::onStartRequest
|
|
|
|
// nsIRequestObserver::onStartRequest
|
|
|
@ -351,15 +422,30 @@ PdfStreamConverter.prototype = { |
|
|
|
|
|
|
|
|
|
|
|
// Setup the request so we can use it below.
|
|
|
|
// Setup the request so we can use it below.
|
|
|
|
aRequest.QueryInterface(Ci.nsIChannel); |
|
|
|
aRequest.QueryInterface(Ci.nsIChannel); |
|
|
|
|
|
|
|
var useFetchByChrome = getBoolPref(PREF_PREFIX + '.fetchByChrome', true); |
|
|
|
|
|
|
|
var dataListener; |
|
|
|
|
|
|
|
if (useFetchByChrome) { |
|
|
|
|
|
|
|
// Creating storage for PDF data
|
|
|
|
|
|
|
|
var contentLength = aRequest.contentLength; |
|
|
|
|
|
|
|
if (contentLength < 0) |
|
|
|
|
|
|
|
throw new 'Unknown length is not supported'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
dataListener = new PdfDataListener(contentLength); |
|
|
|
|
|
|
|
this.dataListener = dataListener; |
|
|
|
|
|
|
|
this.binaryStream = Cc['@mozilla.org/binaryinputstream;1'] |
|
|
|
|
|
|
|
.createInstance(Ci.nsIBinaryInputStream); |
|
|
|
|
|
|
|
} else { |
|
|
|
// Cancel the request so the viewer can handle it.
|
|
|
|
// Cancel the request so the viewer can handle it.
|
|
|
|
aRequest.cancel(Cr.NS_BINDING_ABORTED); |
|
|
|
aRequest.cancel(Cr.NS_BINDING_ABORTED); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Create a new channel that is viewer loaded as a resource.
|
|
|
|
// Create a new channel that is viewer loaded as a resource.
|
|
|
|
var ioService = Services.io; |
|
|
|
var ioService = Services.io; |
|
|
|
var channel = ioService.newChannel( |
|
|
|
var channel = ioService.newChannel( |
|
|
|
'resource://pdf.js/web/viewer.html', null, null); |
|
|
|
PDF_VIEWER_WEB_PAGE, null, null); |
|
|
|
|
|
|
|
|
|
|
|
var listener = this.listener; |
|
|
|
var listener = this.listener; |
|
|
|
|
|
|
|
var self = this; |
|
|
|
// Proxy all the request observer calls, when it gets to onStopRequest
|
|
|
|
// Proxy all the request observer calls, when it gets to onStopRequest
|
|
|
|
// we can get the dom window.
|
|
|
|
// we can get the dom window.
|
|
|
|
var proxy = { |
|
|
|
var proxy = { |
|
|
@ -373,8 +459,8 @@ PdfStreamConverter.prototype = { |
|
|
|
var domWindow = getDOMWindow(channel); |
|
|
|
var domWindow = getDOMWindow(channel); |
|
|
|
// Double check the url is still the correct one.
|
|
|
|
// Double check the url is still the correct one.
|
|
|
|
if (domWindow.document.documentURIObject.equals(aRequest.URI)) { |
|
|
|
if (domWindow.document.documentURIObject.equals(aRequest.URI)) { |
|
|
|
let requestListener = new RequestListener( |
|
|
|
let actions = new ChromeActions(domWindow, dataListener); |
|
|
|
new ChromeActions(domWindow)); |
|
|
|
let requestListener = new RequestListener(actions); |
|
|
|
domWindow.addEventListener(PDFJS_EVENT_ID, function(event) { |
|
|
|
domWindow.addEventListener(PDFJS_EVENT_ID, function(event) { |
|
|
|
requestListener.receive(event); |
|
|
|
requestListener.receive(event); |
|
|
|
}, false, true); |
|
|
|
}, false, true); |
|
|
@ -386,11 +472,27 @@ PdfStreamConverter.prototype = { |
|
|
|
// Keep the URL the same so the browser sees it as the same.
|
|
|
|
// Keep the URL the same so the browser sees it as the same.
|
|
|
|
channel.originalURI = aRequest.URI; |
|
|
|
channel.originalURI = aRequest.URI; |
|
|
|
channel.asyncOpen(proxy, aContext); |
|
|
|
channel.asyncOpen(proxy, aContext); |
|
|
|
|
|
|
|
if (useFetchByChrome) { |
|
|
|
|
|
|
|
// We can use resource principal when data is fetched by the chrome
|
|
|
|
|
|
|
|
// e.g. useful for NoScript
|
|
|
|
|
|
|
|
var securityManager = Cc['@mozilla.org/scriptsecuritymanager;1'] |
|
|
|
|
|
|
|
.getService(Ci.nsIScriptSecurityManager); |
|
|
|
|
|
|
|
var uri = ioService.newURI(PDF_VIEWER_WEB_PAGE, null, null); |
|
|
|
|
|
|
|
var resourcePrincipal = securityManager.getCodebasePrincipal(uri); |
|
|
|
|
|
|
|
channel.owner = resourcePrincipal; |
|
|
|
|
|
|
|
} |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
// nsIRequestObserver::onStopRequest
|
|
|
|
// nsIRequestObserver::onStopRequest
|
|
|
|
onStopRequest: function(aRequest, aContext, aStatusCode) { |
|
|
|
onStopRequest: function(aRequest, aContext, aStatusCode) { |
|
|
|
// Do nothing.
|
|
|
|
if (!this.dataListener) { |
|
|
|
|
|
|
|
// Do nothing
|
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.dataListener.finish(); |
|
|
|
|
|
|
|
delete this.dataListener; |
|
|
|
|
|
|
|
delete this.binaryStream; |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|