@ -14,6 +14,7 @@ const MOZ_CENTRAL = PDFJSSCRIPT_MOZ_CENTRAL;
@@ -14,6 +14,7 @@ const MOZ_CENTRAL = PDFJSSCRIPT_MOZ_CENTRAL;
const PDFJS _EVENT _ID = 'pdf.js.message' ;
const PDF _CONTENT _TYPE = 'application/pdf' ;
const PREF _PREFIX = 'PDFJSSCRIPT_PREF_PREFIX' ;
const PDF _VIEWER _WEB _PAGE = 'resource://pdf.js/web/viewer.html' ;
const MAX _DATABASE _LENGTH = 4096 ;
const FIREFOX _ID = '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}' ;
const SEAMONKEY _ID = '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}' ;
@ -122,9 +123,39 @@ function getLocalizedString(strings, id, property) {
@@ -122,9 +123,39 @@ function getLocalizedString(strings, id, property) {
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.
function ChromeActions ( domWindow ) {
function ChromeActions ( domWindow , dataListener ) {
this . domWindow = domWindow ;
this . dataListener = dataListener ;
}
ChromeActions . prototype = {
@ -194,6 +225,36 @@ ChromeActions.prototype = {
@@ -194,6 +225,36 @@ ChromeActions.prototype = {
getLocale : function ( ) {
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 ) {
try {
// Lazy initialization of localizedStrings
@ -324,17 +385,21 @@ PdfStreamConverter.prototype = {
@@ -324,17 +385,21 @@ PdfStreamConverter.prototype = {
asyncConvertData : function ( aFromType , aToType , aListener , aCtxt ) {
if ( ! isEnabled ( ) )
throw Cr . NS _ERROR _NOT _IMPLEMENTED ;
// Ignoring HTTP POST requests -- pdf.js has to repeat the request.
var skipConversion = false ;
try {
var request = aCtxt ;
request . QueryInterface ( Ci . nsIHttpChannel ) ;
skipConversion = ( request . requestMethod !== 'GET' ) ;
} catch ( e ) {
// Non-HTTP request... continue normally.
var useFetchByChrome = getBoolPref ( PREF _PREFIX + '.fetchByChrome' , true ) ;
if ( ! useFetchByChrome ) {
// Ignoring HTTP POST requests -- pdf.js has to repeat the request.
var skipConversion = false ;
try {
var request = aCtxt ;
request . QueryInterface ( Ci . nsIHttpChannel ) ;
skipConversion = ( request . requestMethod !== 'GET' ) ;
} catch ( e ) {
// Non-HTTP request... continue normally.
}
if ( skipConversion )
throw Cr . NS _ERROR _NOT _IMPLEMENTED ;
}
if ( skipConversion )
throw Cr . NS _ERROR _NOT _IMPLEMENTED ;
// Store the listener passed to us
this . listener = aListener ;
@ -342,8 +407,14 @@ PdfStreamConverter.prototype = {
@@ -342,8 +407,14 @@ PdfStreamConverter.prototype = {
// 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!' ) ;
if ( ! this . dataListener ) {
// Do nothing since all the data loading is handled by the viewer.
return ;
}
var binaryStream = this . binaryStream ;
binaryStream . setInputStream ( aInputStream ) ;
this . dataListener . set ( binaryStream . readByteArray ( aCount ) , aOffset ) ;
} ,
// nsIRequestObserver::onStartRequest
@ -351,15 +422,30 @@ PdfStreamConverter.prototype = {
@@ -351,15 +422,30 @@ PdfStreamConverter.prototype = {
// Setup the request so we can use it below.
aRequest . QueryInterface ( Ci . nsIChannel ) ;
// Cancel the request so the viewer can handle it.
aRequest . cancel ( Cr . NS _BINDING _ABORTED ) ;
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.
aRequest . cancel ( Cr . NS _BINDING _ABORTED ) ;
}
// Create a new channel that is viewer loaded as a resource.
var ioService = Services . io ;
var channel = ioService . newChannel (
'resource://pdf.js/web/viewer.html' , null , null ) ;
PDF _VIEWER _WEB _PAGE , null , null ) ;
var listener = this . listener ;
var self = this ;
// Proxy all the request observer calls, when it gets to onStopRequest
// we can get the dom window.
var proxy = {
@ -373,8 +459,8 @@ PdfStreamConverter.prototype = {
@@ -373,8 +459,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 ( domWindow ) ) ;
let actions = new ChromeActions ( domWindow , dataListener ) ;
let requestListener = new RequestListener ( actions ) ;
domWindow . addEventListener ( PDFJS _EVENT _ID , function ( event ) {
requestListener . receive ( event ) ;
} , false , true ) ;
@ -386,11 +472,27 @@ PdfStreamConverter.prototype = {
@@ -386,11 +472,27 @@ PdfStreamConverter.prototype = {
// Keep the URL the same so the browser sees it as the same.
channel . originalURI = aRequest . URI ;
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
onStopRequest : function ( aRequest , aContext , aStatusCode ) {
// Do nothing.
if ( ! this . dataListener ) {
// Do nothing
return ;
}
this . dataListener . finish ( ) ;
delete this . dataListener ;
delete this . binaryStream ;
}
} ;