Reland "SkPDF: Annotations are clipped by canvas clip stack."

Original patch was created by halcanary@google.com, and was reverted
because it triggered crbug.com/503541.

This patch fixes a bug in the original patch about clip path
transformation.

> Also, remove some SkPDFDevice functions.
> Will fix this GM: http://crrev.com/1159273003
> BUG=skia:3872
> Review URL: https://codereview.chromium.org/1148263005

BUG=skia:3872
BUG=503514

Review URL: https://codereview.chromium.org/1238503007
This commit is contained in:
wangxianzhu 2015-07-17 17:23:15 -07:00 committed by Commit bot
parent 97a26d04e2
commit d76665da1c
3 changed files with 116 additions and 116 deletions

View File

@ -27,7 +27,7 @@ static void draw_url_annotated_text_with_box(
DEF_SIMPLE_GM(annotated_text, canvas, 512, 512) {
SkAutoCanvasRestore autoCanvasRestore(canvas, true);
canvas->clear(SK_ColorWHITE);
canvas->clipRect(SkRect::MakeXYWH(64, 64, 384, 384));
canvas->clipRect(SkRect::MakeXYWH(64, 64, 256, 256));
canvas->clear(0xFFEEEEEE);
SkPaint p;
p.setTextSize(40);

View File

@ -804,8 +804,10 @@ void SkPDFDevice::drawPoints(const SkDraw& d,
return;
}
if (handlePointAnnotation(points, count, *d.fMatrix, passedPaint)) {
return;
if (SkAnnotation* annotation = passedPaint.getAnnotation()) {
if (handlePointAnnotation(points, count, *d.fMatrix, annotation)) {
return;
}
}
// SkDraw::drawPoints converts to multiple calls to fDevice->drawPath.
@ -884,6 +886,79 @@ 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(SkNEW_ARGS(SkPDFDict, ("Annot")));
annotation->insertName("Subtype", "Link");
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->insertObject("Border", border.detach());
SkAutoTUnref<SkPDFArray> rect(SkNEW(SkPDFArray));
rect->reserve(4);
rect->appendScalar(translatedRect.fLeft);
rect->appendScalar(translatedRect.fTop);
rect->appendScalar(translatedRect.fRight);
rect->appendScalar(translatedRect.fBottom);
annotation->insertObject("Rect", rect.detach());
return annotation.detach();
}
static SkPDFDict* create_link_to_url(SkData* urlData, const SkRect& r) {
SkAutoTUnref<SkPDFDict> annotation(create_link_annotation(r));
SkString url(static_cast<const char *>(urlData->data()),
urlData->size() - 1);
SkAutoTUnref<SkPDFDict> action(SkNEW_ARGS(SkPDFDict, ("Action")));
action->insertName("S", "URI");
action->insertString("URI", url);
annotation->insertObject("A", action.detach());
return annotation.detach();
}
static SkPDFDict* create_link_named_dest(SkData* nameData, const SkRect& r) {
SkAutoTUnref<SkPDFDict> annotation(create_link_annotation(r));
SkString name(static_cast<const char *>(nameData->data()),
nameData->size() - 1);
annotation->insertName("Dest", name);
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 NULL;
}
void SkPDFDevice::drawRect(const SkDraw& d,
const SkRect& rect,
const SkPaint& srcPaint) {
@ -902,8 +977,17 @@ void SkPDFDevice::drawRect(const SkDraw& d,
return;
}
if (handleRectAnnotation(r, *d.fMatrix, paint)) {
return;
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());
return;
}
}
ScopedContentEntry content(this, d, paint);
@ -984,8 +1068,16 @@ void SkPDFDevice::drawPath(const SkDraw& d,
return;
}
if (handleRectAnnotation(pathPtr->getBounds(), matrix, paint)) {
return;
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());
return;
}
}
ScopedContentEntry content(this, d.fClipStack, *d.fClip, matrix, paint);
@ -1476,40 +1568,30 @@ bool SkPDFDevice::handleInversePath(const SkDraw& d, const SkPath& origPath,
return true;
}
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) {
handleLinkToURL(urlData, r, matrix);
return p.getAnnotation() != NULL;
}
SkData* linkToName = annotationInfo->find(
SkAnnotationKeys::Link_Named_Dest_Key());
if (linkToName) {
handleLinkToNamedDest(linkToName, r, matrix);
return p.getAnnotation() != NULL;
}
return false;
}
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,
const SkPaint& paint) {
SkAnnotation* annotationInfo = paint.getAnnotation();
if (!annotationInfo) {
return false;
}
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++) {
defineNamedDestination(nameData, points[i], matrix);
SkPoint translatedPoint;
transform.mapXY(points[i].x(), points[i].y(), &translatedPoint);
fNamedDestinations.push(
SkNEW_ARGS(NamedDestination, (nameData, translatedPoint)));
}
return paint.getAnnotation() != NULL;
return true;
}
return false;
}
@ -1521,80 +1603,6 @@ void SkPDFDevice::addAnnotation(SkPDFDict* annotation) {
fAnnotations->appendObject(annotation);
}
static SkPDFDict* create_link_annotation(const SkRect& r,
const SkMatrix& initialTransform,
const SkMatrix& matrix) {
SkMatrix transform = matrix;
transform.postConcat(initialTransform);
SkRect translatedRect;
transform.mapRect(&translatedRect, r);
SkAutoTUnref<SkPDFDict> annotation(SkNEW_ARGS(SkPDFDict, ("Annot")));
annotation->insertName("Subtype", "Link");
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->insertObject("Border", border.detach());
SkAutoTUnref<SkPDFArray> rect(SkNEW(SkPDFArray));
rect->reserve(4);
rect->appendScalar(translatedRect.fLeft);
rect->appendScalar(translatedRect.fTop);
rect->appendScalar(translatedRect.fRight);
rect->appendScalar(translatedRect.fBottom);
annotation->insertObject("Rect", rect.detach());
return annotation.detach();
}
void SkPDFDevice::handleLinkToURL(SkData* urlData, const SkRect& r,
const SkMatrix& matrix) {
SkAutoTUnref<SkPDFDict> annotation(
create_link_annotation(r, fInitialTransform, matrix));
SkString url(static_cast<const char *>(urlData->data()),
urlData->size() - 1);
SkAutoTUnref<SkPDFDict> action(SkNEW_ARGS(SkPDFDict, ("Action")));
action->insertName("S", "URI");
action->insertString("URI", url);
annotation->insertObject("A", action.detach());
this->addAnnotation(annotation.detach());
}
void SkPDFDevice::handleLinkToNamedDest(SkData* nameData, const SkRect& r,
const SkMatrix& matrix) {
SkAutoTUnref<SkPDFDict> annotation(
create_link_annotation(r, fInitialTransform, matrix));
SkString name(static_cast<const char *>(nameData->data()),
nameData->size() - 1);
annotation->insertName("Dest", name);
this->addAnnotation(annotation.detach());
}
struct NamedDestination {
const SkData* nameData;
SkPoint point;
NamedDestination(const SkData* nameData, const SkPoint& point)
: nameData(SkRef(nameData)), point(point) {}
~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) const {
int nDest = fNamedDestinations.count();

View File

@ -292,17 +292,9 @@ private:
bool handleInversePath(const SkDraw& d, const SkPath& origPath,
const SkPaint& paint, bool pathIsMutable,
const SkMatrix* prePathMatrix = NULL);
bool handleRectAnnotation(const SkRect& r, const SkMatrix& matrix,
const SkPaint& paint);
bool handlePointAnnotation(const SkPoint* points, size_t count,
const SkMatrix& matrix, const SkPaint& paint);
const SkMatrix& matrix, SkAnnotation* annot);
void addAnnotation(SkPDFDict*);
void handleLinkToURL(SkData* urlData, const SkRect& r,
const SkMatrix& matrix);
void handleLinkToNamedDest(SkData* nameData, const SkRect& r,
const SkMatrix& matrix);
void defineNamedDestination(SkData* nameData, const SkPoint& point,
const SkMatrix& matrix);
typedef SkBaseDevice INHERITED;