aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/pdf
diff options
context:
space:
mode:
Diffstat (limited to 'src/pdf')
-rw-r--r--src/pdf/SkPDFDevice.cpp111
-rw-r--r--src/pdf/SkPDFDocument.cpp7
-rw-r--r--src/pdf/SkPDFPage.cpp4
-rw-r--r--src/pdf/SkPDFPage.h5
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.