Title: [104377] trunk/Source/WebKit2
Revision
104377
Author
[email protected]
Date
2012-01-06 22:57:32 -0800 (Fri, 06 Jan 2012)

Log Message

REGRESSION (WebKit2): Save as PDF no longer generates links to URLs
<http://webkit.org/b/65076> / <rdar://problem/9606246>

WebKit2 printing works by having the web process render the page content to a PDF. The PDF
data is then shipped to the UI process which will render it in to the printing graphics context.
Links were being lost because the API used to do the rendering of the PDF in to the printing
graphics context, CGContextDrawPDFPage, did not preserve the links that were present in the
PDF content received from the web process.

To fix this we switch to using PDFKit for drawing the PDF in to the printing graphics context.
PDFKit provides the ability for us to iterate over the links in the PDF content ourselves and
add links in to the printing graphics context.

Reviewed by Alexey Proskuryakov.

* UIProcess/API/mac/WKPrintingView.h:
* UIProcess/API/mac/WKPrintingView.mm:
(pdfAnnotationLinkClass): Look up the PDFAnnotationLink class from PDFKit as WebKit2 loads PDFKit lazily.
(pdfDocumentClass): Ditto.
(-[WKPrintingView _drawPDFDocument:page:atPoint:]): Switch to using the PDFKit equivalents of several types.
Iterate over the annotations present in the PDFPage, calling CGPDFContextSetURLForRect for each PDFAnnotationLink
that we find.
(-[WKPrintingView _drawPreview:]): Create an NSData to feed to PDFDocument.
(-[WKPrintingView drawRect:]): Ditto.
* WebKit2Prefix.h: Add the usual workaround to make Objective-C exceptions compile when C++ exception handling is disabled.

Modified Paths

Diff

Modified: trunk/Source/WebKit2/ChangeLog (104376 => 104377)


--- trunk/Source/WebKit2/ChangeLog	2012-01-07 06:46:50 UTC (rev 104376)
+++ trunk/Source/WebKit2/ChangeLog	2012-01-07 06:57:32 UTC (rev 104377)
@@ -1,3 +1,31 @@
+2012-01-06  Mark Rowe  <[email protected]>
+
+        REGRESSION (WebKit2): Save as PDF no longer generates links to URLs
+        <http://webkit.org/b/65076> / <rdar://problem/9606246>
+
+        WebKit2 printing works by having the web process render the page content to a PDF. The PDF
+        data is then shipped to the UI process which will render it in to the printing graphics context.
+        Links were being lost because the API used to do the rendering of the PDF in to the printing
+        graphics context, CGContextDrawPDFPage, did not preserve the links that were present in the
+        PDF content received from the web process.
+
+        To fix this we switch to using PDFKit for drawing the PDF in to the printing graphics context.
+        PDFKit provides the ability for us to iterate over the links in the PDF content ourselves and
+        add links in to the printing graphics context.
+
+        Reviewed by Alexey Proskuryakov.
+
+        * UIProcess/API/mac/WKPrintingView.h:
+        * UIProcess/API/mac/WKPrintingView.mm:
+        (pdfAnnotationLinkClass): Look up the PDFAnnotationLink class from PDFKit as WebKit2 loads PDFKit lazily.
+        (pdfDocumentClass): Ditto.
+        (-[WKPrintingView _drawPDFDocument:page:atPoint:]): Switch to using the PDFKit equivalents of several types.
+        Iterate over the annotations present in the PDFPage, calling CGPDFContextSetURLForRect for each PDFAnnotationLink
+        that we find.
+        (-[WKPrintingView _drawPreview:]): Create an NSData to feed to PDFDocument.
+        (-[WKPrintingView drawRect:]): Ditto.
+        * WebKit2Prefix.h: Add the usual workaround to make Objective-C exceptions compile when C++ exception handling is disabled.
+
 2012-01-06  Viatcheslav Ostapenko  <[email protected]>
 
         [Qt] [WK2] Minibrowser leaks memory ~6-7Mb per reload

Modified: trunk/Source/WebKit2/UIProcess/API/mac/WKPrintingView.h (104376 => 104377)


