]> git.parisson.com Git - pdf.js.git/commitdiff
'GoTo' action/links; document outline (no UI)
authornotmasteryet <async.processingjs@yahoo.com>
Sat, 20 Aug 2011 03:41:56 +0000 (22:41 -0500)
committernotmasteryet <async.processingjs@yahoo.com>
Sat, 20 Aug 2011 03:41:56 +0000 (22:41 -0500)
pdf.js
web/viewer.js

diff --git a/pdf.js b/pdf.js
index b8193a1384d5b6027dc09f65e2a0256c3050d4e2..eb9e180867532435656612fa47e0a7b6dab5d75a 100644 (file)
--- a/pdf.js
+++ b/pdf.js
@@ -3163,7 +3163,7 @@ var XRef = (function() {
 })();
 
 var Page = (function() {
-  function constructor(xref, pageNumber, pageDict) {
+  function constructor(xref, pageNumber, pageDict, ref) {
     this.pageNumber = pageNumber;
     this.pageDict = pageDict;
     this.stats = {
@@ -3174,6 +3174,7 @@ var Page = (function() {
       render: 0.0
     };
     this.xref = xref;
+    this.ref = ref;
   }
 
   constructor.prototype = {
@@ -3349,10 +3350,10 @@ var Page = (function() {
         var annotation = xref.fetch(annotations[i]);
         if (!IsDict(annotation, 'Annot'))
           continue;
-        var subtype = annotation.get("Subtype");
+        var subtype = annotation.get('Subtype');
         if (!IsName(subtype) || subtype.name != 'Link')
           continue;
-        var rect = annotation.get("Rect");
+        var rect = annotation.get('Rect');
         var topLeftCorner = this.rotatePoint(rect[0], rect[1]);
         var bottomRightCorner = this.rotatePoint(rect[2], rect[3]);
 
@@ -3361,14 +3362,17 @@ var Page = (function() {
         link.y = Math.min(topLeftCorner.y, bottomRightCorner.y);
         link.width = Math.abs(topLeftCorner.x - bottomRightCorner.x);
         link.height = Math.abs(topLeftCorner.y - bottomRightCorner.y);
-        var a = annotation.get("A");
+        var a = this.xref.fetchIfRef(annotation.get('A'));
         if (a) {
-          switch(a.get("S").name) {
-            case "URI":
-              link.url = a.get("URI");
+          switch(a.get('S').name) {
+            case 'URI':
+              link.url = a.get('URI');
+              break;
+            case 'GoTo':
+              link.dest = a.get('D');
               break;
             default:
-              TODO("other link types");
+              TODO('other link types');
               break;
           }
         }
@@ -3398,6 +3402,62 @@ var Catalog = (function() {
       // shadow the prototype getter
       return shadow(this, 'toplevelPagesDict', obj);
     },
+    get documentOutline() {
+      function convertIfUnicode(str) {
+        if (str[0] === '\xFE' && str[1] === '\xFF') {
+          // UTF16BE BOM
+          var i, n = str.length, str2 = "";
+          for (i = 2; i < n; i+=2)
+            str2 += String.fromCharCode((str.charCodeAt(i) << 8) | str.charCodeAt(i + 1));
+          str = str2;
+        }
+        return str;
+      }
+
+      var obj = this.catDict.get('Outlines');
+      var root = { items: [] };
+      if (IsRef(obj)) {
+        obj = this.xref.fetch(obj).get('First');
+        var processed = {};
+        if (IsRef(obj)) {
+          var queue = [{obj: obj, parent: root}];
+          // to avoid recursion keeping track of the items
+          // in the processed dictionary
+          processed['R' + obj.num + ',' + obj.gen] = true;
+          while (queue.length > 0) {
+            var i = queue.shift();
+            var outlineDict = this.xref.fetch(i.obj);
+            if (!outlineDict.has('Title'))
+              error('Invalid outline item');
+            var dest = outlineDict.get('Dest');
+            if (!dest && outlineDict.get('A')) {
+              var a = this.xref.fetchIfRef(outlineDict.get('A'));
+              dest = a.get('D');
+            }
+            var outlineItem = {
+              dest: dest,
+              title: convertIfUnicode(outlineDict.get('Title')),
+              color: outlineDict.get('C') || [0, 0, 0],
+              bold: !!(outlineDict.get('F') & 2),
+              italic: !!(outlineDict.get('F') & 1),
+              items: []
+            };
+            i.parent.items.push(outlineItem);
+            obj = outlineDict.get('First');
+            if (IsRef(obj) && !processed['R' + obj.num + ',' + obj.gen]) {
+              queue.push({obj: obj, parent: outlineItem});
+              processed['R' + obj.num + ',' + obj.gen] = true;
+            }
+            obj = outlineDict.get('Next');
+            if (IsRef(obj) && !processed['R' + obj.num + ',' + obj.gen]) {
+              queue.push({obj: obj, parent: i.parent});
+              processed['R' + obj.num + ',' + obj.gen] = true;
+            }
+          }
+        }
+      }
+      return shadow(this, 'documentOutline', root);
+    },
     get numPages() {
       var obj = this.toplevelPagesDict.get('Count');
       assertWellFormed(
@@ -3418,7 +3478,7 @@ var Catalog = (function() {
                          'page dictionary kid is not a reference');
         var obj = this.xref.fetch(kid);
         if (IsDict(obj, 'Page') || (IsDict(obj) && !obj.has('Kids'))) {
-          pageCache.push(new Page(this.xref, pageCache.length, obj));
+          pageCache.push(new Page(this.xref, pageCache.length, obj, kid));
         } else { // must be a child page dictionary
           assertWellFormed(
             IsDict(obj),
index e501a10b215f61e614007dbad22d09bbc6c21ec1..24afce799800b2a37805bd94f75f2ac4e3bdba2b 100644 (file)
@@ -84,6 +84,20 @@ var PDFView = {
     xhr.send(null);
   },
 
+  navigateTo: function (dest) {
+    var i, n = this.pages.length;
+    var destRef = dest[0];
+    // TODO optimize destination page search
+    for (i = 0; i < n; i++) {
+      var pageRef = this.pages[i].content.ref;
+      if (destRef.num == pageRef.num && destRef.gen == pageRef.gen) {
+        this.page = i + 1;
+        // TODO scroll to specific region on the page
+        break;
+      }
+    }
+  },
+
   load: function(data, scale) {
     var sidebar = document.getElementById('sidebarView');
     sidebar.parentNode.scrollTop = 0;
@@ -105,7 +119,7 @@ var PDFView = {
     for (var i = 1; i <= pagesCount; i++) {
       var page = pdf.getPage(i);
       pages.push(new PageView(container, page, i, page.width, page.height,
-                              page.stats));
+                              page.stats, this.navigateTo.bind(this)));
       thumbnails.push(new ThumbnailView(sidebar, pages[i - 1]));
     }
 
@@ -140,7 +154,8 @@ var PDFView = {
   }
 };
 
-var PageView = function(container, content, id, width, height, stats) {
+var PageView = function(container, content, id, width, height,
+                        stats, navigateTo) {
   this.width = width;
   this.height = height;
   this.id = id;
@@ -178,10 +193,9 @@ var PageView = function(container, content, id, width, height, stats) {
         }
         x /= scale;
         y /= scale;
-        for (var i = 0; i < links.length; i++) {
+        var i, n = links.length;
+        for (i = 0; i < n; i++) {
           var link = links[i];
-          if (!link.url)
-            continue;
           if (link.x <= x && link.y <= y &&
             x < link.x + link.width && y < link.y + link.height) {
             currentLink = link;
@@ -193,7 +207,12 @@ var PageView = function(container, content, id, width, height, stats) {
         canvas.style.cursor = 'default';
       }, false);
       canvas.addEventListener('mousedown', function(e) {
-        window.location.href = currentLink.url;
+        if (!currentLink)
+          return;
+        if (currentLink.url)
+          window.location.href = currentLink.url;
+        if (currentLink.dest)
+          navigateTo(currentLink.dest);
       }, false);
     }
   }