Diff
Modified: trunk/Source/WebCore/ChangeLog (208346 => 208347)
--- trunk/Source/WebCore/ChangeLog 2016-11-03 21:07:35 UTC (rev 208346)
+++ trunk/Source/WebCore/ChangeLog 2016-11-03 21:07:51 UTC (rev 208347)
@@ -1,3 +1,52 @@
+2016-11-03 Tim Horton <[email protected]>
+
+ Printing to PDF should produce internal links when HTML has internal links
+ https://bugs.webkit.org/show_bug.cgi?id=112081
+ <rdar://problem/5955705>
+
+ Reviewed by Simon Fraser.
+ Patch originally by David Lattimore.
+
+ No new tests, as it's unclear how to test PDF output.
+
+ * dom/Element.cpp:
+ (WebCore::Element::findAnchorElementForLink):
+ * dom/Element.h:
+ Add findAnchorElementForLink, which looks up the anchor element corresponding
+ to the current element's href, and also returns the fragment name as an out parameter.
+
+ * page/PrintContext.cpp:
+ (WebCore::PrintContext::PrintContext):
+ (WebCore::PrintContext::spoolPage):
+ (WebCore::PrintContext::spoolRect):
+ (WebCore::PrintContext::end):
+ (WebCore::PrintContext::collectLinkedDestinations):
+ (WebCore::PrintContext::outputLinkedDestinations):
+ * rendering/RenderObject.cpp:
+ (WebCore::RenderObject::addPDFURLRect):
+ Plumb internal links (fragment links) through to GraphicsContext, using
+ the fragment name from the page.
+
+ * page/PrintContext.h:
+ * platform/graphics/GraphicsContext.cpp:
+ (WebCore::GraphicsContext::supportsInternalLinks):
+ (WebCore::GraphicsContext::setDestinationForRect):
+ (WebCore::GraphicsContext::addDestinationAtPoint):
+ * platform/graphics/GraphicsContext.h:
+ * platform/graphics/cg/GraphicsContextCG.cpp:
+ (WebCore::GraphicsContext::supportsInternalLinks):
+ (WebCore::GraphicsContext::setDestinationForRect):
+ (WebCore::GraphicsContext::addDestinationAtPoint):
+ Plumb internal links through to the CGContext. Apply the CTM, because
+ these functions expect positions in global coordinates.
+
+ * platform/graphics/win/GraphicsContextDirect2D.cpp:
+ (WebCore::GraphicsContext::setURLForRect):
+ * platform/graphics/cairo/GraphicsContextCairo.cpp:
+ (WebCore::GraphicsContext::setURLForRect):
+ Adjust setURLForRect to take a FloatRect, like everything else, and
+ stop rounding.
+
2016-11-03 Alex Christensen <[email protected]>
Unreviewed, rolling out r208298.
Modified: trunk/Source/WebCore/dom/Element.cpp (208346 => 208347)
--- trunk/Source/WebCore/dom/Element.cpp 2016-11-03 21:07:35 UTC (rev 208346)
+++ trunk/Source/WebCore/dom/Element.cpp 2016-11-03 21:07:51 UTC (rev 208347)
@@ -3744,4 +3744,26 @@
return { };
}
+Element* Element::findAnchorElementForLink(String& outAnchorName)
+{
+ if (!isLink())
+ return nullptr;
+
+ const AtomicString& href = ""
+ if (href.isNull())
+ return nullptr;
+
+ Document& document = this->document();
+ URL url = ""
+ if (!url.isValid())
+ return nullptr;
+
+ if (url.hasFragmentIdentifier() && equalIgnoringFragmentIdentifier(url, document.baseURL())) {
+ outAnchorName = url.fragmentIdentifier();
+ return document.findAnchor(outAnchorName);
+ }
+
+ return nullptr;
+}
+
} // namespace WebCore
Modified: trunk/Source/WebCore/dom/Element.h (208346 => 208347)
--- trunk/Source/WebCore/dom/Element.h 2016-11-03 21:07:35 UTC (rev 208346)
+++ trunk/Source/WebCore/dom/Element.h 2016-11-03 21:07:51 UTC (rev 208347)
@@ -576,6 +576,8 @@
Vector<WebAnimation*> getAnimations();
#endif
+ Element* findAnchorElementForLink(String& outAnchorName);
+
protected:
Element(const QualifiedName&, Document&, ConstructionType);
Modified: trunk/Source/WebCore/page/PrintContext.cpp (208346 => 208347)
--- trunk/Source/WebCore/page/PrintContext.cpp 2016-11-03 21:07:35 UTC (rev 208346)
+++ trunk/Source/WebCore/page/PrintContext.cpp 2016-11-03 21:07:51 UTC (rev 208347)
@@ -24,6 +24,8 @@
#include "GraphicsContext.h"
#include "Frame.h"
#include "FrameView.h"
+#include "HTMLNames.h"
+#include "NodeTraversal.h"
#include "RenderView.h"
#include "StyleInheritedData.h"
#include "StyleResolver.h"
@@ -34,7 +36,6 @@
PrintContext::PrintContext(Frame* frame)
: m_frame(frame)
- , m_isPrinting(false)
{
}
@@ -190,6 +191,7 @@
ctx.translate(-pageRect.x(), -pageRect.y());
ctx.clip(pageRect);
m_frame->view()->paintContents(ctx, pageRect);
+ outputLinkedDestinations(ctx, m_frame->document(), pageRect);
ctx.restore();
}
@@ -200,6 +202,7 @@
ctx.translate(-rect.x(), -rect.y());
ctx.clip(rect);
m_frame->view()->paintContents(ctx, rect);
+ outputLinkedDestinations(ctx, m_frame->document(), rect);
ctx.restore();
}
@@ -208,6 +211,7 @@
ASSERT(m_isPrinting);
m_isPrinting = false;
m_frame->setPrinting(false, FloatSize(), FloatSize(), 0, AdjustViewSize);
+ m_linkedDestinations = nullptr;
}
static inline RenderBoxModelObject* enclosingBoxModelObject(RenderElement* renderer)
@@ -246,6 +250,39 @@
return -1;
}
+void PrintContext::collectLinkedDestinations(Node& node)
+{
+ for (Node* child = &node; child; child = NodeTraversal::next(*child)) {
+ if (!is<Element>(child))
+ continue;
+
+ String outAnchorName;
+ if (Element* element = downcast<Element>(child)->findAnchorElementForLink(outAnchorName))
+ m_linkedDestinations->set(outAnchorName, *element);
+ }
+}
+
+void PrintContext::outputLinkedDestinations(GraphicsContext& graphicsContext, Node* node, const IntRect& pageRect)
+{
+ if (!graphicsContext.supportsInternalLinks())
+ return;
+
+ if (!m_linkedDestinations) {
+ m_linkedDestinations = std::make_unique<HashMap<String, Ref<Element>>>();
+ collectLinkedDestinations(*node);
+ }
+
+ for (const auto& it : *m_linkedDestinations) {
+ FloatPoint point = it.value->renderer()->anchorRect().minXMinYCorner();
+ point.expandedTo(FloatPoint());
+
+ if (!pageRect.contains(roundedIntPoint(point)))
+ continue;
+
+ graphicsContext.addDestinationAtPoint(it.key, point);
+ }
+}
+
String PrintContext::pageProperty(Frame* frame, const char* propertyName, int pageNumber)
{
Document* document = frame->document();
Modified: trunk/Source/WebCore/page/PrintContext.h (208346 => 208347)
--- trunk/Source/WebCore/page/PrintContext.h 2016-11-03 21:07:35 UTC (rev 208346)
+++ trunk/Source/WebCore/page/PrintContext.h 2016-11-03 21:07:51 UTC (rev 208347)
@@ -21,7 +21,9 @@
#pragma once
#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
namespace WebCore {
@@ -31,6 +33,7 @@
class FloatSize;
class GraphicsContext;
class IntRect;
+class Node;
class PrintContext {
public:
@@ -98,9 +101,13 @@
private:
void computePageRectsWithPageSizeInternal(const FloatSize& pageSizeInPixels, bool allowHorizontalTiling);
bool beginAndComputePageRectsWithPageSize(Frame&, const FloatSize& pageSizeInPixels);
+ void collectLinkedDestinations(Node&);
+ void outputLinkedDestinations(GraphicsContext&, Node*, const IntRect& pageRect);
// Used to prevent misuses of begin() and end() (e.g., call end without begin).
- bool m_isPrinting;
+ bool m_isPrinting { false };
+
+ std::unique_ptr<HashMap<String, Ref<Element>>> m_linkedDestinations;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/platform/graphics/GraphicsContext.cpp (208346 => 208347)
--- trunk/Source/WebCore/platform/graphics/GraphicsContext.cpp 2016-11-03 21:07:35 UTC (rev 208346)
+++ trunk/Source/WebCore/platform/graphics/GraphicsContext.cpp 2016-11-03 21:07:51 UTC (rev 208347)
@@ -1178,4 +1178,19 @@
return { point1, point2 };
}
+#if !USE(CG)
+bool GraphicsContext::supportsInternalLinks() const
+{
+ return false;
}
+
+void GraphicsContext::setDestinationForRect(const String&, const FloatRect&)
+{
+}
+
+void GraphicsContext::addDestinationAtPoint(const String&, const FloatPoint&)
+{
+}
+#endif
+
+}
Modified: trunk/Source/WebCore/platform/graphics/GraphicsContext.h (208346 => 208347)
--- trunk/Source/WebCore/platform/graphics/GraphicsContext.h 2016-11-03 21:07:35 UTC (rev 208346)
+++ trunk/Source/WebCore/platform/graphics/GraphicsContext.h 2016-11-03 21:07:51 UTC (rev 208347)
@@ -468,8 +468,11 @@
void translate(const FloatSize& size) { translate(size.width(), size.height()); }
WEBCORE_EXPORT void translate(float x, float y);
- void setURLForRect(const URL&, const IntRect&);
+ void setURLForRect(const URL&, const FloatRect&);
+ void setDestinationForRect(const String& name, const FloatRect&);
+ void addDestinationAtPoint(const String& name, const FloatPoint&);
+
void concatCTM(const AffineTransform&);
void setCTM(const AffineTransform&);
@@ -576,6 +579,8 @@
static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle);
+ bool supportsInternalLinks() const;
+
private:
void platformInit(PlatformGraphicsContext*);
void platformDestroy();
Modified: trunk/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp (208346 => 208347)
--- trunk/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp 2016-11-03 21:07:35 UTC (rev 208346)
+++ trunk/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp 2016-11-03 21:07:51 UTC (rev 208347)
@@ -805,7 +805,7 @@
}
}
-void GraphicsContext::setURLForRect(const URL&, const IntRect&)
+void GraphicsContext::setURLForRect(const URL&, const FloatRect&)
{
notImplemented();
}
Modified: trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp (208346 => 208347)
--- trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp 2016-11-03 21:07:35 UTC (rev 208346)
+++ trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp 2016-11-03 21:07:51 UTC (rev 208347)
@@ -1548,7 +1548,7 @@
setCGFillColor(platformContext(), fillColor());
}
-void GraphicsContext::setURLForRect(const URL& link, const IntRect& destRect)
+void GraphicsContext::setURLForRect(const URL& link, const FloatRect& destRect)
{
#if !PLATFORM(IOS)
if (paintingDisabled())
@@ -1565,15 +1565,11 @@
CGContextRef context = platformContext();
+ FloatRect rect = destRect;
// Get the bounding box to handle clipping.
- CGRect box = CGContextGetClipBoundingBox(context);
+ rect.intersect(CGContextGetClipBoundingBox(context));
- IntRect intBox((int)box.origin.x, (int)box.origin.y, (int)box.size.width, (int)box.size.height);
- IntRect rect = destRect;
- rect.intersect(intBox);
-
- CGPDFContextSetURLForRect(context, urlRef.get(),
- CGRectApplyAffineTransform(rect, CGContextGetCTM(context)));
+ CGPDFContextSetURLForRect(context, urlRef.get(), CGRectApplyAffineTransform(rect, CGContextGetCTM(context)));
#else
UNUSED_PARAM(link);
UNUSED_PARAM(destRect);
@@ -1902,6 +1898,36 @@
CGContextStrokeEllipseInRect(context, ellipse);
}
+bool GraphicsContext::supportsInternalLinks() const
+{
+ return true;
}
+void GraphicsContext::setDestinationForRect(const String& name, const FloatRect& destRect)
+{
+ if (paintingDisabled())
+ return;
+
+ CGContextRef context = platformContext();
+
+ FloatRect rect = destRect;
+ rect.intersect(CGContextGetClipBoundingBox(context));
+
+ CGRect transformedRect = CGRectApplyAffineTransform(rect, CGContextGetCTM(context));
+ CGPDFContextSetDestinationForRect(context, name.createCFString().get(), transformedRect);
+}
+
+void GraphicsContext::addDestinationAtPoint(const String& name, const FloatPoint& position)
+{
+ if (paintingDisabled())
+ return;
+
+ CGContextRef context = platformContext();
+
+ CGPoint transformedPoint = CGPointApplyAffineTransform(position, CGContextGetCTM(context));
+ CGPDFContextAddDestinationAtPoint(context, name.createCFString().get(), transformedPoint);
+}
+
+}
+
#endif
Modified: trunk/Source/WebCore/platform/graphics/win/GraphicsContextDirect2D.cpp (208346 => 208347)
--- trunk/Source/WebCore/platform/graphics/win/GraphicsContextDirect2D.cpp 2016-11-03 21:07:35 UTC (rev 208346)
+++ trunk/Source/WebCore/platform/graphics/win/GraphicsContextDirect2D.cpp 2016-11-03 21:07:51 UTC (rev 208347)
@@ -1642,7 +1642,7 @@
notImplemented();
}
-void GraphicsContext::setURLForRect(const URL& link, const IntRect& destRect)
+void GraphicsContext::setURLForRect(const URL& link, const FloatRect& destRect)
{
if (paintingDisabled())
return;
Modified: trunk/Source/WebCore/rendering/RenderObject.cpp (208346 => 208347)
--- trunk/Source/WebCore/rendering/RenderObject.cpp 2016-11-03 21:07:35 UTC (rev 208346)
+++ trunk/Source/WebCore/rendering/RenderObject.cpp 2016-11-03 21:07:51 UTC (rev 208347)
@@ -604,10 +604,22 @@
Node* node = this->node();
if (!is<Element>(node) || !node->isLink())
return;
- const AtomicString& href = ""
+ Element& element = downcast<Element>(*node);
+ const AtomicString& href = ""
if (href.isNull())
return;
- paintInfo.context().setURLForRect(node->document().completeURL(href), snappedIntRect(urlRect));
+
+ if (paintInfo.context().supportsInternalLinks()) {
+ String outAnchorName;
+ Element* linkTarget = element.findAnchorElementForLink(outAnchorName);
+ if (linkTarget) {
+ paintInfo.context().setDestinationForRect(outAnchorName, urlRect);
+ return;
+ }
+ }
+
+ paintInfo.context().setURLForRect(node->document().completeURL(href), urlRect);
+
}
#if PLATFORM(IOS)
Modified: trunk/Source/WebKit2/ChangeLog (208346 => 208347)
--- trunk/Source/WebKit2/ChangeLog 2016-11-03 21:07:35 UTC (rev 208346)
+++ trunk/Source/WebKit2/ChangeLog 2016-11-03 21:07:51 UTC (rev 208347)
@@ -1,3 +1,24 @@
+2016-11-03 Tim Horton <[email protected]>
+
+ Printing to PDF should produce internal links when HTML has internal links
+ https://bugs.webkit.org/show_bug.cgi?id=112081
+ <rdar://problem/5955705>
+
+ Reviewed by Simon Fraser.
+
+ * UIProcess/mac/WKPrintingView.h:
+ * UIProcess/mac/WKPrintingView.mm:
+ (linkDestinationName):
+ (-[WKPrintingView _drawPDFDocument:page:atPoint:]):
+ Propagate link-to-destination annotations (and each page's destinations)
+ into the printed PDF.
+ Generate a unique destination name based on the page and position, because
+ we have lost the fragment name information.
+
+ (-[WKPrintingView drawRect:]):
+ Compute all of the destinations for every page, so that we can add them
+ to the context as we paint the pages (we need the page CTM in order to add them).
+
2016-11-03 Alex Christensen <[email protected]>
Unreviewed, rolling out r208298.
Modified: trunk/Source/WebKit2/UIProcess/mac/WKPrintingView.h (208346 => 208347)
--- trunk/Source/WebKit2/UIProcess/mac/WKPrintingView.h 2016-11-03 21:07:35 UTC (rev 208346)
+++ trunk/Source/WebKit2/UIProcess/mac/WKPrintingView.h 2016-11-03 21:07:51 UTC (rev 208347)
@@ -33,6 +33,7 @@
#import <wtf/Vector.h>
@class WKPrintingViewData;
+@class PDFDestination;
@class PDFDocument;
namespace WebKit {
@@ -52,6 +53,7 @@
Vector<uint8_t> _printedPagesData;
RetainPtr<PDFDocument> _printedPagesPDFDocument;
+ Vector<Vector<RetainPtr<PDFDestination>>> _linkDestinationsPerPage;
uint64_t _expectedComputedPagesCallback;
HashMap<uint64_t, WebCore::IntRect> _expectedPreviewCallbacks;
Modified: trunk/Source/WebKit2/UIProcess/mac/WKPrintingView.mm (208346 => 208347)
--- trunk/Source/WebKit2/UIProcess/mac/WKPrintingView.mm 2016-11-03 21:07:35 UTC (rev 208346)
+++ trunk/Source/WebKit2/UIProcess/mac/WKPrintingView.mm 2016-11-03 21:07:51 UTC (rev 208347)
@@ -427,6 +427,11 @@
return 0; // Invalid page number.
}
+static CFStringRef linkDestinationName(PDFDocument *document, PDFDestination *destination)
+{
+ return (CFStringRef)[NSString stringWithFormat:@"%lu-%f-%f", (unsigned long)[document indexForPage:destination.page], destination.point.x, destination.point.y];
+}
+
- (void)_drawPDFDocument:(PDFDocument *)pdfDocument page:(unsigned)page atPoint:(NSPoint)point
{
if (!pdfDocument) {
@@ -456,6 +461,11 @@
CGAffineTransform transform = CGContextGetCTM(context);
+ for (const auto& destination : _linkDestinationsPerPage[page]) {
+ CGPoint destinationPoint = CGPointApplyAffineTransform(NSPointToCGPoint([destination point]), transform);
+ CGPDFContextAddDestinationAtPoint(context, linkDestinationName(pdfDocument, destination.get()), destinationPoint);
+ }
+
for (PDFAnnotation *annotation in [pdfPage annotations]) {
if (![annotation isKindOfClass:pdfAnnotationLinkClass()])
continue;
@@ -465,11 +475,17 @@
PDFAnnotationLink *linkAnnotation = (PDFAnnotationLink *)annotation;
#pragma clang diagnostic pop
NSURL *url = "" URL];
- if (!url)
+ CGRect transformedRect = CGRectApplyAffineTransform(NSRectToCGRect([linkAnnotation bounds]), transform);
+
+ if (!url) {
+ PDFDestination *destination = [linkAnnotation destination];
+ if (!destination)
+ continue;
+ CGPDFContextSetDestinationForRect(context, linkDestinationName(pdfDocument, destination), transformedRect);
+
continue;
+ }
- CGRect urlRect = NSRectToCGRect([linkAnnotation bounds]);
- CGRect transformedRect = CGRectApplyAffineTransform(urlRect, transform);
CGPDFContextSetURLForRect(context, (CFURLRef)url, transformedRect);
}
@@ -549,6 +565,31 @@
if (!_printedPagesPDFDocument) {
RetainPtr<NSData> pdfData = adoptNS([[NSData alloc] initWithBytes:_printedPagesData.data() length:_printedPagesData.size()]);
_printedPagesPDFDocument = adoptNS([[pdfDocumentClass() alloc] initWithData:pdfData.get()]);
+
+ unsigned pageCount = [_printedPagesPDFDocument pageCount];
+ _linkDestinationsPerPage.clear();
+ _linkDestinationsPerPage.resize(pageCount);
+ for (unsigned i = 0; i < pageCount; i++) {
+ PDFPage *page = [_printedPagesPDFDocument pageAtIndex:i];
+ for (PDFAnnotation *annotation in page.annotations) {
+ if (![annotation isKindOfClass:pdfAnnotationLinkClass()])
+ continue;
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ PDFAnnotationLink *linkAnnotation = (PDFAnnotationLink *)annotation;
+#pragma clang diagnostic pop
+ if (linkAnnotation.URL)
+ continue;
+
+ PDFDestination *destination = linkAnnotation.destination;
+ if (!destination)
+ continue;
+
+ unsigned destinationPageIndex = [_printedPagesPDFDocument indexForPage:destination.page];
+ _linkDestinationsPerPage[destinationPageIndex].append(destination);
+ }
+ }
}
unsigned printedPageNumber = [self _pageForRect:nsRect] - [self _firstPrintedPageNumber];