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.
5 cr.define('print_preview', function() {
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.
18 * @extends {cr.EventTarget}
20 function PreviewGenerator(
21 destinationStore, printTicketStore, nativeLayer, documentInfo) {
22 cr.EventTarget.call(this);
25 * Used to get the currently selected destination.
26 * @type {!print_preview.DestinationStore}
29 this.destinationStore_ = destinationStore;
32 * Used to read the state of the ticket and write document information.
33 * @type {!print_preview.PrintTicketStore}
36 this.printTicketStore_ = printTicketStore;
39 * Interface to the Chromium native layer.
40 * @type {!print_preview.NativeLayer}
43 this.nativeLayer_ = nativeLayer;
46 * Document data model.
47 * @type {!print_preview.DocumentInfo}
50 this.documentInfo_ = documentInfo;
53 * ID of current in-flight request. Requests that do not share this ID will
58 this.inFlightRequestId_ = -1;
61 * Whether the previews are being generated in landscape mode.
65 this.isLandscapeEnabled_ = false;
68 * Whether the previews are being generated with a header and footer.
72 this.isHeaderFooterEnabled_ = false;
75 * Whether the previews are being generated in color.
79 this.colorValue_ = false;
82 * Whether the document should be fitted to the page.
86 this.isFitToPageEnabled_ = false;
89 * Page ranges setting used used to generate the last preview.
90 * @type {!Array.<object.<{from: number, to: number}>>}
93 this.pageRanges_ = null;
96 * Margins type used to generate the last preview.
97 * @type {!print_preview.ticket_items.MarginsType.Value}
100 this.marginsType_ = print_preview.ticket_items.MarginsType.Value.DEFAULT;
103 * Whether the document should have element CSS backgrounds printed.
107 this.isCssBackgroundEnabled_ = false;
110 * Destination that was selected for the last preview.
111 * @type {print_preview.Destination}
114 this.selectedDestination_ = null;
117 * Event tracker used to keep track of native layer events.
118 * @type {!EventTracker}
121 this.tracker_ = new EventTracker();
123 this.addEventListeners_();
127 * Event types dispatched by the preview generator.
130 PreviewGenerator.EventType = {
131 // Dispatched when the document can be printed.
132 DOCUMENT_READY: 'print_preview.PreviewGenerator.DOCUMENT_READY',
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',
140 // Dispatched when the document preview starts to be generated.
141 PREVIEW_START: 'print_preview.PreviewGenerator.PREVIEW_START',
143 // Dispatched when the current print preview request fails.
144 FAIL: 'print_preview.PreviewGenerator.FAIL'
147 PreviewGenerator.prototype = {
148 __proto__: cr.EventTarget.prototype,
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.
155 requestPreview: function() {
156 if (!this.printTicketStore_.isTicketValidForPreview() ||
157 !this.printTicketStore_.isInitialized ||
158 !this.destinationStore_.selectedDestination) {
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();
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;
180 this.inFlightRequestId_++;
181 this.nativeLayer_.startGetPreview(
182 this.destinationStore_.selectedDestination,
183 this.printTicketStore_,
185 this.inFlightRequestId_);
189 /** Removes all event listeners that the preview generator has attached. */
190 removeEventListeners: function() {
191 this.tracker_.removeAll();
195 * Adds event listeners to the relevant native layer events.
198 addEventListeners_: function() {
201 print_preview.NativeLayer.EventType.PAGE_LAYOUT_READY,
202 this.onPageLayoutReady_.bind(this));
205 print_preview.NativeLayer.EventType.PAGE_COUNT_READY,
206 this.onPageCountReady_.bind(this));
209 print_preview.NativeLayer.EventType.PAGE_PREVIEW_READY,
210 this.onPagePreviewReady_.bind(this));
213 print_preview.NativeLayer.EventType.PREVIEW_GENERATION_DONE,
214 this.onPreviewGenerationDone_.bind(this));
217 print_preview.NativeLayer.EventType.PREVIEW_GENERATION_FAIL,
218 this.onPreviewGenerationFail_.bind(this));
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
229 * @param {number} previewUid Unique identifier of the preview.
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);
241 * Dispatches a PREVIEW_START event. Signals that the preview should be
243 * @param {number} previewUid Unique identifier of the preview.
244 * @param {number} index Index of the first page of the preview.
247 dispatchPreviewStartEvent_: function(previewUid, index) {
248 var previewStartEvent = new Event(
249 PreviewGenerator.EventType.PREVIEW_START);
250 if (!this.documentInfo_.isModifiable) {
253 previewStartEvent.previewUrl = 'chrome://print/' +
254 previewUid.toString() + '/' + index + '/print.pdf';
255 this.dispatchEvent(previewStartEvent);
259 * @return {boolean} Whether the print ticket has changed sufficiently to
260 * determine whether a new preview request should be issued.
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(),
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);
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.
294 onPageLayoutReady_: function(event) {
295 // NOTE: A request ID is not specified, so assuming its for the current
296 // in-flight request.
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);
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));
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));
318 this.documentInfo_.updatePageInfo(
319 new print_preview.PrintableArea(origin, size),
321 event.hasCustomPageSizeStyle,
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.
331 onPageCountReady_: function(event) {
332 if (this.inFlightRequestId_ != event.previewResponseId) {
333 return; // Ignore old response.
335 this.documentInfo_.updatePageCount(event.pageCount);
336 this.pageRanges_ = this.printTicketStore_.pageRange.getPageRanges();
340 * Called when a page's preview has been generated. Dispatches a
342 * @param {Event} event Contains the page index and preview UID.
345 onPagePreviewReady_: function(event) {
346 if (this.inFlightRequestId_ != event.previewResponseId) {
347 return; // Ignore old response.
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);
356 this.dispatchPageReadyEvent_(
357 previewIndex, pageNumber, event.previewUid);
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.
367 onPreviewGenerationDone_: function(event) {
368 if (this.inFlightRequestId_ != event.previewResponseId) {
369 return; // Ignore old response.
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);
376 cr.dispatchSimpleEvent(this, PreviewGenerator.EventType.DOCUMENT_READY);
380 * Called when the preview generation fails.
383 onPreviewGenerationFail_: function() {
384 // NOTE: No request ID is returned from Chromium so its assumed its the
386 cr.dispatchSimpleEvent(this, PreviewGenerator.EventType.FAIL);
392 PreviewGenerator: PreviewGenerator