Index: src/pdf/SkPDFDevice.cpp |
=================================================================== |
--- src/pdf/SkPDFDevice.cpp (revision 8005) |
+++ src/pdf/SkPDFDevice.cpp (working copy) |
@@ -645,6 +645,7 @@ |
fShaderResources.unrefAll(); |
SkSafeUnref(fAnnotations); |
SkSafeUnref(fResourceDict); |
+ fNamedDestinations.deleteAll(); |
if (clearFontUsage) { |
fFontGlyphUsage->reset(); |
@@ -703,6 +704,10 @@ |
return; |
} |
+ if (handlePointAnnotation(points, count, *d.fMatrix, passedPaint)) { |
+ return; |
+ } |
+ |
// SkDraw::drawPoints converts to multiple calls to fDevice->drawPath. |
// We only use this when there's a path effect because of the overhead |
// of multiple calls to setUpContentEntry it causes. |
@@ -791,7 +796,7 @@ |
return; |
} |
- if (handleAnnotations(r, *d.fMatrix, paint)) { |
+ if (handleRectAnnotation(r, *d.fMatrix, paint)) { |
return; |
} |
@@ -847,7 +852,7 @@ |
return; |
} |
- if (handleAnnotations(pathPtr->getBounds(), *d.fMatrix, paint)) { |
+ if (handleRectAnnotation(pathPtr->getBounds(), *d.fMatrix, paint)) { |
return; |
} |
@@ -1286,19 +1291,43 @@ |
return data.copyToData(); |
} |
-bool SkPDFDevice::handleAnnotations(const SkRect& r, const SkMatrix& matrix, |
- const SkPaint& p) { |
+bool SkPDFDevice::handleRectAnnotation(const SkRect& r, const SkMatrix& matrix, |
+ const SkPaint& p) { |
SkAnnotation* annotationInfo = p.getAnnotation(); |
if (!annotationInfo) { |
return false; |
} |
SkData* urlData = annotationInfo->find(SkAnnotationKeys::URL_Key()); |
- if (!urlData) { |
+ if (urlData) { |
+ handleLinkToURL(urlData, r, matrix); |
+ return p.isNoDrawAnnotation(); |
+ } |
+ SkData* linkToName = annotationInfo->find(SkAnnotationKeys::Link_Named_Dest_Key()); |
+ if (linkToName) { |
+ handleLinkToNamedDest(linkToName, r, matrix); |
+ return p.isNoDrawAnnotation(); |
+ } |
+ return false; |
+} |
+ |
+bool SkPDFDevice::handlePointAnnotation(const SkPoint* points, size_t count, |
+ const SkMatrix& matrix, |
+ const SkPaint& paint) { |
+ SkAnnotation* annotationInfo = paint.getAnnotation(); |
+ if (!annotationInfo) { |
return false; |
} |
+ SkData* nameData = annotationInfo->find(SkAnnotationKeys::Define_Named_Dest_Key()); |
+ if (nameData) { |
+ for (size_t i = 0; i < count; i++) { |
+ defineNamedDestination(nameData, points[i], matrix); |
+ } |
+ return paint.isNoDrawAnnotation(); |
+ } |
+ return false; |
+} |
- SkString url(static_cast<const char *>(urlData->data()), |
- urlData->size() - 1); |
+SkPDFDict* SkPDFDevice::createLinkAnnotation(const SkRect& r, const SkMatrix& matrix) { |
SkMatrix transform = matrix; |
transform.postConcat(fInitialTransform); |
SkRect translatedRect; |
@@ -1307,18 +1336,18 @@ |
if (NULL == fAnnotations) { |
fAnnotations = SkNEW(SkPDFArray); |
} |
- SkAutoTUnref<SkPDFDict> annotation(new SkPDFDict("Annot")); |
+ SkPDFDict* annotation(SkNEW_ARGS(SkPDFDict, ("Annot"))); |
annotation->insertName("Subtype", "Link"); |
- fAnnotations->append(annotation.get()); |
+ fAnnotations->append(annotation); |
- SkAutoTUnref<SkPDFArray> border(new SkPDFArray); |
+ SkAutoTUnref<SkPDFArray> border(SkNEW(SkPDFArray)); |
border->reserve(3); |
border->appendInt(0); // Horizontal corner radius. |
border->appendInt(0); // Vertical corner radius. |
border->appendInt(0); // Width, 0 = no border. |
annotation->insert("Border", border.get()); |
- SkAutoTUnref<SkPDFArray> rect(new SkPDFArray); |
+ SkAutoTUnref<SkPDFArray> rect(SkNEW(SkPDFArray)); |
rect->reserve(4); |
rect->appendScalar(translatedRect.fLeft); |
rect->appendScalar(translatedRect.fTop); |
@@ -1326,14 +1355,68 @@ |
rect->appendScalar(translatedRect.fBottom); |
annotation->insert("Rect", rect.get()); |
- SkAutoTUnref<SkPDFDict> action(new SkPDFDict("Action")); |
+ return annotation; |
+} |
+ |
+void SkPDFDevice::handleLinkToURL(SkData* urlData, const SkRect& r, |
+ const SkMatrix& matrix) { |
+ SkAutoTUnref<SkPDFDict> annotation(createLinkAnnotation(r, matrix)); |
+ |
+ SkString url(static_cast<const char *>(urlData->data()), |
+ urlData->size() - 1); |
+ SkAutoTUnref<SkPDFDict> action(SkNEW_ARGS(SkPDFDict, ("Action"))); |
action->insertName("S", "URI"); |
- action->insert("URI", new SkPDFString(url))->unref(); |
+ action->insert("URI", SkNEW_ARGS(SkPDFString, (url)))->unref(); |
annotation->insert("A", action.get()); |
+} |
- return p.isNoDrawAnnotation(); |
+void SkPDFDevice::handleLinkToNamedDest(SkData* nameData, const SkRect& r, |
+ const SkMatrix& matrix) { |
+ SkAutoTUnref<SkPDFDict> annotation(createLinkAnnotation(r, matrix)); |
+ SkString name(static_cast<const char *>(nameData->data()), |
+ nameData->size() - 1); |
+ annotation->insert("Dest", SkNEW_ARGS(SkPDFName, (name)))->unref(); |
} |
+struct NamedDestination { |
+ const SkData* nameData; |
+ SkPoint point; |
+ |
+ NamedDestination(const SkData* nameData, const SkPoint& point) |
+ : nameData(nameData), point(point) { |
+ nameData->ref(); |
+ } |
+ |
+ ~NamedDestination() { |
+ nameData->unref(); |
+ } |
+}; |
+ |
+void SkPDFDevice::defineNamedDestination(SkData* nameData, const SkPoint& point, |
+ const SkMatrix& matrix) { |
+ SkMatrix transform = matrix; |
+ transform.postConcat(fInitialTransform); |
+ SkPoint translatedPoint; |
+ transform.mapXY(point.x(), point.y(), &translatedPoint); |
+ fNamedDestinations.push( |
+ SkNEW_ARGS(NamedDestination, (nameData, translatedPoint))); |
+} |
+ |
+void SkPDFDevice::appendDestinations(SkPDFDict* dict, SkPDFObject* page) { |
+ int nDest = fNamedDestinations.count(); |
+ for (int i = 0; i < nDest; i++) { |
+ NamedDestination* dest = fNamedDestinations[i]; |
+ SkAutoTUnref<SkPDFArray> pdfDest(SkNEW(SkPDFArray)); |
+ pdfDest->reserve(5); |
+ pdfDest->append(SkNEW_ARGS(SkPDFObjRef, (page)))->unref(); |
+ pdfDest->appendName("XYZ"); |
+ pdfDest->appendScalar(dest->point.x()); |
+ pdfDest->appendScalar(dest->point.y()); |
+ pdfDest->appendInt(0); // Leave zoom unchanged |
+ dict->insert(static_cast<const char *>(dest->nameData->data()), pdfDest); |
+ } |
+} |
+ |
SkPDFFormXObject* SkPDFDevice::createFormXObjectFromDevice() { |
SkPDFFormXObject* xobject = SkNEW_ARGS(SkPDFFormXObject, (this)); |
// We always draw the form xobjects that we create back into the device, so |