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 * Create a new PDFMessagingClient. This provides a scripting interface to
7 * the PDF viewer so that it can be customized by things like print preview.
8 * @param {HTMLIFrameElement} iframe an iframe containing the PDF viewer.
9 * @param {Window} window the window of the page containing the iframe.
10 * @param {string} extensionUrl the url of the PDF extension.
12 function PDFMessagingClient(iframe
, window
, extensionUrl
) {
13 this.iframe_
= iframe
;
14 this.extensionUrl_
= extensionUrl
;
15 this.readyToReceive_
= false;
16 this.messageQueue_
= [];
17 window
.addEventListener('message', function(event
) {
18 switch (event
.data
.type
) {
19 case 'readyToReceive':
20 this.flushPendingMessages_();
22 case 'viewportChanged':
23 this.viewportChangedCallback_(event
.data
.pageX
,
26 event
.data
.viewportWidth
,
27 event
.data
.viewportHeight
);
29 case 'documentLoaded':
36 PDFMessagingClient
.prototype = {
39 * Send a message to the extension. If we try to send messages prior to the
40 * extension being ready to receive messages (i.e. before it has finished
41 * loading) we queue up the messages and flush them later.
42 * @param {MessageObject} the message to send.
44 sendMessage_: function(message
) {
45 if (!this.readyToReceive_
) {
46 this.messageQueue_
.push(message
);
50 this.iframe_
.contentWindow
.postMessage(message
, this.extensionUrl_
);
55 * Flushes all pending messages to the extension.
57 flushPendingMessages_: function() {
58 this.readyToReceive_
= true;
59 while (this.messageQueue_
.length
!= 0) {
60 this.iframe_
.contentWindow
.postMessage(this.messageQueue_
.shift(),
66 * Sets the callback which will be run when the PDF viewport changes.
67 * @param {Function} callback the callback to be called.
69 setViewportChangedCallback: function(callback
) {
70 this.viewportChangedCallback_
= callback
;
74 * Sets the callback which will be run when the PDF document has finished
76 * @param {Function} callback the callback to be called.
78 setLoadCallback: function(callback
) {
79 this.loadCallback_
= callback
;
83 * Resets the PDF viewer into print preview mode.
84 * @param {string} url the url of the PDF to load.
85 * @param {boolean} grayscale whether or not to display the PDF in grayscale.
86 * @param {Array.<number>} pageNumbers an array of the page numbers.
87 * @param {boolean} modifiable whether or not the document is modifiable.
89 resetPrintPreviewMode: function(url
, grayscale
, pageNumbers
, modifiable
) {
91 type
: 'resetPrintPreviewMode',
94 pageNumbers
: pageNumbers
,
95 modifiable
: modifiable
100 * Load a page into the document while in print preview mode.
101 * @param {string} url the url of the pdf page to load.
102 * @param {number} index the index of the page to load.
104 loadPreviewPage: function(url
, index
) {
106 type
: 'loadPreviewPage',
113 * Send a key event to the extension.
114 * @param {number} keyCode the key code to send to the extension.
116 sendKeyEvent: function(keyCode
) {
117 // TODO(raymes): Figure out a way to do this. It's only used to do scrolling
118 // the viewport, so probably just expose viewport controls instead.
123 * Creates a PDF viewer with a scripting interface. This is basically 1) an
124 * iframe which is navigated to the PDF viewer extension and 2) a scripting
125 * interface which provides access to various features of the viewer for use
126 * by print preview and accessbility.
127 * @param {string} src the source URL of the PDF to load initially.
128 * @return {HTMLIFrameElement} the iframe element containing the PDF viewer.
130 function PDFCreateOutOfProcessPlugin(src
) {
131 var EXTENSION_URL
= 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai';
132 var iframe
= window
.document
.createElement('iframe');
133 iframe
.setAttribute('src', EXTENSION_URL
+ '/index.html?' + src
);
134 var client
= new PDFMessagingClient(iframe
, window
, EXTENSION_URL
);
136 // Add the functions to the iframe so that they can be called directly.
137 iframe
.setViewportChangedCallback
=
138 client
.setViewportChangedCallback
.bind(client
);
139 iframe
.setLoadCallback
= client
.setLoadCallback
.bind(client
);
140 iframe
.resetPrintPreviewMode
= client
.resetPrintPreviewMode
.bind(client
);
141 iframe
.loadPreviewPage
= client
.loadPreviewPage
.bind(client
);
142 iframe
.sendKeyEvent
= client
.sendKeyEvent
.bind(client
);
147 * Create a new PDFMessagingHost. This is the extension-side of the scripting
148 * interface to the PDF viewer. It handles requests from a page which contains
149 * a PDF viewer extension and translates them into actions on the viewer.
150 * @param {Window} window the window containing the PDF extension.
151 * @param {PDFViewer} pdfViewer the object which provides access to the viewer.
153 function PDFMessagingHost(window
, pdfViewer
) {
154 this.window_
= window
;
155 this.pdfViewer_
= pdfViewer
;
156 this.viewport_
= pdfViewer
.viewport
;
158 window
.addEventListener('message', function(event
) {
159 switch (event
.data
.type
) {
160 case 'resetPrintPreviewMode':
161 this.pdfViewer_
.resetPrintPreviewMode(
163 event
.data
.grayscale
,
164 event
.data
.pageNumbers
,
165 event
.data
.modifiable
);
168 case 'loadPreviewPage':
169 this.pdfViewer_
.loadPreviewPage(event
.data
.url
, event
.data
.index
);
172 }.bind(this), false);
174 if (this.window_
.parent
!= this.window_
)
175 this.sendMessage_({type
: 'readyToReceive'});
178 PDFMessagingHost
.prototype = {
179 sendMessage_: function(message
) {
180 if (this.window_
.parent
== this.window_
)
182 this.window_
.parent
.postMessage(message
, '*');
185 viewportChanged: function() {
186 var visiblePage
= this.viewport_
.getMostVisiblePage();
187 var pageDimensions
= this.viewport_
.getPageScreenRect(visiblePage
);
188 var size
= this.viewport_
.size
;
191 type
: 'viewportChanged',
192 pageX
: pageDimensions
.x
,
193 pageY
: pageDimensions
.y
,
194 pageWidth
: pageDimensions
.width
,
195 viewportWidth
: size
.width
,
196 viewportHeight
: size
.height
,
200 documentLoaded: function() {
201 if (this.window_
.parent
== this.window_
)
203 this.sendMessage_({ type
: 'documentLoaded' });