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 * Media size to generate preview with. {@code null} indicates default size.
62 * @type {cp.cdd.MediaSizeTicketItem}
65 this.mediaSize_
= null;
68 * Whether the previews are being generated in landscape mode.
72 this.isLandscapeEnabled_
= false;
75 * Whether the previews are being generated with a header and footer.
79 this.isHeaderFooterEnabled_
= false;
82 * Whether the previews are being generated in color.
86 this.colorValue_
= false;
89 * Whether the document should be fitted to the page.
93 this.isFitToPageEnabled_
= false;
96 * Page ranges setting used used to generate the last preview.
97 * @type {!Array<object<{from: number, to: number}>>}
100 this.pageRanges_
= null;
103 * Margins type used to generate the last preview.
104 * @type {!print_preview.ticket_items.MarginsType.Value}
107 this.marginsType_
= print_preview
.ticket_items
.MarginsType
.Value
.DEFAULT
;
110 * Whether the document should have element CSS backgrounds printed.
114 this.isCssBackgroundEnabled_
= false;
117 * Destination that was selected for the last preview.
118 * @type {print_preview.Destination}
121 this.selectedDestination_
= null;
124 * Event tracker used to keep track of native layer events.
125 * @type {!EventTracker}
128 this.tracker_
= new EventTracker();
130 this.addEventListeners_();
134 * Event types dispatched by the preview generator.
137 PreviewGenerator
.EventType
= {
138 // Dispatched when the document can be printed.
139 DOCUMENT_READY
: 'print_preview.PreviewGenerator.DOCUMENT_READY',
141 // Dispatched when a page preview is ready. The previewIndex field of the
142 // event is the index of the page in the modified document, not the
143 // original. So page 4 of the original document might be previewIndex = 0 of
144 // the modified document.
145 PAGE_READY
: 'print_preview.PreviewGenerator.PAGE_READY',
147 // Dispatched when the document preview starts to be generated.
148 PREVIEW_START
: 'print_preview.PreviewGenerator.PREVIEW_START',
150 // Dispatched when the current print preview request fails.
151 FAIL
: 'print_preview.PreviewGenerator.FAIL'
154 PreviewGenerator
.prototype = {
155 __proto__
: cr
.EventTarget
.prototype,
158 * Request that new preview be generated. A preview request will not be
159 * generated if the print ticket has not changed sufficiently.
160 * @return {boolean} Whether a new preview was actually requested.
162 requestPreview: function() {
163 if (!this.printTicketStore_
.isTicketValidForPreview() ||
164 !this.printTicketStore_
.isInitialized
||
165 !this.destinationStore_
.selectedDestination
) {
168 if (!this.hasPreviewChanged_()) {
169 // Changes to these ticket items might not trigger a new preview, but
170 // they still need to be recorded.
171 this.marginsType_
= this.printTicketStore_
.marginsType
.getValue();
174 this.mediaSize_
= this.printTicketStore_
.mediaSize
.getValue();
175 this.isLandscapeEnabled_
= this.printTicketStore_
.landscape
.getValue();
176 this.isHeaderFooterEnabled_
=
177 this.printTicketStore_
.headerFooter
.getValue();
178 this.colorValue_
= this.printTicketStore_
.color
.getValue();
179 this.isFitToPageEnabled_
= this.printTicketStore_
.fitToPage
.getValue();
180 this.pageRanges_
= this.printTicketStore_
.pageRange
.getPageRanges();
181 this.marginsType_
= this.printTicketStore_
.marginsType
.getValue();
182 this.isCssBackgroundEnabled_
=
183 this.printTicketStore_
.cssBackground
.getValue();
184 this.isSelectionOnlyEnabled_
=
185 this.printTicketStore_
.selectionOnly
.getValue();
186 this.selectedDestination_
= this.destinationStore_
.selectedDestination
;
188 this.inFlightRequestId_
++;
189 this.nativeLayer_
.startGetPreview(
190 this.destinationStore_
.selectedDestination
,
191 this.printTicketStore_
,
193 this.inFlightRequestId_
);
197 /** Removes all event listeners that the preview generator has attached. */
198 removeEventListeners: function() {
199 this.tracker_
.removeAll();
203 * Adds event listeners to the relevant native layer events.
206 addEventListeners_: function() {
209 print_preview
.NativeLayer
.EventType
.PAGE_LAYOUT_READY
,
210 this.onPageLayoutReady_
.bind(this));
213 print_preview
.NativeLayer
.EventType
.PAGE_COUNT_READY
,
214 this.onPageCountReady_
.bind(this));
217 print_preview
.NativeLayer
.EventType
.PAGE_PREVIEW_READY
,
218 this.onPagePreviewReady_
.bind(this));
221 print_preview
.NativeLayer
.EventType
.PREVIEW_GENERATION_DONE
,
222 this.onPreviewGenerationDone_
.bind(this));
225 print_preview
.NativeLayer
.EventType
.PREVIEW_GENERATION_FAIL
,
226 this.onPreviewGenerationFail_
.bind(this));
230 * Dispatches a PAGE_READY event to signal that a page preview is ready.
231 * @param {number} previewIndex Index of the page with respect to the pages
232 * shown in the preview. E.g an index of 0 is the first displayed page,
233 * but not necessarily the first original document page.
234 * @param {number} pageNumber Number of the page with respect to the
235 * document. A value of 3 means it's the third page of the original
237 * @param {number} previewUid Unique identifier of the preview.
240 dispatchPageReadyEvent_: function(previewIndex
, pageNumber
, previewUid
) {
241 var pageGenEvent
= new Event(PreviewGenerator
.EventType
.PAGE_READY
);
242 pageGenEvent
.previewIndex
= previewIndex
;
243 pageGenEvent
.previewUrl
= 'chrome://print/' + previewUid
.toString() +
244 '/' + (pageNumber
- 1) + '/print.pdf';
245 this.dispatchEvent(pageGenEvent
);
249 * Dispatches a PREVIEW_START event. Signals that the preview should be
251 * @param {number} previewUid Unique identifier of the preview.
252 * @param {number} index Index of the first page of the preview.
255 dispatchPreviewStartEvent_: function(previewUid
, index
) {
256 var previewStartEvent
= new Event(
257 PreviewGenerator
.EventType
.PREVIEW_START
);
258 if (!this.documentInfo_
.isModifiable
) {
261 previewStartEvent
.previewUrl
= 'chrome://print/' +
262 previewUid
.toString() + '/' + index
+ '/print.pdf';
263 this.dispatchEvent(previewStartEvent
);
267 * @return {boolean} Whether the print ticket has changed sufficiently to
268 * determine whether a new preview request should be issued.
271 hasPreviewChanged_: function() {
272 var ticketStore
= this.printTicketStore_
;
273 return this.inFlightRequestId_
== -1 ||
274 !ticketStore
.mediaSize
.isValueEqual(this.mediaSize_
) ||
275 !ticketStore
.landscape
.isValueEqual(this.isLandscapeEnabled_
) ||
276 !ticketStore
.headerFooter
.isValueEqual(this.isHeaderFooterEnabled_
) ||
277 !ticketStore
.color
.isValueEqual(this.colorValue_
) ||
278 !ticketStore
.fitToPage
.isValueEqual(this.isFitToPageEnabled_
) ||
279 this.pageRanges_
== null ||
280 !areRangesEqual(ticketStore
.pageRange
.getPageRanges(),
282 (!ticketStore
.marginsType
.isValueEqual(this.marginsType_
) &&
283 !ticketStore
.marginsType
.isValueEqual(
284 print_preview
.ticket_items
.MarginsType
.Value
.CUSTOM
)) ||
285 (ticketStore
.marginsType
.isValueEqual(
286 print_preview
.ticket_items
.MarginsType
.Value
.CUSTOM
) &&
287 !ticketStore
.customMargins
.isValueEqual(
288 this.documentInfo_
.margins
)) ||
289 !ticketStore
.cssBackground
.isValueEqual(
290 this.isCssBackgroundEnabled_
) ||
291 !ticketStore
.selectionOnly
.isValueEqual(
292 this.isSelectionOnlyEnabled_
) ||
293 (this.selectedDestination_
!=
294 this.destinationStore_
.selectedDestination
);
298 * Called when the page layout of the document is ready. Always occurs
299 * as a result of a preview request.
300 * @param {Event} event Contains layout info about the document.
303 onPageLayoutReady_: function(event
) {
304 // NOTE: A request ID is not specified, so assuming its for the current
305 // in-flight request.
307 var origin
= new print_preview
.Coordinate2d(
308 event
.pageLayout
.printableAreaX
,
309 event
.pageLayout
.printableAreaY
);
310 var size
= new print_preview
.Size(
311 event
.pageLayout
.printableAreaWidth
,
312 event
.pageLayout
.printableAreaHeight
);
314 var margins
= new print_preview
.Margins(
315 Math
.round(event
.pageLayout
.marginTop
),
316 Math
.round(event
.pageLayout
.marginRight
),
317 Math
.round(event
.pageLayout
.marginBottom
),
318 Math
.round(event
.pageLayout
.marginLeft
));
320 var o
= print_preview
.ticket_items
.CustomMargins
.Orientation
;
321 var pageSize
= new print_preview
.Size(
322 event
.pageLayout
.contentWidth
+
323 margins
.get(o
.LEFT
) + margins
.get(o
.RIGHT
),
324 event
.pageLayout
.contentHeight
+
325 margins
.get(o
.TOP
) + margins
.get(o
.BOTTOM
));
327 this.documentInfo_
.updatePageInfo(
328 new print_preview
.PrintableArea(origin
, size
),
330 event
.hasCustomPageSizeStyle
,
335 * Called when the document page count is received from the native layer.
336 * Always occurs as a result of a preview request.
337 * @param {Event} event Contains the document's page count.
340 onPageCountReady_: function(event
) {
341 if (this.inFlightRequestId_
!= event
.previewResponseId
) {
342 return; // Ignore old response.
344 this.documentInfo_
.updatePageCount(event
.pageCount
);
345 this.pageRanges_
= this.printTicketStore_
.pageRange
.getPageRanges();
349 * Called when a page's preview has been generated. Dispatches a
351 * @param {Event} event Contains the page index and preview UID.
354 onPagePreviewReady_: function(event
) {
355 if (this.inFlightRequestId_
!= event
.previewResponseId
) {
356 return; // Ignore old response.
358 var pageNumber
= event
.pageIndex
+ 1;
359 var pageNumberSet
= this.printTicketStore_
.pageRange
.getPageNumberSet();
360 if (pageNumberSet
.hasPageNumber(pageNumber
)) {
361 var previewIndex
= pageNumberSet
.getPageNumberIndex(pageNumber
);
362 if (previewIndex
== 0) {
363 this.dispatchPreviewStartEvent_(event
.previewUid
, event
.pageIndex
);
365 this.dispatchPageReadyEvent_(
366 previewIndex
, pageNumber
, event
.previewUid
);
371 * Called when the preview generation is complete. Dispatches a
372 * DOCUMENT_READY event.
373 * @param {Event} event Contains the preview UID and response ID.
376 onPreviewGenerationDone_: function(event
) {
377 if (this.inFlightRequestId_
!= event
.previewResponseId
) {
378 return; // Ignore old response.
380 // Dispatch a PREVIEW_START event since non-modifiable documents don't
381 // trigger PAGE_READY events.
382 if (!this.documentInfo_
.isModifiable
) {
383 this.dispatchPreviewStartEvent_(event
.previewUid
, 0);
385 cr
.dispatchSimpleEvent(this, PreviewGenerator
.EventType
.DOCUMENT_READY
);
389 * Called when the preview generation fails.
392 onPreviewGenerationFail_: function() {
393 // NOTE: No request ID is returned from Chromium so its assumed its the
395 cr
.dispatchSimpleEvent(this, PreviewGenerator
.EventType
.FAIL
);
401 PreviewGenerator
: PreviewGenerator