aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar wangxianzhu <wangxianzhu@chromium.org>2015-09-17 20:38:02 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-09-17 20:38:02 -0700
commitef6c50a80f77e6da84e198a34755dd42b1b0cf1e (patch)
tree6f621fce7cf1daacd9b8abcfea990f411e8e5974
parent1b55a963a2374a14bb82eb887bb99ee91680f0eb (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
-rw-r--r--gm/annotated_text.cpp3
-rw-r--r--src/doc/SkDocument_PDF.cpp7
-rw-r--r--src/pdf/SkPDFDevice.cpp159
-rw-r--r--src/pdf/SkPDFDevice.h18
4 files changed, 106 insertions, 81 deletions
diff --git a/gm/annotated_text.cpp b/gm/annotated_text.cpp
index 7126206eeb..30f67b0201 100644
--- a/gm/annotated_text.cpp
+++ b/gm/annotated_text.cpp
@@ -34,7 +34,8 @@ DEF_SIMPLE_GM(annotated_text, canvas, 512, 512) {
const char text[] = "Click this link!";
const char url[] = "https://www.google.com/";
draw_url_annotated_text_with_box(canvas, text, 200.0f, 80.0f, p, url);
- SkAutoCanvasRestore autoCanvasRestore2(canvas, true);
+ canvas->saveLayer(nullptr, nullptr);
canvas->rotate(90);
draw_url_annotated_text_with_box(canvas, text, 150.0f, -55.0f, p, url);
+ canvas->restore();
}
diff --git a/src/doc/SkDocument_PDF.cpp b/src/doc/SkDocument_PDF.cpp
index 6c47379951..4ea9d89dd7 100644
--- a/src/doc/SkDocument_PDF.cpp
+++ b/src/doc/SkDocument_PDF.cpp
@@ -70,9 +70,10 @@ static SkPDFDict* create_pdf_page(const SkPDFDevice* pageDevice) {
SkAutoTUnref<SkPDFDict> page(new SkPDFDict("Page"));
page->insertObject("Resources", pageDevice->createResourceDict());
page->insertObject("MediaBox", pageDevice->copyMediaBox());
- if (SkPDFArray* annots = pageDevice->getAnnotations()) {
- SkASSERT(annots->size() > 0);
- page->insertObject("Annots", SkRef(annots));
+ SkAutoTUnref<SkPDFArray> annotations(new SkPDFArray);
+ pageDevice->appendAnnotations(annotations);
+ if (annotations->size() > 0) {
+ page->insertObject("Annots", annotations.detach());
}
page->insertObjRef("Contents", create_pdf_page_content(pageDevice));
return page.detach();
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());
diff --git a/src/pdf/SkPDFDevice.h b/src/pdf/SkPDFDevice.h
index fbd5fb3c9c..45aba29886 100644
--- a/src/pdf/SkPDFDevice.h
+++ b/src/pdf/SkPDFDevice.h
@@ -38,6 +38,7 @@ class SkRRect;
struct ContentEntry;
struct GraphicStateEntry;
struct NamedDestination;
+struct RectWithData;
/** \class SkPDFDevice
@@ -141,6 +142,12 @@ public:
*/
const SkTDArray<SkPDFFont*>& getFontResources() const;
+ /** Add our annotations (link to urls and destinations) to the supplied
+ * array.
+ * @param array Array to add annotations to.
+ */
+ void appendAnnotations(SkPDFArray* array) const;
+
/** Add our named destinations to the supplied dictionary.
* @param dict Dictionary to add destinations to.
* @param page The PDF object representing the page for this device.
@@ -152,10 +159,6 @@ public:
*/
SkPDFArray* copyMediaBox() const;
- /** Get the annotations from this page, or nullptr if there are none.
- */
- SkPDFArray* getAnnotations() const { return fAnnotations; }
-
/** Returns a SkStream with the page contents. The caller is responsible
* for a deleting the returned value.
*/
@@ -196,7 +199,9 @@ private:
SkMatrix fInitialTransform;
SkClipStack fExistingClipStack;
SkRegion fExistingClipRegion;
- SkPDFArray* fAnnotations;
+
+ SkTDArray<RectWithData*> fLinkToURLs;
+ SkTDArray<RectWithData*> fLinkToDestinations;
SkTDArray<NamedDestination*> fNamedDestinations;
SkTDArray<SkPDFObject*> fGraphicStateResources;
@@ -291,7 +296,8 @@ private:
const SkMatrix* prePathMatrix = nullptr);
bool handlePointAnnotation(const SkPoint* points, size_t count,
const SkMatrix& matrix, SkAnnotation* annot);
- void addAnnotation(SkPDFDict*);
+ bool handlePathAnnotation(const SkPath& path, const SkDraw& d,
+ SkAnnotation* annot);
typedef SkBaseDevice INHERITED;