ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / chrome / browser / resources / pdf / pdf_scripting_api.js
blob84b94b12450f611cde0e95e394438f6b15a4b465
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.
5 /**
6  * Turn a dictionary received from postMessage into a key event.
7  * @param {Object} dict A dictionary representing the key event.
8  * @return {Event} A key event.
9  */
10 function DeserializeKeyEvent(dict) {
11   var e = document.createEvent('Event');
12   e.initEvent('keydown');
13   e.keyCode = dict.keyCode;
14   e.shiftKey = dict.shiftKey;
15   e.ctrlKey = dict.ctrlKey;
16   e.altKey = dict.altKey;
17   e.metaKey = dict.metaKey;
18   e.fromScriptingAPI = true;
19   return e;
22 /**
23  * Turn a key event into a dictionary which can be sent over postMessage.
24  * @param {Event} event A key event.
25  * @return {Object} A dictionary representing the key event.
26  */
27 function SerializeKeyEvent(event) {
28   return {
29     keyCode: event.keyCode,
30     shiftKey: event.shiftKey,
31     ctrlKey: event.ctrlKey,
32     altKey: event.altKey,
33     metaKey: event.metaKey
34   };
37 /**
38  * Create a new PDFScriptingAPI. This provides a scripting interface to
39  * the PDF viewer so that it can be customized by things like print preview.
40  * @param {Window} window the window of the page containing the pdf viewer.
41  * @param {Object} plugin the plugin element containing the pdf viewer.
42  */
43 function PDFScriptingAPI(window, plugin) {
44   this.loaded_ = false;
45   this.pendingScriptingMessages_ = [];
46   this.setPlugin(plugin);
48   window.addEventListener('message', function(event) {
49     if (event.origin != 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai') {
50       console.error('Received message that was not from the extension: ' +
51                     event);
52       return;
53     }
54     switch (event.data.type) {
55       case 'viewport':
56         if (this.viewportChangedCallback_)
57           this.viewportChangedCallback_(event.data.pageX,
58                                         event.data.pageY,
59                                         event.data.pageWidth,
60                                         event.data.viewportWidth,
61                                         event.data.viewportHeight);
62         break;
63       case 'documentLoaded':
64         this.loaded_ = true;
65         if (this.loadCallback_)
66           this.loadCallback_();
67         break;
68       case 'getAccessibilityJSONReply':
69         if (this.accessibilityCallback_) {
70           this.accessibilityCallback_(event.data.json);
71           this.accessibilityCallback_ = null;
72         }
73         break;
74       case 'getSelectedTextReply':
75         if (this.selectedTextCallback_) {
76           this.selectedTextCallback_(event.data.selectedText);
77           this.selectedTextCallback_ = null;
78         }
79         break;
80       case 'sendKeyEvent':
81         if (this.keyEventCallback_)
82           this.keyEventCallback_(DeserializeKeyEvent(event.data.keyEvent));
83         break;
84     }
85   }.bind(this), false);
88 PDFScriptingAPI.prototype = {
89   /**
90    * @private
91    * Send a message to the extension. If messages try to get sent before there
92    * is a plugin element set, then we queue them up and send them later (this
93    * can happen in print preview).
94    * @param {Object} message The message to send.
95    */
96   sendMessage_: function(message) {
97     if (this.plugin_)
98       this.plugin_.postMessage(message, '*');
99     else
100       this.pendingScriptingMessages_.push(message);
101   },
103  /**
104   * Sets the plugin element containing the PDF viewer. The element will usually
105   * be passed into the PDFScriptingAPI constructor but may also be set later.
106   * @param {Object} plugin the plugin element containing the PDF viewer.
107   */
108   setPlugin: function(plugin) {
109     this.plugin_ = plugin;
111     if (this.plugin_) {
112       // Send a message to ensure the postMessage channel is initialized which
113       // allows us to receive messages.
114       this.sendMessage_({
115         type: 'initialize'
116       });
117       // Flush pending messages.
118       while (this.pendingScriptingMessages_.length > 0)
119         this.sendMessage_(this.pendingScriptingMessages_.shift());
120     }
121   },
123   /**
124    * Sets the callback which will be run when the PDF viewport changes.
125    * @param {Function} callback the callback to be called.
126    */
127   setViewportChangedCallback: function(callback) {
128     this.viewportChangedCallback_ = callback;
129   },
131   /**
132    * Sets the callback which will be run when the PDF document has finished
133    * loading. If the document is already loaded, it will be run immediately.
134    * @param {Function} callback the callback to be called.
135    */
136   setLoadCallback: function(callback) {
137     this.loadCallback_ = callback;
138     if (this.loaded_ && this.loadCallback_)
139       this.loadCallback_();
140   },
142   /**
143    * Sets a callback that gets run when a key event is fired in the PDF viewer.
144    * @param {Function} callback the callback to be called with a key event.
145    */
146   setKeyEventCallback: function(callback) {
147     this.keyEventCallback_ = callback;
148   },
150   /**
151    * Resets the PDF viewer into print preview mode.
152    * @param {string} url the url of the PDF to load.
153    * @param {boolean} grayscale whether or not to display the PDF in grayscale.
154    * @param {Array<number>} pageNumbers an array of the page numbers.
155    * @param {boolean} modifiable whether or not the document is modifiable.
156    */
157   resetPrintPreviewMode: function(url, grayscale, pageNumbers, modifiable) {
158     this.loaded_ = false;
159     this.sendMessage_({
160       type: 'resetPrintPreviewMode',
161       url: url,
162       grayscale: grayscale,
163       pageNumbers: pageNumbers,
164       modifiable: modifiable
165     });
166   },
168   /**
169    * Load a page into the document while in print preview mode.
170    * @param {string} url the url of the pdf page to load.
171    * @param {number} index the index of the page to load.
172    */
173   loadPreviewPage: function(url, index) {
174     this.sendMessage_({
175       type: 'loadPreviewPage',
176       url: url,
177       index: index
178     });
179   },
181   /**
182    * Get accessibility JSON for the document. May only be called after document
183    * load.
184    * @param {Function} callback a callback to be called with the accessibility
185    *     json that has been retrieved.
186    * @param {number} [page] the 0-indexed page number to get accessibility data
187    *     for. If this is not provided, data about the entire document is
188    *     returned.
189    * @return {boolean} true if the function is successful, false if there is an
190    *     outstanding request for accessibility data that has not been answered.
191    */
192   getAccessibilityJSON: function(callback, page) {
193     if (this.accessibilityCallback_)
194       return false;
195     this.accessibilityCallback_ = callback;
196     var message = {
197       type: 'getAccessibilityJSON',
198     };
199     if (page || page == 0)
200       message.page = page;
201     this.sendMessage_(message);
202     return true;
203   },
205   /**
206    * Select all the text in the document. May only be called after document
207    * load.
208    */
209   selectAll: function() {
210     this.sendMessage_({
211       type: 'selectAll'
212     });
213   },
215   /**
216    * Get the selected text in the document. The callback will be called with the
217    * text that is selected. May only be called after document load.
218    * @param {Function} callback a callback to be called with the selected text.
219    * @return {boolean} true if the function is successful, false if there is an
220    *     outstanding request for selected text that has not been answered.
221    */
222   getSelectedText: function(callback) {
223     if (this.selectedTextCallback_)
224       return false;
225     this.selectedTextCallback_ = callback;
226     this.sendMessage_({
227       type: 'getSelectedText'
228     });
229     return true;
230   },
232   /**
233    * Print the document. May only be called after document load.
234    */
235   print: function() {
236     this.sendMessage_({
237       type: 'print'
238     });
239   },
241   /**
242    * Send a key event to the extension.
243    * @param {Event} keyEvent the key event to send to the extension.
244    */
245   sendKeyEvent: function(keyEvent) {
246     this.sendMessage_({
247       type: 'sendKeyEvent',
248       keyEvent: SerializeKeyEvent(keyEvent)
249     });
250   },
254  * Creates a PDF viewer with a scripting interface. This is basically 1) an
255  * iframe which is navigated to the PDF viewer extension and 2) a scripting
256  * interface which provides access to various features of the viewer for use
257  * by print preview and accessibility.
258  * @param {string} src the source URL of the PDF to load initially.
259  * @return {HTMLIFrameElement} the iframe element containing the PDF viewer.
260  */
261 function PDFCreateOutOfProcessPlugin(src) {
262   var iframe = window.document.createElement('iframe');
263   iframe.setAttribute(
264       'src',
265       'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/index.html?' + src);
266   // Prevent the frame from being tab-focusable.
267   iframe.setAttribute('tabindex', '-1');
268   var client = new PDFScriptingAPI(window);
269   iframe.onload = function() {
270     client.setPlugin(iframe.contentWindow);
271   };
272   // Add the functions to the iframe so that they can be called directly.
273   iframe.setViewportChangedCallback =
274       client.setViewportChangedCallback.bind(client);
275   iframe.setLoadCallback = client.setLoadCallback.bind(client);
276   iframe.setKeyEventCallback = client.setKeyEventCallback.bind(client);
277   iframe.resetPrintPreviewMode = client.resetPrintPreviewMode.bind(client);
278   iframe.loadPreviewPage = client.loadPreviewPage.bind(client);
279   iframe.sendKeyEvent = client.sendKeyEvent.bind(client);
280   return iframe;