diff --git a/src/core/obj.js b/src/core/obj.js index f1de50f59..cc2e36dd6 100644 --- a/src/core/obj.js +++ b/src/core/obj.js @@ -457,6 +457,46 @@ var Catalog = (function CatalogClosure() { } return shadow(this, 'destinations', dests); }, + getDestination: function Catalog_getDestination(destinationId) { + function fetchDestination(dest) { + return isDict(dest) ? dest.get('D') : dest; + } + + var xref = this.xref; + var dest, nameTreeRef, nameDictionaryRef; + var obj = this.catDict.get('Names'); + if (obj && obj.has('Dests')) { + nameTreeRef = obj.getRaw('Dests'); + } else if (this.catDict.has('Dests')) { + nameDictionaryRef = this.catDict.get('Dests'); + } + + if (nameDictionaryRef) { + // reading simple destination dictionary + obj = nameDictionaryRef; + obj.forEach(function catalogForEach(key, value) { + if (!value) { + return; + } + if (key === destinationId) { + dest = fetchDestination(value); + } + }); + } + if (nameTreeRef) { + var nameTree = new NameTree(nameTreeRef, xref); + var names = nameTree.getAll(); + for (var name in names) { + if (!names.hasOwnProperty(name)) { + continue; + } + if (name === destinationId) { + dest = fetchDestination(names[name]); + } + } + } + return dest; + }, get attachments() { var xref = this.xref; var attachments = null, nameTreeRef; diff --git a/src/core/worker.js b/src/core/worker.js index d4deb0c8c..40d7d899e 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -325,6 +325,12 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = { } ); + handler.on('GetDestination', + function wphSetupGetDestination(data) { + return pdfManager.ensureCatalog('getDestination', [ data.id ]); + } + ); + handler.on('GetAttachments', function wphSetupGetAttachments(data) { return pdfManager.ensureCatalog('attachments'); diff --git a/src/display/api.js b/src/display/api.js index b20472231..8fc68c2ef 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -293,10 +293,20 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() { /** * @return {Promise} A promise that is resolved with a lookup table for * mapping named destinations to reference numbers. + * + * This can be slow for large documents: use getDestination instead */ getDestinations: function PDFDocumentProxy_getDestinations() { return this.transport.getDestinations(); }, + /** + * @param {string} id The named destination to get. + * @return {Promise} A promise that is resolved with all information + * of the given named destination. + */ + getDestination: function PDFDocumentProxy_getDestination(id) { + return this.transport.getDestination(id); + }, /** * @return {Promise} A promise that is resolved with a lookup table for * mapping named attachments to their content. @@ -1128,6 +1138,10 @@ var WorkerTransport = (function WorkerTransportClosure() { return this.messageHandler.sendWithPromise('GetDestinations', null); }, + getDestination: function WorkerTransport_getDestination(id) { + return this.messageHandler.sendWithPromise('GetDestination', { id: id } ); + }, + getAttachments: function WorkerTransport_getAttachments() { return this.messageHandler.sendWithPromise('GetAttachments', null); }, diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index a8ba8382d..0044764e2 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -123,6 +123,13 @@ describe('api', function() { 0, 841.89, null] }); }); }); + it('gets a destination', function() { + var promise = doc.getDestination('chapter1'); + waitsForPromiseResolved(promise, function(data) { + expect(data).toEqual([{ gen: 0, num: 17 }, { name: 'XYZ' }, + 0, 841.89, null]); + }); + }); it('gets attachments', function() { var promise = doc.getAttachments(); waitsForPromiseResolved(promise, function (data) { diff --git a/web/viewer.js b/web/viewer.js index d4b449df9..95614693d 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -675,15 +675,19 @@ var PDFViewerApplication = { } }; - this.destinationsPromise.then(function() { - if (typeof dest === 'string') { - destString = dest; - dest = self.destinations[dest]; - } - if (!(dest instanceof Array)) { + var destinationPromise; + if (typeof dest === 'string') { + destString = dest; + destinationPromise = this.pdfDocument.getDestination(dest); + } else { + destinationPromise = Promise.resolve(dest); + } + destinationPromise.then(function(destination) { + dest = destination; + if (!(destination instanceof Array)) { return; // invalid destination } - goToDestination(dest[0]); + goToDestination(destination[0]); }); }, @@ -984,15 +988,8 @@ var PDFViewerApplication = { } }); - var destinationsPromise = - this.destinationsPromise = pdfDocument.getDestinations(); - destinationsPromise.then(function(destinations) { - self.destinations = destinations; - }); - - // outline depends on destinations and pagesRefMap - var promises = [pagesPromise, destinationsPromise, - this.animationStartedPromise]; + // outline depends on pagesRefMap + var promises = [pagesPromise, this.animationStartedPromise]; Promise.all(promises).then(function() { pdfDocument.getOutline().then(function(outline) { var outlineView = document.getElementById('outlineView');