diff options
author | wangxianzhu <wangxianzhu@chromium.org> | 2015-09-17 20:38:02 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-09-17 20:38:02 -0700 |
commit | ef6c50a80f77e6da84e198a34755dd42b1b0cf1e (patch) | |
tree | 6f621fce7cf1daacd9b8abcfea990f411e8e5974 /src/pdf/SkPDFDevice.cpp | |
parent | 1b55a963a2374a14bb82eb887bb99ee91680f0eb (diff) |
Merge sub-device annotations in SkPDFDevice::drawDevice()
Previously annotations added between saveLayer/restore were lost.
Merge annotations in SkPDFDevice::drawDevice(). Also modified code to
apply correct transformation and clipping on annotations added between
saveLayer/restore:
- Apply the initial transform only when adding the annotations into the
doc, otherwise we need to unapply sub-device's initial transform
before merging the annotations into parent-device.
- Apply only device-local clipping. fClipStack is in global coordinates,
which is not suitable to clip rects in sub-devices.
BUG=skia:4080
BUG=503515
Review URL: https://codereview.chromium.org/1257533004
Diffstat (limited to 'src/pdf/SkPDFDevice.cpp')
-rw-r--r-- | src/pdf/SkPDFDevice.cpp | 159 |
1 files changed, 88 insertions, 71 deletions
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp index a5c9557412..52c4c655cd 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()); |