Index: src/pdf/SkPDFDevice.cpp |
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp |
index a5c9557412032281fbbc341599baf5ff44dd451b..52c4c655cd9c38d6b1cd58c4cb0b217f54321c8a 100644 |
--- a/src/pdf/SkPDFDevice.cpp |
+++ b/src/pdf/SkPDFDevice.cpp |
@@ -25,6 +25,7 @@ |
#include "SkPDFStream.h" |
#include "SkPDFTypes.h" |
#include "SkPDFUtils.h" |
+#include "SkRasterClip.h" |
#include "SkRect.h" |
#include "SkRRect.h" |
#include "SkString.h" |
@@ -702,7 +703,6 @@ SkPDFDevice::SkPDFDevice(SkISize pageSize, SkScalar rasterDpi, SkPDFCanon* canon |
, fPageSize(pageSize) |
, fContentSize(pageSize) |
, fExistingClipRegion(SkIRect::MakeSize(pageSize)) |
- , fAnnotations(nullptr) |
, fLastContentEntry(nullptr) |
, fLastMarginContentEntry(nullptr) |
, fDrawingArea(kContent_DrawingArea) |
@@ -731,7 +731,6 @@ SkPDFDevice::~SkPDFDevice() { |
} |
void SkPDFDevice::init() { |
- fAnnotations = nullptr; |
fContentEntries.free(); |
fLastContentEntry = nullptr; |
fMarginContentEntries.free(); |
@@ -747,7 +746,8 @@ void SkPDFDevice::cleanUp(bool clearFontUsage) { |
fXObjectResources.unrefAll(); |
fFontResources.unrefAll(); |
fShaderResources.unrefAll(); |
- SkSafeUnref(fAnnotations); |
+ fLinkToURLs.deleteAll(); |
+ fLinkToDestinations.deleteAll(); |
fNamedDestinations.deleteAll(); |
if (clearFontUsage) { |
@@ -876,22 +876,6 @@ void SkPDFDevice::drawPoints(const SkDraw& d, |
} |
} |
-static SkPath transform_and_clip_path(const SkDraw& d, |
- const SkPath& region, |
- const SkMatrix& initialTransform) { |
- SkPath path = region; |
- SkMatrix transform = *d.fMatrix; |
- transform.postConcat(initialTransform); |
- path.transform(transform); |
- if (const SkClipStack* clipStack = d.fClipStack) { |
- SkPath clip; |
- (void)clipStack->asPath(&clip); |
- clip.transform(initialTransform); |
- Op(clip, path, SkPathOp::kIntersect_SkPathOp, &path); |
- } |
- return path; |
-} |
- |
static SkPDFDict* create_link_annotation(const SkRect& translatedRect) { |
SkAutoTUnref<SkPDFDict> annotation(new SkPDFDict("Annot")); |
annotation->insertName("Subtype", "Link"); |
@@ -914,7 +898,7 @@ static SkPDFDict* create_link_annotation(const SkRect& translatedRect) { |
return annotation.detach(); |
} |
-static SkPDFDict* create_link_to_url(SkData* urlData, const SkRect& r) { |
+static SkPDFDict* create_link_to_url(const SkData* urlData, const SkRect& r) { |
SkAutoTUnref<SkPDFDict> annotation(create_link_annotation(r)); |
SkString url(static_cast<const char *>(urlData->data()), |
@@ -926,7 +910,8 @@ static SkPDFDict* create_link_to_url(SkData* urlData, const SkRect& r) { |
return annotation.detach(); |
} |
-static SkPDFDict* create_link_named_dest(SkData* nameData, const SkRect& r) { |
+static SkPDFDict* create_link_named_dest(const SkData* nameData, |
+ const SkRect& r) { |
SkAutoTUnref<SkPDFDict> annotation(create_link_annotation(r)); |
SkString name(static_cast<const char *>(nameData->data()), |
nameData->size() - 1); |
@@ -934,21 +919,6 @@ static SkPDFDict* create_link_named_dest(SkData* nameData, const SkRect& r) { |
return annotation.detach(); |
} |
-static SkPDFDict* create_rect_annotation(const SkRect& r, |
- SkAnnotation* annotation) { |
- SkASSERT(annotation); |
- SkData* urlData = annotation->find(SkAnnotationKeys::URL_Key()); |
- if (urlData) { |
- return create_link_to_url(urlData, r); |
- } |
- SkData* linkToName = |
- annotation->find(SkAnnotationKeys::Link_Named_Dest_Key()); |
- if (linkToName) { |
- return create_link_named_dest(linkToName, r); |
- } |
- return nullptr; |
-} |
- |
void SkPDFDevice::drawRect(const SkDraw& d, |
const SkRect& rect, |
const SkPaint& srcPaint) { |
@@ -970,12 +940,7 @@ void SkPDFDevice::drawRect(const SkDraw& d, |
if (SkAnnotation* annotation = paint.getAnnotation()) { |
SkPath path; |
path.addRect(rect); |
- SkRect transformedRect = |
- transform_and_clip_path(d, path, fInitialTransform).getBounds(); |
- SkAutoTUnref<SkPDFDict> annot( |
- create_rect_annotation(transformedRect, annotation)); |
- if (annot) { |
- this->addAnnotation(annot.detach()); |
+ if (handlePathAnnotation(path, d, annotation)) { |
return; |
} |
} |
@@ -1059,13 +1024,7 @@ void SkPDFDevice::drawPath(const SkDraw& d, |
} |
if (SkAnnotation* annotation = paint.getAnnotation()) { |
- SkRect transformedRect = |
- transform_and_clip_path(d, *pathPtr, fInitialTransform) |
- .getBounds(); |
- SkAutoTUnref<SkPDFDict> annot( |
- create_rect_annotation(transformedRect, annotation)); |
- if (annot) { |
- this->addAnnotation(annot.detach()); |
+ if (handlePathAnnotation(*pathPtr, d, annotation)) { |
return; |
} |
} |
@@ -1327,10 +1286,42 @@ void SkPDFDevice::drawVertices(const SkDraw& d, SkCanvas::VertexMode, |
// TODO: implement drawVertices |
} |
+struct RectWithData { |
+ SkRect rect; |
+ SkAutoTUnref<const SkData> data; |
+ |
+ RectWithData(const SkRect& rect, const SkData* data) |
+ : rect(rect), data(SkRef(data)) {} |
+}; |
+ |
+struct NamedDestination { |
+ SkAutoTUnref<const SkData> nameData; |
+ SkPoint point; |
+ |
+ NamedDestination(const SkData* nameData, const SkPoint& point) |
+ : nameData(SkRef(nameData)), point(point) {} |
+}; |
+ |
void SkPDFDevice::drawDevice(const SkDraw& d, SkBaseDevice* device, |
int x, int y, const SkPaint& paint) { |
// our onCreateCompatibleDevice() always creates SkPDFDevice subclasses. |
SkPDFDevice* pdfDevice = static_cast<SkPDFDevice*>(device); |
+ |
+ SkScalar scalarX = SkIntToScalar(x); |
+ SkScalar scalarY = SkIntToScalar(y); |
+ for (RectWithData* link : pdfDevice->fLinkToURLs) { |
+ fLinkToURLs.push(new RectWithData( |
+ link->rect.makeOffset(scalarX, scalarY), link->data)); |
+ } |
+ for (RectWithData* link : pdfDevice->fLinkToDestinations) { |
+ fLinkToDestinations.push(new RectWithData( |
+ link->rect.makeOffset(scalarX, scalarY), link->data)); |
+ } |
+ for (NamedDestination* d : pdfDevice->fNamedDestinations) { |
+ fNamedDestinations.push(new NamedDestination( |
+ d->nameData, d->point + SkPoint::Make(scalarX, scalarY))); |
+ } |
+ |
if (pdfDevice->isContentEmpty()) { |
return; |
} |
@@ -1557,50 +1548,76 @@ bool SkPDFDevice::handleInversePath(const SkDraw& d, const SkPath& origPath, |
return true; |
} |
-struct NamedDestination { |
- SkAutoTUnref<const SkData> nameData; |
- SkPoint point; |
- |
- NamedDestination(const SkData* nameData, const SkPoint& point) |
- : nameData(SkRef(nameData)), point(point) {} |
-}; |
- |
bool SkPDFDevice::handlePointAnnotation(const SkPoint* points, size_t count, |
const SkMatrix& matrix, |
SkAnnotation* annotationInfo) { |
SkData* nameData = annotationInfo->find( |
SkAnnotationKeys::Define_Named_Dest_Key()); |
if (nameData) { |
- SkMatrix transform = matrix; |
- transform.postConcat(fInitialTransform); |
for (size_t i = 0; i < count; i++) { |
- SkPoint translatedPoint; |
- transform.mapXY(points[i].x(), points[i].y(), &translatedPoint); |
- fNamedDestinations.push(new NamedDestination(nameData, translatedPoint)); |
+ SkPoint transformedPoint; |
+ matrix.mapXY(points[i].x(), points[i].y(), &transformedPoint); |
+ fNamedDestinations.push(new NamedDestination(nameData, transformedPoint)); |
} |
return true; |
} |
return false; |
} |
-void SkPDFDevice::addAnnotation(SkPDFDict* annotation) { |
- if (nullptr == fAnnotations) { |
- fAnnotations = new SkPDFArray; |
+bool SkPDFDevice::handlePathAnnotation(const SkPath& path, |
+ const SkDraw& d, |
+ SkAnnotation* annotation) { |
+ SkASSERT(annotation); |
+ |
+ SkPath transformedPath = path; |
+ transformedPath.transform(*d.fMatrix); |
+ SkRasterClip clip = *d.fRC; |
+ clip.op(transformedPath, SkISize::Make(width(), height()), SkRegion::kIntersect_Op, false); |
+ SkRect transformedRect = SkRect::Make(clip.getBounds()); |
+ |
+ SkData* urlData = annotation->find(SkAnnotationKeys::URL_Key()); |
+ if (urlData) { |
+ if (!transformedRect.isEmpty()) { |
+ fLinkToURLs.push(new RectWithData(transformedRect, urlData)); |
+ } |
+ return true; |
} |
- fAnnotations->appendObject(annotation); |
+ |
+ SkData* linkToDestination = |
+ annotation->find(SkAnnotationKeys::Link_Named_Dest_Key()); |
+ if (linkToDestination) { |
+ if (!transformedRect.isEmpty()) { |
+ fLinkToDestinations.push(new RectWithData(transformedRect, linkToDestination)); |
+ } |
+ return true; |
+ } |
+ |
+ return false; |
} |
+void SkPDFDevice::appendAnnotations(SkPDFArray* array) const { |
+ array->reserve(fLinkToURLs.count() + fLinkToDestinations.count()); |
+ for (RectWithData* rectWithURL : fLinkToURLs) { |
+ SkRect r; |
+ fInitialTransform.mapRect(&r, rectWithURL->rect); |
+ array->appendObject(create_link_to_url(rectWithURL->data, r)); |
+ } |
+ for (RectWithData* linkToDestination : fLinkToDestinations) { |
+ SkRect r; |
+ fInitialTransform.mapRect(&r, linkToDestination->rect); |
+ array->appendObject(create_link_named_dest(linkToDestination->data, r)); |
+ } |
+} |
void SkPDFDevice::appendDestinations(SkPDFDict* dict, SkPDFObject* page) const { |
- int nDest = fNamedDestinations.count(); |
- for (int i = 0; i < nDest; i++) { |
- NamedDestination* dest = fNamedDestinations[i]; |
+ for (NamedDestination* dest : fNamedDestinations) { |
SkAutoTUnref<SkPDFArray> pdfDest(new SkPDFArray); |
pdfDest->reserve(5); |
pdfDest->appendObjRef(SkRef(page)); |
pdfDest->appendName("XYZ"); |
- pdfDest->appendScalar(dest->point.x()); |
- pdfDest->appendScalar(dest->point.y()); |
+ SkPoint p = fInitialTransform.mapXY(dest->point.x(), dest->point.y()); |
+ pdfDest->appendScalar(p.x()); |
+ pdfDest->appendScalar(p.y()); |
pdfDest->appendInt(0); // Leave zoom unchanged |
SkString name(static_cast<const char*>(dest->nameData->data())); |
dict->insertObject(name, pdfDest.detach()); |