diff options
Diffstat (limited to 'src/pdf')
-rw-r--r-- | src/pdf/SkPDFDevice.cpp | 111 | ||||
-rw-r--r-- | src/pdf/SkPDFDocument.cpp | 7 | ||||
-rw-r--r-- | src/pdf/SkPDFPage.cpp | 4 | ||||
-rw-r--r-- | src/pdf/SkPDFPage.h | 5 |
4 files changed, 113 insertions, 14 deletions
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp index eae7ab73f0..245299639e 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(SkPDFString, (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->appendInt(dest->point.x()); + pdfDest->appendInt(dest->point.y()); + pdfDest->appendInt(0); // Leave zoom unchanged + dict->insert(static_cast<const char *>(dest->nameData->data()), pdfDest); + } } SkPDFFormXObject* SkPDFDevice::createFormXObjectFromDevice() { diff --git a/src/pdf/SkPDFDocument.cpp b/src/pdf/SkPDFDocument.cpp index 4c66c6bb90..7ee2778326 100644 --- a/src/pdf/SkPDFDocument.cpp +++ b/src/pdf/SkPDFDocument.cpp @@ -107,18 +107,25 @@ bool SkPDFDocument::emitPDF(SkWStream* stream) { fDocCatalog->insert("OutputIntent", intentArray.get()); */ + SkPDFDict* dests = SkNEW(SkPDFDict); // fPageResources owns reference + fCatalog->addObject(dests, true /* onFirstPage */); + fPageResources.push(dests); + bool firstPage = true; for (int i = 0; i < fPages.count(); i++) { int resourceCount = fPageResources.count(); fPages[i]->finalizePage(fCatalog.get(), firstPage, &fPageResources); addResourcesToCatalog(resourceCount, firstPage, &fPageResources, fCatalog.get()); + fPages[i]->appendDestinations(dests); if (i == 0) { firstPage = false; fSecondPageFirstResourceIndex = fPageResources.count(); } } + fDocCatalog->insert("Dests", SkNEW_ARGS(SkPDFObjRef, (dests)))->unref(); + // Build font subsetting info before proceeding. perform_font_subsetting(fCatalog.get(), fPages, &fSubstitutes); diff --git a/src/pdf/SkPDFPage.cpp b/src/pdf/SkPDFPage.cpp index f47f8ffd46..4cdc00003b 100644 --- a/src/pdf/SkPDFPage.cpp +++ b/src/pdf/SkPDFPage.cpp @@ -147,3 +147,7 @@ const SkTDArray<SkPDFFont*>& SkPDFPage::getFontResources() const { const SkPDFGlyphSetMap& SkPDFPage::getFontGlyphUsage() const { return fDevice->getFontGlyphUsage(); } + +void SkPDFPage::appendDestinations(SkPDFDict* dict) { + fDevice->appendDestinations(dict, this); +} diff --git a/src/pdf/SkPDFPage.h b/src/pdf/SkPDFPage.h index 72ba335e66..285a2f565e 100644 --- a/src/pdf/SkPDFPage.h +++ b/src/pdf/SkPDFPage.h @@ -48,6 +48,11 @@ public: void finalizePage(SkPDFCatalog* catalog, bool firstPage, SkTDArray<SkPDFObject*>* resourceObjects); + /** Add destinations for this page to the supplied dictionary. + * @param dict Dictionary to add destinations to. + */ + void appendDestinations(SkPDFDict* dict); + /** Determine the size of the page content and store to the catalog * the offsets of all nonresource-indirect objects that make up the page * content. This must be called before emitPage(), but after finalizePage. |