Home | History | Annotate | Download | only in injected
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 
      6 /**
      7  * @fileoverview Logic to process PDFs
      8  */
      9 
     10 goog.provide('cvox.PdfProcessor');
     11 
     12 /**
     13  * Process PDFs created with Chrome's built-in PDF plug-in, which has an
     14  * accessibility hook.
     15  */
     16 cvox.PdfProcessor.processEmbeddedPdfs = function() {
     17   if (window.location.hash == '#original') {
     18     return;
     19   }
     20 
     21   var es = document.querySelectorAll('embed[type="application/pdf"]');
     22   for (var i = 0; i < es.length; i++) {
     23     var e = es[i];
     24     if (typeof e.accessibility === 'function') {
     25       var infoJSON = e.accessibility();
     26       var info = cvox.ChromeVoxJSON.parse(infoJSON);
     27 
     28       if (!info.loaded) {
     29         window.setTimeout(cvox.PdfProcessor.processEmbeddedPdfs, 100);
     30         continue;
     31       }
     32       if (!info.copyable) {
     33         cvox.ChromeVox.tts.speak(
     34             'Unable to access copy-protected PDF. Skipping.');
     35         continue;
     36       }
     37 
     38       var div = document.createElement('DIV');
     39 
     40       var headerDiv = document.createElement('DIV');
     41       headerDiv.style.position = 'relative';
     42       headerDiv.style.background = 'white';
     43       headerDiv.style.margin = '20pt';
     44       headerDiv.style.padding = '20pt';
     45       headerDiv.style.border = '1px solid #000';
     46       var filename = e.src.substr(e.src.lastIndexOf('/') + 1);
     47       document.title = filename;
     48       var html = cvox.ChromeVox.msgs.getMsg(
     49           'pdf_header', [filename, e.src + '#original']);
     50       headerDiv.innerHTML = html;
     51       // Set up a handler to reload the page when 'Show original' is clicked.
     52       var showLink = headerDiv.getElementsByTagName('a')[0];
     53       showLink.addEventListener('click', function() {
     54         window.location.href = e.src + '#original';
     55         window.location.reload();
     56       }, true);
     57       div.appendChild(headerDiv);
     58 
     59       // Document Styles
     60       div.style.position = 'relative';
     61       div.style.background = '#CCC';
     62       div.style.paddingTop = '1pt';
     63       div.style.paddingBottom = '1pt';
     64       div.style.width = '100%';
     65       div.style.minHeight = '100%';
     66 
     67       var displayPage = function(i) {
     68         var json = e.accessibility(i);
     69         var page = cvox.ChromeVoxJSON.parse(json);
     70         var pageDiv = document.createElement('DIV');
     71         var pageAnchor = document.createElement('A');
     72 
     73         // Page Achor Setup
     74         pageAnchor.name = 'page' + i;
     75 
     76         // Page Styles
     77         pageDiv.style.position = 'relative';
     78         pageDiv.style.background = 'white';
     79         pageDiv.style.margin = 'auto';
     80         pageDiv.style.marginTop = '20pt';
     81         pageDiv.style.marginBottom = '20pt';
     82         pageDiv.style.height = page.height + 'pt';
     83         pageDiv.style.width = page.width + 'pt';
     84         pageDiv.style.boxShadow = '0pt 0pt 10pt #333';
     85 
     86         // Text Nodes
     87         var texts = page['textBox'];
     88         for (var j = 0; j < texts.length; j++) {
     89           var text = texts[j];
     90           var textSpan = document.createElement('Span');
     91 
     92           // Text Styles
     93           textSpan.style.position = 'absolute';
     94           textSpan.style.left = text.left + 'pt';
     95           textSpan.style.top = text.top + 'pt';
     96           textSpan.style.fontSize = (0.8 * text.height) + 'pt';
     97 
     98           // Text Content
     99           for (var k = 0; k < text['textNodes'].length; k++) {
    100             var node = text['textNodes'][k];
    101             if (node.type == 'text') {
    102               textSpan.appendChild(document.createTextNode(node.text));
    103             } else if (node.type == 'url') {
    104               var a = document.createElement('A');
    105               a.href = node.url;
    106               a.appendChild(document.createTextNode(node.text));
    107               textSpan.appendChild(a);
    108             }
    109           }
    110 
    111           pageDiv.appendChild(textSpan);
    112         }
    113         div.appendChild(pageAnchor);
    114         div.appendChild(pageDiv);
    115 
    116         if (i < info['numberOfPages'] - 1) {
    117           window.setTimeout(function() { displayPage(i + 1); }, 0);
    118         } else {
    119           // NOTE(deboer): In the case of 'native' pdfs loaded directly
    120           // from a URL, we can not delete them outright.  Doing so exposes a
    121           // bug where all keyboard events are lost. We set it to
    122           // 'display: none' instead.
    123           e.style.display = 'none';
    124           e.parentNode.appendChild(div);
    125 
    126           // TODO(stoarca): Why are we resetting the navigationManager?
    127           // This function is too big and confusing, it needs to be cleaned up.
    128           cvox.ChromeVox.navigationManager.reset();
    129         }
    130       };
    131 
    132       window.setTimeout(function() { displayPage(0); }, 0);
    133     }
    134   }
    135 };
    136