Hack to support automatic printing from pdf javascript.

This commit is contained in:
Brendan Dahl 2013-02-28 15:29:07 -08:00
parent e20a9846ca
commit 5c43565404
4 changed files with 120 additions and 23 deletions

View File

@ -119,6 +119,16 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
promise.resolve(destinations); promise.resolve(destinations);
return promise; return promise;
}, },
/**
* @return {Promise} A promise that is resolved with an array of all the
* JavaScript strings in the name tree.
*/
getJavaScript: function PDFDocumentProxy_getDestinations() {
var promise = new PDFJS.Promise();
var js = this.pdfInfo.javaScript;
promise.resolve(js);
return promise;
},
/** /**
* @return {Promise} A promise that is resolved with an {array} that is a * @return {Promise} A promise that is resolved with an {array} that is a
* tree outline (if it has one) of the PDF. The tree is in the format of: * tree outline (if it has one) of the PDF. The tree is in the format of:

View File

@ -17,7 +17,7 @@
/* globals assertWellFormed, bytesToString, CipherTransformFactory, error, info, /* globals assertWellFormed, bytesToString, CipherTransformFactory, error, info,
InvalidPDFException, isArray, isCmd, isDict, isInt, isName, isRef, InvalidPDFException, isArray, isCmd, isDict, isInt, isName, isRef,
isStream, JpegStream, Lexer, log, Page, Parser, Promise, shadow, isStream, JpegStream, Lexer, log, Page, Parser, Promise, shadow,
stringToPDFString, stringToUTF8String, warn */ stringToPDFString, stringToUTF8String, warn, isString */
'use strict'; 'use strict';
@ -292,34 +292,51 @@ var Catalog = (function CatalogClosure() {
}); });
} }
if (nameTreeRef) { if (nameTreeRef) {
// reading name tree var nameTree = new NameTree(nameTreeRef, xref);
var processed = new RefSet(); var names = nameTree.getAll();
processed.put(nameTreeRef); for (var name in names) {
var queue = [nameTreeRef]; if (!names.hasOwnProperty(name)) {
while (queue.length > 0) {
var i, n;
obj = xref.fetch(queue.shift());
if (obj.has('Kids')) {
var kids = obj.get('Kids');
for (i = 0, n = kids.length; i < n; i++) {
var kid = kids[i];
if (processed.has(kid))
error('invalid destinations');
queue.push(kid);
processed.put(kid);
}
continue; continue;
} }
var names = obj.get('Names'); dests[name] = fetchDestination(names[name]);
if (names) {
for (i = 0, n = names.length; i < n; i += 2) {
dests[names[i]] = fetchDestination(xref.fetchIfRef(names[i + 1]));
}
}
} }
} }
return shadow(this, 'destinations', dests); return shadow(this, 'destinations', dests);
}, },
get javaScript() {
var xref = this.xref;
var obj = this.catDict.get('Names');
var javaScript = [];
if (obj && obj.has('JavaScript')) {
var nameTree = new NameTree(obj.getRaw('JavaScript'), xref);
var names = nameTree.getAll();
for (var name in names) {
if (!names.hasOwnProperty(name)) {
continue;
}
// We don't really use the JavaScript right now so this code is
// defensive so we don't cause errors on document load.
var jsDict = names[name];
if (!isDict(jsDict)) {
continue;
}
var type = jsDict.get('S');
if (!isName(type) || type.name !== 'JavaScript') {
continue;
}
var js = jsDict.get('JS');
if (!isString(js) && !isStream(js)) {
continue;
}
if (isStream(js)) {
js = bytesToString(js.getBytes());
}
javaScript.push(js);
}
}
return shadow(this, 'javaScript', javaScript);
},
getPage: function Catalog_getPage(n) { getPage: function Catalog_getPage(n) {
var pageCache = this.pageCache; var pageCache = this.pageCache;
if (!pageCache) { if (!pageCache) {
@ -755,6 +772,55 @@ var XRef = (function XRefClosure() {
return XRef; return XRef;
})(); })();
/**
* A NameTree is like a Dict but has some adventagous properties, see the spec
* (7.9.6) for more details.
* TODO: implement all the Dict functions and make this more efficent.
*/
var NameTree = (function NameTreeClosure() {
function NameTree(root, xref) {
this.root = root;
this.xref = xref;
}
NameTree.prototype = {
getAll: function NameTree_getAll() {
var dict = {};
if (!this.root) {
return dict;
}
var xref = this.xref;
// reading name tree
var processed = new RefSet();
processed.put(this.root);
var queue = [this.root];
while (queue.length > 0) {
var i, n;
var obj = xref.fetch(queue.shift());
if (obj.has('Kids')) {
var kids = obj.get('Kids');
for (i = 0, n = kids.length; i < n; i++) {
var kid = kids[i];
if (processed.has(kid))
error('invalid destinations');
queue.push(kid);
processed.put(kid);
}
continue;
}
var names = obj.get('Names');
if (names) {
for (i = 0, n = names.length; i < n; i += 2) {
dict[names[i]] = xref.fetchIfRef(names[i + 1]);
}
}
}
return dict;
}
};
return NameTree;
})();
/** /**
* A PDF document and page is built of many objects. E.g. there are objects * A PDF document and page is built of many objects. E.g. there are objects
* for fonts, images, rendering code and such. These objects might get processed * for fonts, images, rendering code and such. These objects might get processed

View File

@ -152,6 +152,7 @@ var WorkerMessageHandler = {
numPages: pdfModel.numPages, numPages: pdfModel.numPages,
fingerprint: pdfModel.getFingerprint(), fingerprint: pdfModel.getFingerprint(),
destinations: pdfModel.catalog.destinations, destinations: pdfModel.catalog.destinations,
javaScript: pdfModel.catalog.javaScript,
outline: pdfModel.catalog.documentOutline, outline: pdfModel.catalog.documentOutline,
info: pdfModel.getDocumentInfo(), info: pdfModel.getDocumentInfo(),
metadata: pdfModel.catalog.metadata, metadata: pdfModel.catalog.metadata,

View File

@ -1310,6 +1310,26 @@ var PDFView = {
} }
self.pagesRefMap = pagesRefMap; self.pagesRefMap = pagesRefMap;
// Wait to do this here so all the canvases are setup.
if (PDFView.supportsPrinting) {
pdfDocument.getJavaScript().then(function(javaScript) {
if (javaScript.length) {
PDFView.fallback();
}
// Hack to support auto printing.
var regex = /\bprint\s*\(/g;
for (var i = 0, ii = javaScript.length; i < ii; i++) {
var js = javaScript[i];
if (js && regex.test(js)) {
setTimeout(function() {
window.print();
});
return;
}
}
});
}
}); });
var destinationsPromise = pdfDocument.getDestinations(); var destinationsPromise = pdfDocument.getDestinations();