Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / resources / print_preview / preview_generator.js
1 // Copyright (c) 2012 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 cr.define('print_preview', function() {
6   'use strict';
7
8   /**
9    * Interface to the Chromium print preview generator.
10    * @param {!print_preview.DestinationStore} destinationStore Used to get the
11    *     currently selected destination.
12    * @param {!print_preview.PrintTicketStore} printTicketStore Used to read the
13    *     state of the ticket and write document information.
14    * @param {!print_preview.NativeLayer} nativeLayer Used to communicate to
15    *     Chromium's preview rendering system.
16    * @param {!print_preview.DocumentInfo} documentInfo Document data model.
17    * @constructor
18    * @extends {cr.EventTarget}
19    */
20   function PreviewGenerator(
21        destinationStore, printTicketStore, nativeLayer, documentInfo) {
22     cr.EventTarget.call(this);
23
24     /**
25      * Used to get the currently selected destination.
26      * @type {!print_preview.DestinationStore}
27      * @private
28      */
29     this.destinationStore_ = destinationStore;
30
31     /**
32      * Used to read the state of the ticket and write document information.
33      * @type {!print_preview.PrintTicketStore}
34      * @private
35      */
36     this.printTicketStore_ = printTicketStore;
37
38     /**
39      * Interface to the Chromium native layer.
40      * @type {!print_preview.NativeLayer}
41      * @private
42      */
43     this.nativeLayer_ = nativeLayer;
44
45     /**
46      * Document data model.
47      * @type {!print_preview.DocumentInfo}
48      * @private
49      */
50     this.documentInfo_ = documentInfo;
51
52     /**
53      * ID of current in-flight request. Requests that do not share this ID will
54      * be ignored.
55      * @type {number}
56      * @private
57      */
58     this.inFlightRequestId_ = -1;
59
60     /**
61      * Whether the previews are being generated in landscape mode.
62      * @type {boolean}
63      * @private
64      */
65     this.isLandscapeEnabled_ = false;
66
67     /**
68      * Whether the previews are being generated with a header and footer.
69      * @type {boolean}
70      * @private
71      */
72     this.isHeaderFooterEnabled_ = false;
73
74     /**
75      * Whether the previews are being generated in color.
76      * @type {boolean}
77      * @private
78      */
79     this.colorValue_ = false;
80
81     /**
82      * Whether the document should be fitted to the page.
83      * @type {boolean}
84      * @private
85      */
86     this.isFitToPageEnabled_ = false;
87
88     /**
89      * Page ranges setting used used to generate the last preview.
90      * @type {!Array.<object.<{from: number, to: number}>>}
91      * @private
92      */
93     this.pageRanges_ = null;
94
95     /**
96      * Margins type used to generate the last preview.
97      * @type {!print_preview.ticket_items.MarginsType.Value}
98      * @private
99      */
100     this.marginsType_ = print_preview.ticket_items.MarginsType.Value.DEFAULT;
101
102     /**
103      * Whether the document should have element CSS backgrounds printed.
104      * @type {boolean}
105      * @private
106      */
107     this.isCssBackgroundEnabled_ = false;
108
109     /**
110      * Destination that was selected for the last preview.
111      * @type {print_preview.Destination}
112      * @private
113      */
114     this.selectedDestination_ = null;
115
116     /**
117      * Event tracker used to keep track of native layer events.
118      * @type {!EventTracker}
119      * @private
120      */
121     this.tracker_ = new EventTracker();
122
123     this.addEventListeners_();
124   };
125
126   /**
127    * Event types dispatched by the preview generator.
128    * @enum {string}
129    */
130   PreviewGenerator.EventType = {
131     // Dispatched when the document can be printed.
132     DOCUMENT_READY: 'print_preview.PreviewGenerator.DOCUMENT_READY',
133
134     // Dispatched when a page preview is ready. The previewIndex field of the
135     // event is the index of the page in the modified document, not the
136     // original. So page 4 of the original document might be previewIndex = 0 of
137     // the modified document.
138     PAGE_READY: 'print_preview.PreviewGenerator.PAGE_READY',
139
140     // Dispatched when the document preview starts to be generated.
141     PREVIEW_START: 'print_preview.PreviewGenerator.PREVIEW_START',
142
143     // Dispatched when the current print preview request fails.
144     FAIL: 'print_preview.PreviewGenerator.FAIL'
145   };
146
147   PreviewGenerator.prototype = {
148     __proto__: cr.EventTarget.prototype,
149
150     /**
151      * Request that new preview be generated. A preview request will not be
152      * generated if the print ticket has not changed sufficiently.
153      * @return {boolean} Whether a new preview was actually requested.
154      */
155     requestPreview: function() {
156       if (!this.printTicketStore_.isTicketValidForPreview() ||
157           !this.printTicketStore_.isInitialized ||
158           !this.destinationStore_.selectedDestination) {
159         return false;
160       }
161       if (!this.hasPreviewChanged_()) {
162         // Changes to these ticket items might not trigger a new preview, but
163         // they still need to be recorded.
164         this.marginsType_ = this.printTicketStore_.marginsType.getValue();
165         return false;
166       }
167       this.isLandscapeEnabled_ = this.printTicketStore_.landscape.getValue();
168       this.isHeaderFooterEnabled_ =
169           this.printTicketStore_.headerFooter.getValue();
170       this.colorValue_ = this.printTicketStore_.color.getValue();
171       this.isFitToPageEnabled_ = this.printTicketStore_.fitToPage.getValue();
172       this.pageRanges_ = this.printTicketStore_.pageRange.getPageRanges();
173       this.marginsType_ = this.printTicketStore_.marginsType.getValue();
174       this.isCssBackgroundEnabled_ =
175           this.printTicketStore_.cssBackground.getValue();
176       this.isSelectionOnlyEnabled_ =
177           this.printTicketStore_.selectionOnly.getValue();
178       this.selectedDestination_ = this.destinationStore_.selectedDestination;
179
180       this.inFlightRequestId_++;
181       this.nativeLayer_.startGetPreview(
182           this.destinationStore_.selectedDestination,
183           this.printTicketStore_,
184           this.documentInfo_,
185           this.inFlightRequestId_);
186       return true;
187     },
188
189     /** Removes all event listeners that the preview generator has attached. */
190     removeEventListeners: function() {
191       this.tracker_.removeAll();
192     },
193
194     /**
195      * Adds event listeners to the relevant native layer events.
196      * @private
197      */
198     addEventListeners_: function() {
199       this.tracker_.add(
200           this.nativeLayer_,
201           print_preview.NativeLayer.EventType.PAGE_LAYOUT_READY,
202           this.onPageLayoutReady_.bind(this));
203       this.tracker_.add(
204           this.nativeLayer_,
205           print_preview.NativeLayer.EventType.PAGE_COUNT_READY,
206           this.onPageCountReady_.bind(this));
207       this.tracker_.add(
208           this.nativeLayer_,
209           print_preview.NativeLayer.EventType.PAGE_PREVIEW_READY,
210           this.onPagePreviewReady_.bind(this));
211       this.tracker_.add(
212           this.nativeLayer_,
213           print_preview.NativeLayer.EventType.PREVIEW_GENERATION_DONE,
214           this.onPreviewGenerationDone_.bind(this));
215       this.tracker_.add(
216           this.nativeLayer_,
217           print_preview.NativeLayer.EventType.PREVIEW_GENERATION_FAIL,
218           this.onPreviewGenerationFail_.bind(this));
219     },
220
221     /**
222      * Dispatches a PAGE_READY event to signal that a page preview is ready.
223      * @param {number} previewIndex Index of the page with respect to the pages
224      *     shown in the preview. E.g an index of 0 is the first displayed page,
225      *     but not necessarily the first original document page.
226      * @param {number} pageNumber Number of the page with respect to the
227      *     document. A value of 3 means it's the third page of the original
228      *     document.
229      * @param {number} previewUid Unique identifier of the preview.
230      * @private
231      */
232     dispatchPageReadyEvent_: function(previewIndex, pageNumber, previewUid) {
233       var pageGenEvent = new Event(PreviewGenerator.EventType.PAGE_READY);
234       pageGenEvent.previewIndex = previewIndex;
235       pageGenEvent.previewUrl = 'chrome://print/' + previewUid.toString() +
236           '/' + (pageNumber - 1) + '/print.pdf';
237       this.dispatchEvent(pageGenEvent);
238     },
239
240     /**
241      * Dispatches a PREVIEW_START event. Signals that the preview should be
242      * reloaded.
243      * @param {number} previewUid Unique identifier of the preview.
244      * @param {number} index Index of the first page of the preview.
245      * @private
246      */
247     dispatchPreviewStartEvent_: function(previewUid, index) {
248       var previewStartEvent = new Event(
249           PreviewGenerator.EventType.PREVIEW_START);
250       if (!this.documentInfo_.isModifiable) {
251         index = -1;
252       }
253       previewStartEvent.previewUrl = 'chrome://print/' +
254           previewUid.toString() + '/' + index + '/print.pdf';
255       this.dispatchEvent(previewStartEvent);
256     },
257
258     /**
259      * @return {boolean} Whether the print ticket has changed sufficiently to
260      *     determine whether a new preview request should be issued.
261      * @private
262      */
263     hasPreviewChanged_: function() {
264       var ticketStore = this.printTicketStore_;
265       return this.inFlightRequestId_ == -1 ||
266           !ticketStore.landscape.isValueEqual(this.isLandscapeEnabled_) ||
267           !ticketStore.headerFooter.isValueEqual(this.isHeaderFooterEnabled_) ||
268           !ticketStore.color.isValueEqual(this.colorValue_) ||
269           !ticketStore.fitToPage.isValueEqual(this.isFitToPageEnabled_) ||
270           this.pageRanges_ == null ||
271           !areRangesEqual(ticketStore.pageRange.getPageRanges(),
272                           this.pageRanges_) ||
273           (!ticketStore.marginsType.isValueEqual(this.marginsType_) &&
274               !ticketStore.marginsType.isValueEqual(
275                   print_preview.ticket_items.MarginsType.Value.CUSTOM)) ||
276           (ticketStore.marginsType.isValueEqual(
277               print_preview.ticket_items.MarginsType.Value.CUSTOM) &&
278               !ticketStore.customMargins.isValueEqual(
279                   this.documentInfo_.margins)) ||
280           !ticketStore.cssBackground.isValueEqual(
281               this.isCssBackgroundEnabled_) ||
282           !ticketStore.selectionOnly.isValueEqual(
283               this.isSelectionOnlyEnabled_) ||
284           (this.selectedDestination_ !=
285               this.destinationStore_.selectedDestination);
286     },
287
288     /**
289      * Called when the page layout of the document is ready. Always occurs
290      * as a result of a preview request.
291      * @param {Event} event Contains layout info about the document.
292      * @private
293      */
294     onPageLayoutReady_: function(event) {
295       // NOTE: A request ID is not specified, so assuming its for the current
296       // in-flight request.
297
298       var origin = new print_preview.Coordinate2d(
299           event.pageLayout.printableAreaX,
300           event.pageLayout.printableAreaY);
301       var size = new print_preview.Size(
302           event.pageLayout.printableAreaWidth,
303           event.pageLayout.printableAreaHeight);
304
305       var margins = new print_preview.Margins(
306           Math.round(event.pageLayout.marginTop),
307           Math.round(event.pageLayout.marginRight),
308           Math.round(event.pageLayout.marginBottom),
309           Math.round(event.pageLayout.marginLeft));
310
311       var o = print_preview.ticket_items.CustomMargins.Orientation;
312       var pageSize = new print_preview.Size(
313           event.pageLayout.contentWidth +
314               margins.get(o.LEFT) + margins.get(o.RIGHT),
315           event.pageLayout.contentHeight +
316               margins.get(o.TOP) + margins.get(o.BOTTOM));
317
318       this.documentInfo_.updatePageInfo(
319           new print_preview.PrintableArea(origin, size),
320           pageSize,
321           event.hasCustomPageSizeStyle,
322           margins);
323     },
324
325     /**
326      * Called when the document page count is received from the native layer.
327      * Always occurs as a result of a preview request.
328      * @param {Event} event Contains the document's page count.
329      * @private
330      */
331     onPageCountReady_: function(event) {
332       if (this.inFlightRequestId_ != event.previewResponseId) {
333         return; // Ignore old response.
334       }
335       this.documentInfo_.updatePageCount(event.pageCount);
336       this.pageRanges_ = this.printTicketStore_.pageRange.getPageRanges();
337     },
338
339     /**
340      * Called when a page's preview has been generated. Dispatches a
341      * PAGE_READY event.
342      * @param {Event} event Contains the page index and preview UID.
343      * @private
344      */
345     onPagePreviewReady_: function(event) {
346       if (this.inFlightRequestId_ != event.previewResponseId) {
347         return; // Ignore old response.
348       }
349       var pageNumber = event.pageIndex + 1;
350       var pageNumberSet = this.printTicketStore_.pageRange.getPageNumberSet();
351       if (pageNumberSet.hasPageNumber(pageNumber)) {
352         var previewIndex = pageNumberSet.getPageNumberIndex(pageNumber);
353         if (previewIndex == 0) {
354           this.dispatchPreviewStartEvent_(event.previewUid, event.pageIndex);
355         }
356         this.dispatchPageReadyEvent_(
357             previewIndex, pageNumber, event.previewUid);
358       }
359     },
360
361     /**
362      * Called when the preview generation is complete. Dispatches a
363      * DOCUMENT_READY event.
364      * @param {Event} event Contains the preview UID and response ID.
365      * @private
366      */
367     onPreviewGenerationDone_: function(event) {
368       if (this.inFlightRequestId_ != event.previewResponseId) {
369         return; // Ignore old response.
370       }
371       // Dispatch a PREVIEW_START event since non-modifiable documents don't
372       // trigger PAGE_READY events.
373       if (!this.documentInfo_.isModifiable) {
374         this.dispatchPreviewStartEvent_(event.previewUid, 0);
375       }
376       cr.dispatchSimpleEvent(this, PreviewGenerator.EventType.DOCUMENT_READY);
377     },
378
379     /**
380      * Called when the preview generation fails.
381      * @private
382      */
383     onPreviewGenerationFail_: function() {
384       // NOTE: No request ID is returned from Chromium so its assumed its the
385       // current one.
386       cr.dispatchSimpleEvent(this, PreviewGenerator.EventType.FAIL);
387     }
388   };
389
390   // Export
391   return {
392     PreviewGenerator: PreviewGenerator
393   };
394 });