• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
10goog.provide('cvox.PdfProcessor');
11
12/**
13 * Process PDFs created with Chrome's built-in PDF plug-in, which has an
14 * accessibility hook.
15 */
16cvox.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