WKWebView does not render PDF pages in AirPrint
authoraestes@apple.com <aestes@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Jun 2016 22:05:04 +0000 (22:05 +0000)
committeraestes@apple.com <aestes@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Jun 2016 22:05:04 +0000 (22:05 +0000)
commit90e20bbf3fda5303f8994b3095760274e19036e8
tree44263dffc1b648823a24e1822bb651e9bae9aec4
parent4647f5a1a775b3c5ceb59156a7d43ea62be666b8
WKWebView does not render PDF pages in AirPrint
https://bugs.webkit.org/show_bug.cgi?id=151386
rdar://problem/22499157

Reviewed by Tim Horton.

_WKWebViewPrintFormatter originally attempted to handle PDFs, but the code path was never
properly tested since Safari prints PDFs by setting a printingItem on the
UIPrintInteractionController instead of going through a print formatter. The existing code
almost worked, if it weren't for CGContextScaleCTM() scaling each page into oblivion due to
_totalScaleFactor equaling 0.

This patch properly implements -[_WKWebViewPrintFormatter drawInRect:forPageAtIndex:] to
handle drawing both PDFs generated by WebKit and PDFs loaded in the main frame. It also
takes the opportunity to clean up a number of issues in the existing code:

- Handling of -[_WKWebViewPrintFormatter startPage] is now correct. I had previously assumed
  this property represented the first page of output to print, but it actually represents
  the first page in the overall print job that the print formatter renders. In other words,
  regardless of -startPage, the print formatter should always print all its pages.
- Code specific to webpage and PDF printing was factored out into WKContentView and
  WKPDFView, respectively. Each conforms to @protocol(_WKWebViewPrintProvider), and
  _WKWebViewPrintFormatter accesses the provider via -[WKWebView _printProvider].
- Instead of piping the printed PDF data from WebPageProxy to WKWebView via PageClient, use
  the GenericCallback mechanism to have WebPageProxy call a lambda specified by
  WKContentView when the printed PDF is available.
- Removed _totalScaleFactor and used CGPDFPageGetDrawingTransform() to transform both
  webpages and PDFs. For webpages, _totalScaleFactor will always equal the ratio of the
  paper width to the PDF page width, so CGPDFPageGetDrawingTransform() will apply the same
  scaling as CGContextScaleCTM(_totalScaleFactor, _totalScaleFactor) would.

* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _printProvider]): Added. Returns _currentContentView if it conforms to
@protocol(_WKWebViewPrintProvider).
(-[WKWebView _computePageCountAndStartDrawingToPDFForFrame:printInfo:firstPage:computedTotalScaleFactor:]):
Moved code to _wk_pageCountForPrintFormatter in WKContentView and WKPDFView.
(-[WKWebView _endPrinting]): Deleted.
(-[WKWebView _printedDocument]): Deleted.
(-[WKWebView _setPrintedDocument:]): Deleted.
* UIProcess/API/Cocoa/WKWebViewInternal.h: Declared the _printProvider property.
* UIProcess/PageClient.h: Removed didFinishDrawingPagesToPDF().
* UIProcess/WebPageProxy.h: Declared computePagesForPrintingAndDrawToPDF() and
drawToPDFCallback().
* UIProcess/WebPageProxy.messages.in: Renamed DidFinishDrawingPagesToPDF to
DrawToPDFCallback.
* UIProcess/_WKWebViewPrintFormatter.mm: Backed the frameToPrint property with a RetainPtr
ivar so that it doesn't need to be released manually in -dealloc; removed _totalScaleFactor
and _printInfo ivars and added a _printedDocument ivar; removed the property declaration for
webView.
(-[_WKWebViewPrintFormatter frameToPrint]): Added a custom getter for the frameToPrint
property.
(-[_WKWebViewPrintFormatter setFrameToPrint:]): Added a custom setter for the frameToPrint
property.
(-[_WKWebViewPrintFormatter _webView]): Renamed from webView; added an underscore since this
is a private method.
(-[_WKWebViewPrintFormatter _recalcPageCount]): Retrieved the page count from the print
provider and clamped its value to NSIntegerMax.
(-[_WKWebViewPrintFormatter drawInRect:forPageAtIndex:]): Retrieved the printed document
from the print provider if needed; modified the CTM transformations to work for both
webpages and PDFs.
(-[_WKWebViewPrintFormatter dealloc]): Deleted.
(-[_WKWebViewPrintFormatter webView]): Renamed to _webView.
(-[_WKWebViewPrintFormatter rectForPageAtIndex:]): Deleted.
* UIProcess/_WKWebViewPrintFormatterInternal.h: Added. Moved a UIPrintFormatter internal
method declaration to here and defined the _WKWebViewPrintProvider protocol.
* UIProcess/ios/PageClientImplIOS.h: Removed didFinishDrawingPagesToPDF().
* UIProcess/ios/PageClientImplIOS.mm: Ditto.
(WebKit::PageClientImpl::didFinishDrawingPagesToPDF): Deleted.
* UIProcess/ios/WKContentView.mm: Conformed to @protocol(_WKWebViewPrintProvider).
(-[WKContentView _wk_pageCountForPrintFormatter:]): Moved the code to compute page count
from WKWebView to here.
(-[WKContentView _wk_printedDocument]): Moved the code to get the printed document from
WKWebView to here.
* UIProcess/ios/WKPDFView.mm:
(-[WKPDFView _wk_pageCountForPrintFormatter:]): Moved the code to compute the page count
from WKWebView to here; added a call to CGPDFDocumentAllowsPrinting(), returning 0 if
printing is not allowed.
(-[WKPDFView _wk_printedDocument]): Moved the code to get the printed document from
WKWebView to here.
* UIProcess/ios/WebPageProxyIOS.mm:
(WebKit::WebPageProxy::computePagesForPrintingAndDrawToPDF): Registered the callback with
m_callbacks and sent Messages::WebPage::ComputePagesForPrintingAndDrawToPDF; returned the
synchronously-returned page count.
(WebKit::WebPageProxy::drawToPDFCallback): Added to perform the callback when drawing to PDF
is complete.
(WebKit::WebPageProxy::didFinishDrawingPagesToPDF): Deleted.
* WebKit2.xcodeproj/project.pbxproj: Added _WKWebViewPrintFormatterInternal.h.
* WebProcess/WebPage/WebPage.h: Renamed computePagesForPrintingAndStartDrawingToPDF() to
computePagesForPrintingAndDrawToPDF().
* WebProcess/WebPage/WebPage.messages.in: Renamed
ComputePagesForPrintingAndStartDrawingToPDF to ComputePagesForPrintingAndDrawToPDF. Removed
the startPage parameter and added a callbackID.
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::computePagesForPrintingAndDrawToPDF): Renamed from
computePagesForPrintingAndStartDrawingToPDF(). Added a call to endPrinting() after sending
Messages::WebPageProxy::DrawToPDFCallback.
(WebKit::WebPage::computePagesForPrintingAndStartDrawingToPDF): Renamed to
computePagesForPrintingAndDrawToPDF.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@201888 268f45cc-cd09-0410-ab3c-d52691b4dbfc
17 files changed:
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit2/UIProcess/API/Cocoa/WKWebViewInternal.h
Source/WebKit2/UIProcess/PageClient.h
Source/WebKit2/UIProcess/WebPageProxy.h
Source/WebKit2/UIProcess/WebPageProxy.messages.in
Source/WebKit2/UIProcess/_WKWebViewPrintFormatter.mm
Source/WebKit2/UIProcess/_WKWebViewPrintFormatterInternal.h [new file with mode: 0644]
Source/WebKit2/UIProcess/ios/PageClientImplIOS.h
Source/WebKit2/UIProcess/ios/PageClientImplIOS.mm
Source/WebKit2/UIProcess/ios/WKContentView.mm
Source/WebKit2/UIProcess/ios/WKPDFView.mm
Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm
Source/WebKit2/WebKit2.xcodeproj/project.pbxproj
Source/WebKit2/WebProcess/WebPage/WebPage.h
Source/WebKit2/WebProcess/WebPage/WebPage.messages.in
Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm