2011-02-04 Dimitri Glazkov <dglazkov@chromium.org>
[WebKit.git] / Source / WebKit2 / UIProcess / API / mac / WKPrintingView.mm
1 /*
2  * Copyright (C) 2011 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "WKPrintingView.h"
28
29 #import "Logging.h"
30 #import "PrintInfo.h"
31 #import "WebData.h"
32 #import "WebPageProxy.h"
33
34 using namespace WebKit;
35 using namespace WebCore;
36
37 NSString * const WebKitOriginalTopPrintingMarginKey = @"WebKitOriginalTopMargin";
38 NSString * const WebKitOriginalBottomPrintingMarginKey = @"WebKitOriginalBottomMargin";
39
40 NSString * const NSPrintInfoDidChangeNotification = @"NSPrintInfoDidChange";
41
42 @implementation WKPrintingView
43
44 - (id)initWithFrameProxy:(WebFrameProxy*)frame
45 {
46     self = [super init]; // No frame rect to pass to NSView.
47     if (!self)
48         return nil;
49
50     _webFrame = frame;
51
52     return self;
53 }
54
55 - (BOOL)isFlipped
56 {
57     return YES;
58 }
59
60 - (void)_adjustPrintingMarginsForHeaderAndFooter
61 {
62     NSPrintInfo *info = [_printOperation printInfo];
63     NSMutableDictionary *infoDictionary = [info dictionary];
64
65     // We need to modify the top and bottom margins in the NSPrintInfo to account for the space needed by the
66     // header and footer. Because this method can be called more than once on the same NSPrintInfo (see 5038087),
67     // we stash away the unmodified top and bottom margins the first time this method is called, and we read from
68     // those stashed-away values on subsequent calls.
69     double originalTopMargin;
70     double originalBottomMargin;
71     NSNumber *originalTopMarginNumber = [infoDictionary objectForKey:WebKitOriginalTopPrintingMarginKey];
72     if (!originalTopMarginNumber) {
73         ASSERT(![infoDictionary objectForKey:WebKitOriginalBottomPrintingMarginKey]);
74         originalTopMargin = [info topMargin];
75         originalBottomMargin = [info bottomMargin];
76         [infoDictionary setObject:[NSNumber numberWithDouble:originalTopMargin] forKey:WebKitOriginalTopPrintingMarginKey];
77         [infoDictionary setObject:[NSNumber numberWithDouble:originalBottomMargin] forKey:WebKitOriginalBottomPrintingMarginKey];
78     } else {
79         ASSERT([originalTopMarginNumber isKindOfClass:[NSNumber class]]);
80         ASSERT([[infoDictionary objectForKey:WebKitOriginalBottomPrintingMarginKey] isKindOfClass:[NSNumber class]]);
81         originalTopMargin = [originalTopMarginNumber doubleValue];
82         originalBottomMargin = [[infoDictionary objectForKey:WebKitOriginalBottomPrintingMarginKey] doubleValue];
83     }
84     
85     CGFloat scale = [info scalingFactor];
86     [info setTopMargin:originalTopMargin + _webFrame->page()->headerHeight(_webFrame.get()) * scale];
87     [info setBottomMargin:originalBottomMargin + _webFrame->page()->footerHeight(_webFrame.get()) * scale];
88 }
89
90 - (BOOL)_isPrintingPreview
91 {
92     // <rdar://problem/8901041> Please add an API returning whether the current print operation is for preview.
93     // Assuming that if NSPrintOperation is allowed to spawn a thread for printing, it will. Print preview doesn't spawn a thread.
94     return !_isPrintingFromSecondaryThread;
95 }
96
97 - (void)_updatePreview
98 {
99     // <rdar://problem/8900923> Please add an API to force print preview update.
100     _isForcingPreviewUpdate = YES;
101     [[NSNotificationCenter defaultCenter] postNotificationName:NSPrintInfoDidChangeNotification object:nil];
102     _isForcingPreviewUpdate = NO;
103 }
104
105 - (BOOL)_hasPageRects
106 {
107     // WebCore always prints at least one page.
108     return !_printingPageRects.isEmpty();
109 }
110
111 - (NSUInteger)_firstPrintedPageNumber
112 {
113     // Need to directly access the dictionary because -[NSPrintOperation pageRange] verifies pagination, potentially causing recursion.
114     return [[[[_printOperation printInfo] dictionary] objectForKey:NSPrintFirstPage] unsignedIntegerValue];
115 }
116
117 - (NSUInteger)_lastPrintedPageNumber
118 {
119     ASSERT([self _hasPageRects]);
120
121     // Need to directly access the dictionary because -[NSPrintOperation pageRange] verifies pagination, potentially causing recursion.
122     NSUInteger firstPage = [[[[_printOperation printInfo] dictionary] objectForKey:NSPrintFirstPage] unsignedIntegerValue];
123     NSUInteger lastPage = [[[[_printOperation printInfo] dictionary] objectForKey:NSPrintLastPage] unsignedIntegerValue];
124     if (lastPage - firstPage >= _printingPageRects.size())
125         return _printingPageRects.size();
126     return lastPage;
127 }
128
129 - (uint64_t)_expectedPreviewCallbackForRect:(const IntRect&)rect
130 {
131     for (HashMap<uint64_t, WebCore::IntRect>::iterator iter = _expectedPreviewCallbacks.begin(); iter != _expectedPreviewCallbacks.end(); ++iter) {
132         if (iter->second  == rect)
133             return iter->first;
134     }
135     return 0;
136 }
137
138 struct IPCCallbackContext {
139     RetainPtr<WKPrintingView> view;
140     uint64_t callbackID;
141 };
142
143 static void pageDidDrawToPDF(WKDataRef dataRef, WKErrorRef, void* untypedContext)
144 {
145     ASSERT(isMainThread());
146
147     OwnPtr<IPCCallbackContext> context = adoptPtr(static_cast<IPCCallbackContext*>(untypedContext));
148     WKPrintingView *view = context->view.get();
149     WebData* data = toImpl(dataRef);
150
151     if (context->callbackID == view->_expectedPrintCallback) {
152         ASSERT(![view _isPrintingPreview]);
153         ASSERT(view->_printedPagesData.isEmpty());
154         ASSERT(!view->_printedPagesPDFDocument);
155         if (data)
156             view->_printedPagesData.append(data->bytes(), data->size());
157         view->_expectedPrintCallback = 0;
158         view->_printingCallbackCondition.signal();
159     } else {
160         // If the user has already changed print setup, then this response is obsolete. And this callback is not in response to the latest request,
161         // then the user has already moved to another page - we'll cache the response, but won't draw it.
162         HashMap<uint64_t, WebCore::IntRect>::iterator iter = view->_expectedPreviewCallbacks.find(context->callbackID);
163         if (iter != view->_expectedPreviewCallbacks.end()) {
164             ASSERT([view _isPrintingPreview]);
165
166             if (data) {
167                 pair<HashMap<WebCore::IntRect, Vector<uint8_t> >::iterator, bool> entry = view->_pagePreviews.add(iter->second, Vector<uint8_t>());
168                 entry.first->second.append(data->bytes(), data->size());
169             }
170             bool receivedResponseToLatestRequest = view->_latestExpectedPreviewCallback == context->callbackID;
171             view->_latestExpectedPreviewCallback = 0;
172             view->_expectedPreviewCallbacks.remove(context->callbackID);
173             if (receivedResponseToLatestRequest)
174                 [view _updatePreview];
175         }
176     }
177 }
178
179 - (void)_preparePDFDataForPrintingOnSecondaryThread
180 {
181     ASSERT(isMainThread());
182
183     if (!_webFrame->page()) {
184         _printingCallbackCondition.signal();
185         return;
186     }
187
188     MutexLocker lock(_printingCallbackMutex);
189
190     ASSERT([self _hasPageRects]);
191     ASSERT(_printedPagesData.isEmpty());
192     ASSERT(!_printedPagesPDFDocument);
193     ASSERT(!_expectedPrintCallback);
194
195     NSUInteger firstPage = [self _firstPrintedPageNumber];
196     NSUInteger lastPage = [self _lastPrintedPageNumber];
197
198     ASSERT(firstPage > 0);
199     ASSERT(firstPage <= lastPage);
200     LOG(View, "WKPrintingView requesting PDF data for pages %u...%u", firstPage, lastPage);
201
202     // Return to printing mode if we're already back to screen (e.g. due to window resizing).
203     _webFrame->page()->beginPrinting(_webFrame.get(), PrintInfo([_printOperation printInfo]));
204
205     IPCCallbackContext* context = new IPCCallbackContext;
206     RefPtr<DataCallback> callback = DataCallback::create(context, pageDidDrawToPDF);
207     _expectedPrintCallback = callback->callbackID();
208
209     context->view = self;
210     context->callbackID = callback->callbackID();
211
212     _webFrame->page()->drawPagesToPDF(_webFrame.get(), firstPage - 1, lastPage - firstPage + 1, callback.get());
213 }
214
215 static void pageDidComputePageRects(const Vector<WebCore::IntRect>& pageRects, double totalScaleFactorForPrinting, WKErrorRef, void* untypedContext)
216 {
217     ASSERT(isMainThread());
218
219     OwnPtr<IPCCallbackContext> context = adoptPtr(static_cast<IPCCallbackContext*>(untypedContext));
220     WKPrintingView *view = context->view.get();
221
222     // If the user has already changed print setup, then this response is obsolete.
223     if (context->callbackID == view->_expectedComputedPagesCallback) {
224         ASSERT(isMainThread());
225         ASSERT(view->_expectedPreviewCallbacks.isEmpty());
226         ASSERT(!view->_latestExpectedPreviewCallback);
227         ASSERT(!view->_expectedPrintCallback);
228         ASSERT(view->_pagePreviews.isEmpty());
229         view->_expectedComputedPagesCallback = 0;
230
231         view->_printingPageRects = pageRects;
232         view->_totalScaleFactorForPrinting = totalScaleFactorForPrinting;
233
234         const IntRect& lastPrintingPageRect = view->_printingPageRects[view->_printingPageRects.size() - 1];
235         NSRect newFrameSize = NSMakeRect(0, 0, 
236             ceil(lastPrintingPageRect.maxX() * view->_totalScaleFactorForPrinting), 
237             ceil(lastPrintingPageRect.maxY() * view->_totalScaleFactorForPrinting));
238         LOG(View, "WKPrintingView setting frame size to x:%g y:%g width:%g height:%g", newFrameSize.origin.x, newFrameSize.origin.y, newFrameSize.size.width, newFrameSize.size.height);
239         [view setFrame:newFrameSize];
240
241         if ([view _isPrintingPreview]) {
242             // Show page count, and ask for an actual image to replace placeholder.
243             [view _updatePreview];
244         } else {
245             // When printing, request everything we'll need beforehand.
246             [view _preparePDFDataForPrintingOnSecondaryThread];
247         }
248     }
249 }
250
251 - (BOOL)_askPageToComputePageRects
252 {
253     ASSERT(isMainThread());
254
255     if (!_webFrame->page())
256         return NO;
257
258     ASSERT(!_expectedComputedPagesCallback);
259
260     IPCCallbackContext* context = new IPCCallbackContext;
261     RefPtr<ComputedPagesCallback> callback = ComputedPagesCallback::create(context, pageDidComputePageRects);
262     _expectedComputedPagesCallback = callback->callbackID();
263     context->view = self;
264     context->callbackID = _expectedComputedPagesCallback;
265
266     _webFrame->page()->computePagesForPrinting(_webFrame.get(), PrintInfo([_printOperation printInfo]), callback.release());
267     return YES;
268 }
269
270 static void prepareDataForPrintingOnSecondaryThread(void* untypedContext)
271 {
272     ASSERT(isMainThread());
273
274     WKPrintingView *view = static_cast<WKPrintingView *>(untypedContext);
275     MutexLocker lock(view->_printingCallbackMutex);
276
277     // We may have received page rects while a message to call this function traveled from secondary thread to main one.
278     if ([view _hasPageRects]) {
279         [view _preparePDFDataForPrintingOnSecondaryThread];
280         return;
281     }
282
283     // A request for pages has already been made, just wait for it to finish.
284     if (view->_expectedComputedPagesCallback)
285         return;
286
287     [view _askPageToComputePageRects];
288 }
289
290 - (BOOL)knowsPageRange:(NSRangePointer)range
291 {
292     LOG(View, "-[WKPrintingView knowsPageRange:], %s, %s", [self _hasPageRects] ? "print data is available" : "print data is not available yet", isMainThread() ? "on main thread" : "on secondary thread");
293     ASSERT(_printOperation == [NSPrintOperation currentOperation]);
294
295     // Assuming that once we switch to printing from a secondary thread, we don't go back.
296     ASSERT(!_isPrintingFromSecondaryThread || !isMainThread());
297     if (!isMainThread())
298         _isPrintingFromSecondaryThread = YES;
299
300     [self _adjustPrintingMarginsForHeaderAndFooter];
301
302     if ([self _hasPageRects])
303         *range = NSMakeRange(1, _printingPageRects.size());
304     else if (!isMainThread()) {
305         ASSERT(![self _isPrintingPreview]);
306         MutexLocker lock(_printingCallbackMutex);
307         callOnMainThread(prepareDataForPrintingOnSecondaryThread, self);
308         _printingCallbackCondition.wait(_printingCallbackMutex);
309         *range = NSMakeRange(1, _printingPageRects.size());
310     } else {
311         ASSERT([self _isPrintingPreview]);
312
313         [self _askPageToComputePageRects];
314
315         *range = NSMakeRange(1, NSIntegerMax);
316     }
317     return YES;
318 }
319
320 - (unsigned)_pageForRect:(NSRect)rect
321 {
322     // Assuming that rect exactly matches one of the pages.
323     for (size_t i = 0; i < _printingPageRects.size(); ++i) {
324         IntRect currentRect(_printingPageRects[i]);
325         currentRect.scale(_totalScaleFactorForPrinting);
326         if (rect.origin.y == currentRect.y() && rect.origin.x == currentRect.x())
327             return i + 1;
328     }
329     ASSERT_NOT_REACHED();
330     return 0; // Invalid page number.
331 }
332
333 - (void)_drawPDFDocument:(CGPDFDocumentRef)pdfDocument page:(unsigned)page atPoint:(NSPoint)point
334 {
335     if (!pdfDocument) {
336         LOG_ERROR("Couldn't create a PDF document with data passed for preview");
337         return;
338     }
339
340     CGPDFPageRef pdfPage = CGPDFDocumentGetPage(pdfDocument, page);
341     if (!pdfPage) {
342         LOG_ERROR("Preview data doesn't have page %d", page);
343         return;
344     }
345
346     NSGraphicsContext *nsGraphicsContext = [NSGraphicsContext currentContext];
347     CGContextRef context = static_cast<CGContextRef>([nsGraphicsContext graphicsPort]);
348
349     CGContextSaveGState(context);
350     CGContextTranslateCTM(context, point.x, point.y);
351     CGContextScaleCTM(context, _totalScaleFactorForPrinting, -_totalScaleFactorForPrinting);
352     CGContextTranslateCTM(context, 0, -CGPDFPageGetBoxRect(pdfPage, kCGPDFMediaBox).size.height);
353     CGContextDrawPDFPage(context, pdfPage);
354     CGContextRestoreGState(context);
355 }
356
357 - (void)_drawPreview:(NSRect)nsRect
358 {
359     ASSERT(isMainThread());
360
361     IntRect rect(nsRect);
362     rect.scale(1 / _totalScaleFactorForPrinting);
363     HashMap<WebCore::IntRect, Vector<uint8_t> >::iterator pagePreviewIterator = _pagePreviews.find(rect);
364     if (pagePreviewIterator == _pagePreviews.end())  {
365         // It's too early to ask for page preview if we don't even know page size and scale.
366         if ([self _hasPageRects]) {
367             if (uint64_t existingCallback = [self _expectedPreviewCallbackForRect:rect]) {
368                 // We've already asked for a preview of this page, and are waiting for response.
369                 // There is no need to ask again.
370                 _latestExpectedPreviewCallback = existingCallback;
371             } else {
372                 // Preview isn't available yet, request it asynchronously.
373                 if (!_webFrame->page())
374                     return;
375
376                 // Return to printing mode if we're already back to screen (e.g. due to window resizing).
377                 _webFrame->page()->beginPrinting(_webFrame.get(), PrintInfo([_printOperation printInfo]));
378
379                 IPCCallbackContext* context = new IPCCallbackContext;
380                 RefPtr<DataCallback> callback = DataCallback::create(context, pageDidDrawToPDF);
381                 _latestExpectedPreviewCallback = callback->callbackID();
382                 _expectedPreviewCallbacks.add(_latestExpectedPreviewCallback, rect);
383
384                 context->view = self;
385                 context->callbackID = callback->callbackID();
386
387                 _webFrame->page()->drawRectToPDF(_webFrame.get(), rect, callback.get());
388                 return;
389             }
390         }
391
392         // FIXME: Draw a placeholder
393         return;
394     }
395
396     const Vector<uint8_t>& pdfData = pagePreviewIterator->second;
397     RetainPtr<CGDataProviderRef> pdfDataProvider(AdoptCF, CGDataProviderCreateWithData(0, pdfData.data(), pdfData.size(), 0));
398     RetainPtr<CGPDFDocumentRef> pdfDocument(AdoptCF, CGPDFDocumentCreateWithProvider(pdfDataProvider.get()));
399
400     [self _drawPDFDocument:pdfDocument.get() page:1 atPoint:NSMakePoint(nsRect.origin.x, nsRect.origin.y)];
401 }
402
403 - (void)drawRect:(NSRect)nsRect
404 {
405     LOG(View, "WKPrintingView printing rect x:%g, y:%g, width:%g, height:%g%s", nsRect.origin.x, nsRect.origin.y, nsRect.size.width, nsRect.size.height, [self _isPrintingPreview] ? " for preview" : "");
406
407     ASSERT(_printOperation == [NSPrintOperation currentOperation]);
408
409     if (!_webFrame->page())
410         return;
411
412     if ([self _isPrintingPreview]) {
413         [self _drawPreview:nsRect];
414         return;
415     }
416
417     ASSERT(!isMainThread());
418     ASSERT(!_printedPagesData.isEmpty()); // Prepared by knowsPageRange:
419
420     if (!_printedPagesPDFDocument) {
421         RetainPtr<CGDataProviderRef> pdfDataProvider(AdoptCF, CGDataProviderCreateWithData(0, _printedPagesData.data(), _printedPagesData.size(), 0));
422         _printedPagesPDFDocument.adoptCF(CGPDFDocumentCreateWithProvider(pdfDataProvider.get()));
423     }
424
425     unsigned printedPageNumber = [self _pageForRect:nsRect] - [self _firstPrintedPageNumber] + 1;
426     [self _drawPDFDocument:_printedPagesPDFDocument.get() page:printedPageNumber atPoint:NSMakePoint(nsRect.origin.x, nsRect.origin.y)];
427 }
428
429 - (void)_drawPageBorderWithSizeOnMainThread:(NSSize)borderSize
430 {
431     ASSERT(isMainThread());
432
433     // When printing from a secondary thread, the main thread doesn't have graphics context and printing operation set up.
434     NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
435     [NSGraphicsContext setCurrentContext:[_printOperation context]];
436
437     ASSERT(![NSPrintOperation currentOperation]);
438     [NSPrintOperation setCurrentOperation:_printOperation];
439
440     [self drawPageBorderWithSize:borderSize];
441
442     [NSPrintOperation setCurrentOperation:nil];
443     [NSGraphicsContext setCurrentContext:currentContext];
444 }
445
446 - (void)drawPageBorderWithSize:(NSSize)borderSize
447 {
448     ASSERT(NSEqualSizes(borderSize, [[_printOperation printInfo] paperSize]));    
449     ASSERT(_printOperation == [NSPrintOperation currentOperation]);
450
451     if (!isMainThread()) {
452         // Don't call the client from a secondary thread.
453         NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[WKPrintingView instanceMethodSignatureForSelector:@selector(_drawPageBorderWithSizeOnMainThread:)]];
454         [invocation setSelector:@selector(_drawPageBorderWithSizeOnMainThread:)];
455         [invocation setArgument:&borderSize atIndex:2];
456         [invocation performSelectorOnMainThread:@selector(invokeWithTarget:) withObject:self waitUntilDone:YES];
457         return;
458     }
459
460     if (!_webFrame->page())
461         return;
462
463     // The header and footer rect height scales with the page, but the width is always
464     // all the way across the printed page (inset by printing margins).
465     NSPrintInfo *printInfo = [_printOperation printInfo];
466     CGFloat scale = [printInfo scalingFactor];
467     NSSize paperSize = [printInfo paperSize];
468     CGFloat headerFooterLeft = [printInfo leftMargin] / scale;
469     CGFloat headerFooterWidth = (paperSize.width - ([printInfo leftMargin] + [printInfo rightMargin])) / scale;
470     NSRect footerRect = NSMakeRect(headerFooterLeft, [printInfo bottomMargin] / scale - _webFrame->page()->footerHeight(_webFrame.get()), headerFooterWidth, _webFrame->page()->footerHeight(_webFrame.get()));
471     NSRect headerRect = NSMakeRect(headerFooterLeft, (paperSize.height - [printInfo topMargin]) / scale, headerFooterWidth, _webFrame->page()->headerHeight(_webFrame.get()));
472
473     NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
474     [currentContext saveGraphicsState];
475     NSRectClip(headerRect);
476     _webFrame->page()->drawHeader(_webFrame.get(), headerRect);
477     [currentContext restoreGraphicsState];
478
479     [currentContext saveGraphicsState];
480     NSRectClip(footerRect);
481     _webFrame->page()->drawFooter(_webFrame.get(), footerRect);
482     [currentContext restoreGraphicsState];
483 }
484
485 - (NSRect)rectForPage:(NSInteger)page
486 {
487     ASSERT(_printOperation == [NSPrintOperation currentOperation]);
488     if (![self _hasPageRects]) {
489         LOG(View, "-[WKPrintingView rectForPage:%d] - data is not yet available", (int)page);
490         // We must be still calculating the page range.
491         ASSERT(_expectedComputedPagesCallback);
492         return NSMakeRect(0, 0, 1, 1);
493     }
494
495     IntRect rect = _printingPageRects[page - 1];
496     rect.scale(_totalScaleFactorForPrinting);
497     LOG(View, "-[WKPrintingView rectForPage:%d] -> x %d, y %d, width %d, height %d", (int)page, rect.x(), rect.y(), rect.width(), rect.height());
498     return rect;
499 }
500
501 // Temporary workaround for <rdar://problem/8944535>. Force correct printout positioning.
502 - (NSPoint)locationOfPrintRect:(NSRect)aRect
503 {
504     ASSERT(_printOperation == [NSPrintOperation currentOperation]);
505     return NSMakePoint([[_printOperation printInfo] leftMargin], [[_printOperation printInfo] bottomMargin]);
506 }
507
508 - (void)beginDocument
509 {
510     ASSERT(_printOperation == [NSPrintOperation currentOperation]);
511
512     // Forcing preview update gets us here, but page setup hasn't actually changed.
513     if (_isForcingPreviewUpdate)
514         return;
515
516     [super beginDocument];
517
518     _webFrame->page()->setAutodisplay(false);
519 }
520
521 - (void)endDocument
522 {
523     ASSERT(_printOperation == [NSPrintOperation currentOperation]);
524
525     // Forcing preview update gets us here, but page setup hasn't actually changed.
526     if (_isForcingPreviewUpdate)
527         return;
528
529     LOG(View, "-[WKPrintingView endDocument] - clearing cached data");
530
531     // Both existing data and pending responses are now obsolete.
532     _printingPageRects.clear();
533     _totalScaleFactorForPrinting = 1;
534     _pagePreviews.clear();
535     _printedPagesData.clear();
536     _printedPagesPDFDocument = nullptr;
537     _expectedComputedPagesCallback = 0;
538     _expectedPreviewCallbacks.clear();
539     _latestExpectedPreviewCallback = 0;
540     _expectedPrintCallback = 0;
541
542     _webFrame->page()->setAutodisplay(true);
543
544     [super endDocument];
545 }
546 @end