1a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved. 2a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// found in the LICENSE file. 4a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 5a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch/** 6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Create a new PDFScriptingAPI. This provides a scripting interface to 7a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * the PDF viewer so that it can be customized by things like print preview. 8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {Window} window the window of the page containing the pdf viewer. 9a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * @param {string} extensionUrl the url of the PDF extension. 10a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch */ 11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)function PDFScriptingAPI(window, extensionUrl) { 12a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch this.extensionUrl_ = extensionUrl; 13a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch this.messageQueue_ = []; 14a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch window.addEventListener('message', function(event) { 15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (event.origin != this.extensionUrl_) { 16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) console.error('Received message that was not from the extension: ' + 17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) event); 18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 20a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch switch (event.data.type) { 21a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch case 'readyToReceive': 22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.setDestinationWindow(event.source); 23a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch break; 24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case 'viewport': 25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (this.viewportChangedCallback_) 26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.viewportChangedCallback_(event.data.pageX, 27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) event.data.pageY, 28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) event.data.pageWidth, 29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) event.data.viewportWidth, 30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) event.data.viewportHeight); 31a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch break; 32a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch case 'documentLoaded': 33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (this.loadCallback_) 34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.loadCallback_(); 35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case 'getAccessibilityJSONReply': 37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (this.accessibilityCallback_) { 38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.accessibilityCallback_(event.data.json); 39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.accessibilityCallback_ = null; 40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 41a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch break; 42a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 43a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch }.bind(this), false); 44a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 45a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)PDFScriptingAPI.prototype = { 47a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch /** 48a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * @private 49a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * Send a message to the extension. If we try to send messages prior to the 50a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * extension being ready to receive messages (i.e. before it has finished 51a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * loading) we queue up the messages and flush them later. 52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {Object} the message to send. 53a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch */ 54a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch sendMessage_: function(message) { 55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!this.pdfWindow_) { 56a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch this.messageQueue_.push(message); 57a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return; 58a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 59a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.pdfWindow_.postMessage(message, this.extensionUrl_); 61a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch }, 62a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 63a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch /** 64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Sets the destination window containing the PDF viewer. This will be called 65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * when a 'readyToReceive' message is received from the PDF viewer or it can 66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * be called during tests. It then flushes any pending messages to the window. 67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {Window} pdfWindow the window containing the PDF viewer. 68a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch */ 69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) setDestinationWindow: function(pdfWindow) { 70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.pdfWindow_ = pdfWindow; 71a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch while (this.messageQueue_.length != 0) { 72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.pdfWindow_.postMessage(this.messageQueue_.shift(), 73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.extensionUrl_); 74a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 75a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch }, 76a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 77a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch /** 78a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * Sets the callback which will be run when the PDF viewport changes. 79a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * @param {Function} callback the callback to be called. 80a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch */ 81a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch setViewportChangedCallback: function(callback) { 82a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch this.viewportChangedCallback_ = callback; 83a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch }, 84a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 85a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch /** 86a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * Sets the callback which will be run when the PDF document has finished 87a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * loading. 88a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * @param {Function} callback the callback to be called. 89a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch */ 90a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch setLoadCallback: function(callback) { 91a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch this.loadCallback_ = callback; 92a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch }, 93a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 94a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch /** 95a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * Resets the PDF viewer into print preview mode. 96a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * @param {string} url the url of the PDF to load. 97a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * @param {boolean} grayscale whether or not to display the PDF in grayscale. 98a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * @param {Array.<number>} pageNumbers an array of the page numbers. 99a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * @param {boolean} modifiable whether or not the document is modifiable. 100a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch */ 101a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch resetPrintPreviewMode: function(url, grayscale, pageNumbers, modifiable) { 102a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch this.sendMessage_({ 103a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch type: 'resetPrintPreviewMode', 104a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch url: url, 105a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch grayscale: grayscale, 106a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch pageNumbers: pageNumbers, 107a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch modifiable: modifiable 108a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch }); 109a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch }, 110a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 111a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch /** 112a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * Load a page into the document while in print preview mode. 113a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * @param {string} url the url of the pdf page to load. 114a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * @param {number} index the index of the page to load. 115a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch */ 116a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch loadPreviewPage: function(url, index) { 117a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch this.sendMessage_({ 118a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch type: 'loadPreviewPage', 119a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch url: url, 120a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch index: index 121a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch }); 122a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch }, 123a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 124a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch /** 125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Get accessibility JSON for the document. 126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {Function} callback a callback to be called with the accessibility 127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * json that has been retrieved. 128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {number} [page] the 0-indexed page number to get accessibility data 129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * for. If this is not provided, data about the entire document is 130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * returned. 131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @return {boolean} true if the function is successful, false if there is an 132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * outstanding request for accessibility data that has not been answered. 133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) getAccessibilityJSON: function(callback, page) { 135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (this.accessibilityCallback_) 136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return false; 137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.accessibilityCallback_ = callback; 138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) var message = { 139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) type: 'getAccessibilityJSON', 140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) }; 141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (page || page == 0) 142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) message.page = page; 143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.sendMessage_(message); 144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return true; 145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) }, 146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) /** 148a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * Send a key event to the extension. 149a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * @param {number} keyCode the key code to send to the extension. 150a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch */ 151a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch sendKeyEvent: function(keyCode) { 152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this.sendMessage_({ 153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) type: 'sendKeyEvent', 154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) keyCode: keyCode 155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) }); 156a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch }, 157a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}; 158a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 159a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch/** 160a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * Creates a PDF viewer with a scripting interface. This is basically 1) an 161a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * iframe which is navigated to the PDF viewer extension and 2) a scripting 162a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * interface which provides access to various features of the viewer for use 163a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * by print preview and accessbility. 164a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * @param {string} src the source URL of the PDF to load initially. 165a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * @return {HTMLIFrameElement} the iframe element containing the PDF viewer. 166a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch */ 167a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochfunction PDFCreateOutOfProcessPlugin(src) { 168a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch var EXTENSION_URL = 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai'; 169a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch var iframe = window.document.createElement('iframe'); 170a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch iframe.setAttribute('src', EXTENSION_URL + '/index.html?' + src); 171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) var client = new PDFScriptingAPI(window, EXTENSION_URL); 172a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 173a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // Add the functions to the iframe so that they can be called directly. 174a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch iframe.setViewportChangedCallback = 175a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch client.setViewportChangedCallback.bind(client); 176a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch iframe.setLoadCallback = client.setLoadCallback.bind(client); 177a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch iframe.resetPrintPreviewMode = client.resetPrintPreviewMode.bind(client); 178a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch iframe.loadPreviewPage = client.loadPreviewPage.bind(client); 179a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch iframe.sendKeyEvent = client.sendKeyEvent.bind(client); 180a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return iframe; 181a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 182