diff options
author | epoger@google.com <epoger@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-03-08 09:09:10 +0000 |
---|---|---|
committer | epoger@google.com <epoger@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-03-08 09:09:10 +0000 |
commit | b58772f86659cfe0e8d9247fcee878dddd8fdad9 (patch) | |
tree | 78c54090d70af79ab206ef5137833c0703874203 /src/pdf/SkPDFDevice.cpp | |
parent | 754a3eb73b796398062f09cc98eae224262a3bc8 (diff) |
PDF: add support for named destinations.
Landing patchset 7 from https://codereview.appspot.com/7374052 for dml@google.com
Review URL: https://codereview.chromium.org/12533009
git-svn-id: http://skia.googlecode.com/svn/trunk@8034 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/pdf/SkPDFDevice.cpp')
-rw-r--r-- | src/pdf/SkPDFDevice.cpp | 111 |
1 files changed, 97 insertions, 14 deletions
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp index eae7ab73f0..be1bca5915 100644 --- a/src/pdf/SkPDFDevice.cpp +++ b/src/pdf/SkPDFDevice.cpp @@ -645,6 +645,7 @@ void SkPDFDevice::cleanUp(bool clearFontUsage) { fShaderResources.unrefAll(); SkSafeUnref(fAnnotations); SkSafeUnref(fResourceDict); + fNamedDestinations.deleteAll(); if (clearFontUsage) { fFontGlyphUsage->reset(); @@ -703,6 +704,10 @@ void SkPDFDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode, 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 @@ void SkPDFDevice::drawRect(const SkDraw& d, const SkRect& r, return; } - if (handleAnnotations(r, *d.fMatrix, paint)) { + if (handleRectAnnotation(r, *d.fMatrix, paint)) { return; } @@ -847,7 +852,7 @@ void SkPDFDevice::drawPath(const SkDraw& d, const SkPath& origPath, return; } - if (handleAnnotations(pathPtr->getBounds(), *d.fMatrix, paint)) { + if (handleRectAnnotation(pathPtr->getBounds(), *d.fMatrix, paint)) { return; } @@ -1286,19 +1291,43 @@ SkData* SkPDFDevice::copyContentToData() const { 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 @@ bool SkPDFDevice::handleAnnotations(const SkRect& r, const SkMatrix& matrix, 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,12 +1355,66 @@ bool SkPDFDevice::handleAnnotations(const SkRect& r, const SkMatrix& matrix, 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()); +} + +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; - return p.isNoDrawAnnotation(); + 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() { |