]> git.parisson.com Git - pdf.js.git/commitdiff
Simple AcroForms support
authornotmasteryet <async.processingjs@yahoo.com>
Thu, 3 Nov 2011 01:46:39 +0000 (20:46 -0500)
committernotmasteryet <async.processingjs@yahoo.com>
Thu, 3 Nov 2011 01:46:39 +0000 (20:46 -0500)
src/core.js
web/viewer.css
web/viewer.js

index 09d665972748cc80d63b47fc8e680b659a27b78f..fa9747c7274e267505dccbd214fa53a32a1363ab 100644 (file)
@@ -265,46 +265,87 @@ var Page = (function pagePage() {
       }
     },
     getLinks: function pageGetLinks() {
+      var links = [];
+      var annotations = pageGetAnnotations();
+      var i, n = annotations.length;
+      for (i = 0; i < n; ++i) {
+        if (annotations[i].type != 'Link')
+          continue;
+        links.push(annotations[i]);
+      }
+      return links;
+    },
+    getAnnotations: function pageGetAnnotations() {
       var xref = this.xref;
       var annotations = xref.fetchIfRef(this.annotations) || [];
       var i, n = annotations.length;
-      var links = [];
+      var items = [];
       for (i = 0; i < n; ++i) {
         var annotation = xref.fetch(annotations[i]);
         if (!isDict(annotation))
           continue;
         var subtype = annotation.get('Subtype');
-        if (!isName(subtype) || subtype.name != 'Link')
+        if (!isName(subtype))
           continue;
         var rect = annotation.get('Rect');
         var topLeftCorner = this.rotatePoint(rect[0], rect[1]);
         var bottomRightCorner = this.rotatePoint(rect[2], rect[3]);
 
-        var link = {};
-        link.x = Math.min(topLeftCorner.x, bottomRightCorner.x);
-        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 = this.xref.fetchIfRef(annotation.get('A'));
-        if (a) {
-          switch (a.get('S').name) {
-            case 'URI':
-              link.url = a.get('URI');
-              break;
-            case 'GoTo':
-              link.dest = a.get('D');
+        var item = {};
+        item.type = subtype.name;
+        item.x = Math.min(topLeftCorner.x, bottomRightCorner.x);
+        item.y = Math.min(topLeftCorner.y, bottomRightCorner.y);
+        item.width = Math.abs(topLeftCorner.x - bottomRightCorner.x);
+        item.height = Math.abs(topLeftCorner.y - bottomRightCorner.y);
+        switch (subtype.name) {
+          case 'Link':
+            var a = this.xref.fetchIfRef(annotation.get('A'));
+            if (a) {
+              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');
+              }
+            } else if (annotation.has('Dest')) {
+              // simple destination link
+              var dest = annotation.get('Dest');
+              link.dest = isName(dest) ? dest.name : dest;
+            }
+            break;
+          case 'Widget':
+            var fieldType = annotation.get('FT');
+            if (!isName(fieldType))
               break;
-            default:
-              TODO('other link types');
-          }
-        } else if (annotation.has('Dest')) {
-          // simple destination link
-          var dest = annotation.get('Dest');
-          link.dest = isName(dest) ? dest.name : dest;
+            item.fieldType = fieldType.name;
+            var fieldName = [];
+            var name = stringToPDFString(annotation.get('T'));
+            if (name)
+              fieldName.push(name)
+            var parent = xref.fetchIfRef(annotation.get('Parent'));
+            while (parent) {
+              name = stringToPDFString(parent.get('T'));
+              if (name)
+                fieldName.unshift(name);
+              parent = xref.fetchIfRef(parent.get('Parent'));
+            }
+            item.fullName = fieldName.join('.');
+            var alternativeText = stringToPDFString(annotation.get('TU') || '');
+            item.alternativeText = alternativeText;
+            var da = annotation.get('DA') || '';
+            var m = /([\d\.]+)\sTf/.exec(da);
+            if (m)
+              item.fontSize = parseFloat(m[1]);
+            item.flags = annotation.get('Ff') || 0;
+            break;
         }
-        links.push(link);
+        items.push(item);
       }
-      return links;
+      return items;
     },
     startRendering: function pageStartRendering(ctx, callback)  {
       this.ctx = ctx;
@@ -342,6 +383,7 @@ var PDFDocModel = (function pdfDoc() {
     assertWellFormed(stream.length > 0, 'stream must have data');
     this.stream = stream;
     this.setup();
+    this.acroForm = this.xref.fetchIfRef(this.catalog.catDict.get('AcroForm'));
   }
 
   function find(stream, needle, limit, backwards) {
index 27ad0638a59ef0d7bc109a643248fe0914eb5f26..456d3eb94f074a47c118a7433378a2d66bf155c3 100644 (file)
@@ -231,6 +231,23 @@ canvas {
   -webkit-box-shadow: 0px 2px 10px #ff0;
 }
 
+.page > .inputHint {
+  opacity: 0.2;
+  background: #ccc;
+  position: absolute;
+}
+
+.page > .inputControl {
+  background: transparent;
+  border: 0px none;
+  position: absolute;
+  margin: auto;
+}
+
+.page > .inputControl[type='checkbox'] {
+  margin: 0px;
+}
+
 #viewer {
   margin: 44px 0px 0px;
   padding: 8px 0px;
@@ -281,6 +298,10 @@ canvas {
     display: block;
     page-break-after: always;
   }
+
+  .inputHint {
+    display: none;
+  }
 }
 
 #loading {
index 1ab2c555c60a2c65b83d9fba31682e7704cbc0d9..5d9e083d781f48ee02cd4e31df34839cfe2fe9cc 100644 (file)
@@ -33,6 +33,7 @@ var PDFView = {
   thumbnails: [],
   currentScale: kDefaultScale,
   initialBookmark: document.location.hash.substring(1),
+  formFields: [],
 
   setScale: function pdfViewSetScale(val, resetAutoSettings) {
     var pages = this.pages;
@@ -362,7 +363,7 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
     div.removeAttribute('data-loaded');
   };
 
-  function setupLinks(content, scale) {
+  function setupAnnotations(content, scale) {
     function bindLink(link, dest) {
       link.href = PDFView.getDestinationHash(dest);
       link.onclick = function pageViewSetupLinksOnclick() {
@@ -371,18 +372,82 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
         return false;
       };
     }
+    function bindInputItem(input, item) {
+      if (input.name in PDFView.formFields) {
+        var value = PDFView.formFields[input.name];
+        if (input.type == 'checkbox')
+          input.checked = value;
+        else if (!input.type || input.type == 'text')
+          input.value = value;
+      }
+      input.onchange = function pageViewSetupInputOnBlur() {
+        if (input.type == 'checkbox')
+          PDFView.formFields[input.name] = input.checked;
+        else if (!input.type || input.type == 'text')
+          PDFView.formFields[input.name] = input.value;
+      };
+    }
+    function createElementWithStyle(tagName, item) {
+      var element = document.createElement(tagName);
+      element.style.left = (Math.floor(item.x - view.x) * scale) + 'px';
+      element.style.top = (Math.floor(item.y - view.y) * scale) + 'px';
+      element.style.width = Math.ceil(item.width * scale) + 'px';
+      element.style.height = Math.ceil(item.height * scale) + 'px';
+      return element;
+    }
+    function assignFontStyle(element, item) {
+      var fontStyles = '';
+      if ('fontSize' in item)
+        fontStyles += 'font-size: ' + Math.round(item.fontSize * scale) + 'px';
+      element.setAttribute('style', element.getAttribute('style') + fontStyles);
+    }
 
-    var links = content.getLinks();
-    for (var i = 0; i < links.length; i++) {
-      var link = document.createElement('a');
-      link.style.left = (Math.floor(links[i].x - view.x) * scale) + 'px';
-      link.style.top = (Math.floor(links[i].y - view.y) * scale) + 'px';
-      link.style.width = Math.ceil(links[i].width * scale) + 'px';
-      link.style.height = Math.ceil(links[i].height * scale) + 'px';
-      link.href = links[i].url || '';
-      if (!links[i].url)
-        bindLink(link, ('dest' in links[i]) ? links[i].dest : null);
-      div.appendChild(link);
+    var items = content.getAnnotations();
+    for (var i = 0; i < items.length; i++) {
+      var item = items[i];
+      switch (item.type) {
+        case 'Link':
+          var link = createElementWithStyle('a', item);
+          link.href = item.url || '';
+          if (!item.url)
+            bindLink(link, ('dest' in item) ? item.dest : null);
+          div.appendChild(link);
+          break;
+        case 'Widget':
+          if (item.fieldType != 'Tx' && item.fieldType != 'Btn' &&
+              item.fieldType != 'Ch')
+            break;
+          var inputDiv = createElementWithStyle('div', item);
+          inputDiv.className = 'inputHint';
+          div.appendChild(inputDiv);
+          var input;
+          if (item.fieldType == 'Tx') {
+            input = createElementWithStyle('input', item);
+          }
+          if (item.fieldType == 'Btn') {
+            input = createElementWithStyle('input', item);
+            if (item.flags & 32768) {
+              input.type = 'radio';
+              TODO('radio button is not supported');
+            } else if (item.flags & 65536) {
+              input.type = 'button';
+              TODO('pushbutton is not supported');
+            } else {
+              input.type = 'checkbox';
+            }
+          }
+          if (item.fieldType == 'Ch') {
+            input = createElementWithStyle('select', item);
+            TODO('select box is not supported');
+          }
+          input.className = 'inputControl';
+          input.name = item.fullName;
+          input.title = item.alternativeText;
+          assignFontStyle(input, item);
+          bindInputItem(input, item);
+          div.appendChild(input);
+          break;
+      }
     }
   }
 
@@ -489,7 +554,7 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
     stats.begin = Date.now();
     this.content.startRendering(ctx, this.updateStats);
 
-    setupLinks(this.content, this.scale);
+    setupAnnotations(this.content, this.scale);
     div.setAttribute('data-loaded', true);
 
     return true;
@@ -738,6 +803,8 @@ window.addEventListener('pagechange', function pagechange(evt) {
 
 window.addEventListener('keydown', function keydown(evt) {
   var curElement = document.activeElement;
+  if (curElement && curElement.tagName == 'INPUT')
+    return;
   var controlsElement = document.getElementById('controls');
   while (curElement) {
     if (curElement === controlsElement)