--- trunk/Source/WebKit2/UIProcess/API/mac/WKPrintingView.h	2012-01-07 06:46:50 UTC (rev 104376)
+++ trunk/Source/WebKit2/UIProcess/API/mac/WKPrintingView.h	2012-01-07 06:57:32 UTC (rev 104377)
@@ -27,6 +27,7 @@
 #import <wtf/RetainPtr.h>
 
 @class WKPrintingViewData;
+@class PDFDocument;
 
 namespace WebKit {
     class WebFrameProxy;
@@ -43,7 +44,7 @@
     HashMap<WebCore::IntRect, Vector<uint8_t> > _pagePreviews;
 
     Vector<uint8_t> _printedPagesData;
-    RetainPtr<CGPDFDocumentRef> _printedPagesPDFDocument;
+    RetainPtr<PDFDocument> _printedPagesPDFDocument;
 
     uint64_t _expectedComputedPagesCallback;
     HashMap<uint64_t, WebCore::IntRect> _expectedPreviewCallbacks;

Modified: trunk/Source/WebKit2/UIProcess/API/mac/WKPrintingView.mm (104376 => 104377)


--- trunk/Source/WebKit2/UIProcess/API/mac/WKPrintingView.mm	2012-01-07 06:46:50 UTC (rev 104376)
+++ trunk/Source/WebKit2/UIProcess/API/mac/WKPrintingView.mm	2012-01-07 06:57:32 UTC (rev 104377)
@@ -30,6 +30,7 @@
 #import "PrintInfo.h"
 #import "WebData.h"
 #import "WebPageProxy.h"
+#import <PDFKit/PDFKit.h>
 #import <WebCore/WebCoreObjCExtras.h>
 #import <wtf/MainThread.h>
 
@@ -410,16 +411,30 @@
     return 0; // Invalid page number.
 }
 
-- (void)_drawPDFDocument:(CGPDFDocumentRef)pdfDocument page:(unsigned)page atPoint:(NSPoint)point
+static Class pdfAnnotationLinkClass()
 {
+    static Class pdfAnnotationLinkClass = NSClassFromString(@"PDFAnnotationLink");
+    return pdfAnnotationLinkClass;
+}
+
+static Class pdfDocumentClass()
+{
+    static Class pdfDocumentClass = NSClassFromString(@"PDFDocument");
+    return pdfDocumentClass;
+}
+
+- (void)_drawPDFDocument:(PDFDocument *)pdfDocument page:(unsigned)page atPoint:(NSPoint)point
+{
     if (!pdfDocument) {
         LOG_ERROR("Couldn't create a PDF document with data passed for preview");
         return;
     }
 
-    CGPDFPageRef pdfPage = CGPDFDocumentGetPage(pdfDocument, page);
-    if (!pdfPage) {
-        LOG_ERROR("Preview data doesn't have page %d", page);
+    PDFPage *pdfPage;
+    @try {
+        pdfPage = [pdfDocument pageAtIndex:page];
+    } @catch (id exception) {
+        LOG_ERROR("Preview data doesn't have page %d: %@", page, exception);
         return;
     }
 
@@ -429,8 +444,25 @@
     CGContextSaveGState(context);
     CGContextTranslateCTM(context, point.x, point.y);
     CGContextScaleCTM(context, _totalScaleFactorForPrinting, -_totalScaleFactorForPrinting);
-    CGContextTranslateCTM(context, 0, -CGPDFPageGetBoxRect(pdfPage, kCGPDFMediaBox).size.height);
-    CGContextDrawPDFPage(context, pdfPage);
+    CGContextTranslateCTM(context, 0, -[pdfPage boundsForBox:kPDFDisplayBoxMediaBox].size.height);
+    [pdfPage drawWithBox:kPDFDisplayBoxMediaBox];
+
+    CGAffineTransform transform = CGContextGetCTM(context);
+
+    for (PDFAnnotation *annotation in [pdfPage annotations]) {
+        if (![annotation isKindOfClass:pdfAnnotationLinkClass()])
+            continue;
+
+        PDFAnnotationLink *linkAnnotation = (PDFAnnotationLink *)annotation;
+        NSURL *url = "" URL];
+        if (!url)
+            continue;
+
+        CGRect urlRect = NSRectToCGRect([linkAnnotation bounds]);
+        CGRect transformedRect = CGRectApplyAffineTransform(urlRect, transform);
+        CGPDFContextSetURLForRect(context, (CFURLRef)url, transformedRect);
+    }
+
     CGContextRestoreGState(context);
 }
 
