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.
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.
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;
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.
27 function SerializeKeyEvent(event
) {
29 keyCode
: event
.keyCode
,
30 shiftKey
: event
.shiftKey
,
31 ctrlKey
: event
.ctrlKey
,
33 metaKey
: event
.metaKey
38 * An enum containing a value specifying whether the PDF is currently loading,
39 * has finished loading or failed to load.
48 * Create a new PDFScriptingAPI. This provides a scripting interface to
49 * the PDF viewer so that it can be customized by things like print preview.
50 * @param {Window} window the window of the page containing the pdf viewer.
51 * @param {Object} plugin the plugin element containing the pdf viewer.
53 function PDFScriptingAPI(window
, plugin
) {
54 this.loadState_
= LoadState
.LOADING
;
55 this.pendingScriptingMessages_
= [];
56 this.setPlugin(plugin
);
58 window
.addEventListener('message', function(event
) {
59 if (event
.origin
!= 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai') {
60 console
.error('Received message that was not from the extension: ' +
64 switch (event
.data
.type
) {
66 if (this.viewportChangedCallback_
)
67 this.viewportChangedCallback_(event
.data
.pageX
,
70 event
.data
.viewportWidth
,
71 event
.data
.viewportHeight
);
73 case 'documentLoaded':
74 this.loadState_
= event
.data
.load_state
;
75 if (this.loadCallback_
)
76 this.loadCallback_(this.loadState_
== LoadState
.SUCCESS
);
78 case 'getAccessibilityJSONReply':
79 if (this.accessibilityCallback_
) {
80 this.accessibilityCallback_(event
.data
.json
);
81 this.accessibilityCallback_
= null;
84 case 'getSelectedTextReply':
85 if (this.selectedTextCallback_
) {
86 this.selectedTextCallback_(event
.data
.selectedText
);
87 this.selectedTextCallback_
= null;
91 if (this.keyEventCallback_
)
92 this.keyEventCallback_(DeserializeKeyEvent(event
.data
.keyEvent
));
98 PDFScriptingAPI
.prototype = {
101 * Send a message to the extension. If messages try to get sent before there
102 * is a plugin element set, then we queue them up and send them later (this
103 * can happen in print preview).
104 * @param {Object} message The message to send.
106 sendMessage_: function(message
) {
108 this.plugin_
.postMessage(message
, '*');
110 this.pendingScriptingMessages_
.push(message
);
114 * Sets the plugin element containing the PDF viewer. The element will usually
115 * be passed into the PDFScriptingAPI constructor but may also be set later.
116 * @param {Object} plugin the plugin element containing the PDF viewer.
118 setPlugin: function(plugin
) {
119 this.plugin_
= plugin
;
122 // Send a message to ensure the postMessage channel is initialized which
123 // allows us to receive messages.
127 // Flush pending messages.
128 while (this.pendingScriptingMessages_
.length
> 0)
129 this.sendMessage_(this.pendingScriptingMessages_
.shift());
134 * Sets the callback which will be run when the PDF viewport changes.
135 * @param {Function} callback the callback to be called.
137 setViewportChangedCallback: function(callback
) {
138 this.viewportChangedCallback_
= callback
;
142 * Sets the callback which will be run when the PDF document has finished
143 * loading. If the document is already loaded, it will be run immediately.
144 * @param {Function} callback the callback to be called.
146 setLoadCallback: function(callback
) {
147 this.loadCallback_
= callback
;
148 if (this.loadState_
!= LoadState
.LOADING
&& this.loadCallback_
)
149 this.loadCallback_(this.loadState_
== LoadState
.SUCCESS
);
153 * Sets a callback that gets run when a key event is fired in the PDF viewer.
154 * @param {Function} callback the callback to be called with a key event.
156 setKeyEventCallback: function(callback
) {
157 this.keyEventCallback_
= callback
;
161 * Resets the PDF viewer into print preview mode.
162 * @param {string} url the url of the PDF to load.
163 * @param {boolean} grayscale whether or not to display the PDF in grayscale.
164 * @param {Array<number>} pageNumbers an array of the page numbers.
165 * @param {boolean} modifiable whether or not the document is modifiable.
167 resetPrintPreviewMode: function(url
, grayscale
, pageNumbers
, modifiable
) {
168 this.loadState_
= LoadState
.LOADING
;
170 type
: 'resetPrintPreviewMode',
172 grayscale
: grayscale
,
173 pageNumbers
: pageNumbers
,
174 modifiable
: modifiable
179 * Load a page into the document while in print preview mode.
180 * @param {string} url the url of the pdf page to load.
181 * @param {number} index the index of the page to load.
183 loadPreviewPage: function(url
, index
) {
185 type
: 'loadPreviewPage',
192 * Get accessibility JSON for the document. May only be called after document
194 * @param {Function} callback a callback to be called with the accessibility
195 * json that has been retrieved.
196 * @param {number} [page] the 0-indexed page number to get accessibility data
197 * for. If this is not provided, data about the entire document is
199 * @return {boolean} true if the function is successful, false if there is an
200 * outstanding request for accessibility data that has not been answered.
202 getAccessibilityJSON: function(callback
, page
) {
203 if (this.accessibilityCallback_
)
205 this.accessibilityCallback_
= callback
;
207 type
: 'getAccessibilityJSON',
209 if (page
|| page
== 0)
211 this.sendMessage_(message
);
216 * Select all the text in the document. May only be called after document
219 selectAll: function() {
226 * Get the selected text in the document. The callback will be called with the
227 * text that is selected. May only be called after document load.
228 * @param {Function} callback a callback to be called with the selected text.
229 * @return {boolean} true if the function is successful, false if there is an
230 * outstanding request for selected text that has not been answered.
232 getSelectedText: function(callback
) {
233 if (this.selectedTextCallback_
)
235 this.selectedTextCallback_
= callback
;
237 type
: 'getSelectedText'
243 * Print the document. May only be called after document load.
252 * Send a key event to the extension.
253 * @param {Event} keyEvent the key event to send to the extension.
255 sendKeyEvent: function(keyEvent
) {
257 type
: 'sendKeyEvent',
258 keyEvent
: SerializeKeyEvent(keyEvent
)
264 * Creates a PDF viewer with a scripting interface. This is basically 1) an
265 * iframe which is navigated to the PDF viewer extension and 2) a scripting
266 * interface which provides access to various features of the viewer for use
267 * by print preview and accessibility.
268 * @param {string} src the source URL of the PDF to load initially.
269 * @return {HTMLIFrameElement} the iframe element containing the PDF viewer.
271 function PDFCreateOutOfProcessPlugin(src
) {
272 var iframe
= window
.document
.createElement('iframe');
275 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/index.html?' + src
);
276 // Prevent the frame from being tab-focusable.
277 iframe
.setAttribute('tabindex', '-1');
278 var client
= new PDFScriptingAPI(window
);
279 iframe
.onload = function() {
280 client
.setPlugin(iframe
.contentWindow
);
282 // Add the functions to the iframe so that they can be called directly.
283 iframe
.setViewportChangedCallback
=
284 client
.setViewportChangedCallback
.bind(client
);
285 iframe
.setLoadCallback
= client
.setLoadCallback
.bind(client
);
286 iframe
.setKeyEventCallback
= client
.setKeyEventCallback
.bind(client
);
287 iframe
.resetPrintPreviewMode
= client
.resetPrintPreviewMode
.bind(client
);
288 iframe
.loadPreviewPage
= client
.loadPreviewPage
.bind(client
);
289 iframe
.sendKeyEvent
= client
.sendKeyEvent
.bind(client
);