Fix bug in raster implementation of SkRRectsGaussianEdgeMaskFilter

The bug was the raster version didn't correctly handle the CTM.

This CL also adds a way to test the behavior (by translating the
reveal GM around in SampleApp)

GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=3729

Change-Id: Iaacc905167d20b453203307e5ef840f552fdbb38
Reviewed-on: https://skia-review.googlesource.com/3729
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Robert Phillips 2016-10-20 11:58:40 -04:00 committed by Skia Commit-Bot
parent ddb37d67ba
commit d2fe3bce07
2 changed files with 45 additions and 13 deletions

View File

@ -28,7 +28,9 @@ constexpr int kClipOffset = 32;
class Object {
public:
virtual ~Object() {}
virtual bool asRRect(SkRRect* rr) const = 0;
// When it returns true, this call will have placed a device-space _circle, rect or
// simple circular_ RRect in "rr"
virtual bool asDevSpaceRRect(const SkMatrix& ctm, SkRRect* rr) const = 0;
virtual SkPath asPath(SkScalar inset) const = 0;
virtual void draw(SkCanvas* canvas, const SkPaint& paint) const = 0;
virtual void clip(SkCanvas* canvas) const = 0;
@ -44,8 +46,24 @@ public:
fRRect = SkRRect::MakeRectXY(r, 4*kPad, 4*kPad);
}
bool asRRect(SkRRect* rr) const override {
*rr = fRRect;
bool asDevSpaceRRect(const SkMatrix& ctm, SkRRect* rr) const override {
if (!ctm.isSimilarity()) { // the corners have to remain circular
return false;
}
SkScalar scales[2];
if (!ctm.getMinMaxScales(scales)) {
return false;
}
SkASSERT(SkScalarNearlyEqual(scales[0], scales[1]));
SkRect devRect;
ctm.mapRect(&devRect, fRRect.rect());
SkScalar scaledRad = scales[0] * fRRect.getSimpleRadii().fX;
*rr = SkRRect::MakeRectXY(devRect, scaledRad, scaledRad);
return true;
}
@ -88,7 +106,7 @@ public:
fStrokedBounds = r.makeOutset(kPad, kPad);
}
bool asRRect(SkRRect* rr) const override {
bool asDevSpaceRRect(const SkMatrix& ctm, SkRRect* rr) const override {
return false;
}
@ -144,8 +162,14 @@ public:
fRRect = SkRRect::MakeOval(r);
}
bool asRRect(SkRRect* rr) const override {
*rr = fRRect;
bool asDevSpaceRRect(const SkMatrix& ctm, SkRRect* rr) const override {
if (!ctm.isSimilarity()) { // circles have to remain circles
return false;
}
SkRect devRect;
ctm.mapRect(&devRect, fRRect.rect());
*rr = SkRRect::MakeOval(devRect);
return true;
}
@ -186,8 +210,14 @@ class Rect : public Object {
public:
Rect(const SkRect& r) : fRect(r) { }
bool asRRect(SkRRect* rr) const override {
*rr = SkRRect::MakeRect(fRect);
bool asDevSpaceRRect(const SkMatrix& ctm, SkRRect* rr) const override {
if (!ctm.rectStaysRect()) {
return false;
}
SkRect devRect;
ctm.mapRect(&devRect, fRect);
*rr = SkRRect::MakeRect(devRect);
return true;
}
@ -246,7 +276,7 @@ public:
fPath.close();
}
bool asRRect(SkRRect* rr) const override {
bool asDevSpaceRRect(const SkMatrix& ctm, SkRRect* rr) const override {
return false;
}
@ -311,6 +341,7 @@ public:
}
protected:
bool runAsBench() const override { return true; }
SkString onShortName() override {
return SkString("reveal");
@ -393,10 +424,12 @@ protected:
SkPaint paint;
SkRRect clipRR, drawnRR;
SkRRect devSpaceClipRR, devSpaceDrawnRR;
if (clipObj->asRRect(&clipRR) && drawObj->asRRect(&drawnRR)) {
paint.setMaskFilter(SkRRectsGaussianEdgeMaskFilter::Make(clipRR, drawnRR,
if (clipObj->asDevSpaceRRect(canvas->getTotalMatrix(), &devSpaceClipRR) &&
drawObj->asDevSpaceRRect(canvas->getTotalMatrix(), &devSpaceDrawnRR)) {
paint.setMaskFilter(SkRRectsGaussianEdgeMaskFilter::Make(devSpaceClipRR,
devSpaceDrawnRR,
fBlurRadius));
}

View File

@ -160,7 +160,6 @@ bool SkRRectsGaussianEdgeMaskFilterImpl::filterMask(SkMask* dst, const SkMask& s
uint8_t* dstPixels = dst->fImage = SkMask::AllocImage(dstSize);
SkPoint basePt = { SkIntToScalar(src.fBounds.fLeft), SkIntToScalar(src.fBounds.fTop) };
matrix.mapPoints(&basePt, 1);
for (int y = 0; y < dst->fBounds.height(); ++y) {
const uint8_t* srcRow = srcPixels + y * dst->fRowBytes;