@@ -473,11 +505,11 @@
         return;
     }
 
-    const Vector<uint8_t>& pdfData = pagePreviewIterator->second;
-    RetainPtr<CGDataProviderRef> pdfDataProvider(AdoptCF, CGDataProviderCreateWithData(0, pdfData.data(), pdfData.size(), 0));
-    RetainPtr<CGPDFDocumentRef> pdfDocument(AdoptCF, CGPDFDocumentCreateWithProvider(pdfDataProvider.get()));
+    const Vector<uint8_t>& pdfDataBytes = pagePreviewIterator->second;
+    RetainPtr<NSData> pdfData(AdoptNS, [[NSData alloc] initWithBytes:pdfDataBytes.data() length:pdfDataBytes.size()]);
+    RetainPtr<PDFDocument> pdfDocument(AdoptNS, [[pdfDocumentClass() alloc] initWithData:pdfData.get()]);
 
-    [self _drawPDFDocument:pdfDocument.get() page:1 atPoint:NSMakePoint(nsRect.origin.x, nsRect.origin.y)];
+    [self _drawPDFDocument:pdfDocument.get() page:0 atPoint:NSMakePoint(nsRect.origin.x, nsRect.origin.y)];
 }
 
 - (void)drawRect:(NSRect)nsRect
@@ -498,11 +530,11 @@
     ASSERT(!_printedPagesData.isEmpty()); // Prepared by knowsPageRange:
 
     if (!_printedPagesPDFDocument) {
-        RetainPtr<CGDataProviderRef> pdfDataProvider(AdoptCF, CGDataProviderCreateWithData(0, _printedPagesData.data(), _printedPagesData.size(), 0));
-        _printedPagesPDFDocument.adoptCF(CGPDFDocumentCreateWithProvider(pdfDataProvider.get()));
+        RetainPtr<NSData> pdfData(AdoptNS, [[NSData alloc] initWithBytes:_printedPagesData.data() length:_printedPagesData.size()]);
+        _printedPagesPDFDocument.adoptNS([[pdfDocumentClass() alloc] initWithData:pdfData.get()]);
     }
 
-    unsigned printedPageNumber = [self _pageForRect:nsRect] - [self _firstPrintedPageNumber] + 1;
+    unsigned printedPageNumber = [self _pageForRect:nsRect] - [self _firstPrintedPageNumber];
     [self _drawPDFDocument:_printedPagesPDFDocument.get() page:printedPageNumber atPoint:NSMakePoint(nsRect.origin.x, nsRect.origin.y)];
 }
 

Modified: trunk/Source/WebKit2/WebKit2Prefix.h (104376 => 104377)


--- trunk/Source/WebKit2/WebKit2Prefix.h	2012-01-07 06:46:50 UTC (rev 104376)
+++ trunk/Source/WebKit2/WebKit2Prefix.h	2012-01-07 06:57:32 UTC (rev 104377)
@@ -28,7 +28,21 @@
 #import <Cocoa/Cocoa.h>
 #endif
 
+/* When C++ exceptions are disabled, the C++ library defines |try| and |catch|
+* to allow C++ code that expects exceptions to build. These definitions
+* interfere with Objective-C++ uses of Objective-C exception handlers, which
+* use |@try| and |@catch|. As a workaround, undefine these macros. */
+
 #ifdef __cplusplus
+#include <algorithm> // needed for exception_defines.h
+#endif
+
+#ifdef __OBJC__
+#undef try
+#undef catch
+#endif
+
+#ifdef __cplusplus
 #define new ("if you use new/delete make sure to include config.h at the top of the file"()) 
 #define delete ("if you use new/delete make sure to include config.h at the top of the file"()) 
 #endif
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to