diff options
-rw-r--r-- | src/core/SkRasterClip.cpp | 24 | ||||
-rw-r--r-- | tests/AAClipTest.cpp | 62 |
2 files changed, 77 insertions, 9 deletions
diff --git a/src/core/SkRasterClip.cpp b/src/core/SkRasterClip.cpp index 9a845de31e..aea731e1af 100644 --- a/src/core/SkRasterClip.cpp +++ b/src/core/SkRasterClip.cpp @@ -150,21 +150,27 @@ bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) { return this->updateCacheAndReturnNonEmpty(); } -// return true if x is nearly integral (within 1/16) since that is the highest -// precision our aa code can have. -static bool is_integral(SkScalar x) { - int ix = SkScalarRoundToInt(x); - SkScalar sx = SkIntToScalar(ix); - return SkScalarAbs(sx - x) < (SK_Scalar1 / 16); +/** + * Our antialiasing currently has a granularity of 1/4 of a pixel along each + * axis. Thus we can treat an axis coordinate as an integer if it differs + * from its nearest int by < half of that value (1.8 in this case). + */ +static bool nearly_integral(SkScalar x) { + static const SkScalar domain = SK_Scalar1 / 4; + static const SkScalar halfDomain = domain / 2; + + x += halfDomain; + return x - SkScalarFloorToScalar(x) < domain; } bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) { AUTO_RASTERCLIP_VALIDATE(*this); if (fIsBW && doAA) { - // check that the rect really needs aa - if (is_integral(r.fLeft) && is_integral(r.fTop) && - is_integral(r.fRight) && is_integral(r.fBottom)) { + // check that the rect really needs aa, or is it close enought to + // integer boundaries that we can just treat it as a BW rect? + if (nearly_integral(r.fLeft) && nearly_integral(r.fTop) && + nearly_integral(r.fRight) && nearly_integral(r.fBottom)) { doAA = false; } } diff --git a/tests/AAClipTest.cpp b/tests/AAClipTest.cpp index 2898f30880..bf52b01acd 100644 --- a/tests/AAClipTest.cpp +++ b/tests/AAClipTest.cpp @@ -316,6 +316,67 @@ static void test_path_with_hole(skiatest::Reporter* reporter) { } } +#include "SkRasterClip.h" + +static void copyToMask(const SkRasterClip& rc, SkMask* mask) { + if (rc.isAA()) { + rc.aaRgn().copyToMask(mask); + } else { + copyToMask(rc.bwRgn(), mask); + } +} + +static bool operator==(const SkRasterClip& a, const SkRasterClip& b) { + if (a.isEmpty()) { + return b.isEmpty(); + } + if (b.isEmpty()) { + return false; + } + + SkMask ma, mb; + copyToMask(a, &ma); + copyToMask(b, &mb); + return ma == mb; +} + +static void did_dx_affect(skiatest::Reporter* reporter, const SkScalar dx[], + size_t count, bool changed) { + SkIRect ir = { 0, 0, 10, 10 }; + + for (size_t i = 0; i < count; ++i) { + SkRect r; + r.set(ir); + + SkRasterClip rc0(ir); + SkRasterClip rc1(ir); + SkRasterClip rc2(ir); + + rc0.op(r, SkRegion::kIntersect_Op, false); + r.offset(dx[i], 0); + rc1.op(r, SkRegion::kIntersect_Op, true); + r.offset(-2*dx[i], 0); + rc2.op(r, SkRegion::kIntersect_Op, true); + + REPORTER_ASSERT(reporter, changed != (rc0 == rc1)); + REPORTER_ASSERT(reporter, changed != (rc0 == rc2)); + } +} + +static void test_nearly_integral(skiatest::Reporter* reporter) { + // All of these should generate equivalent rasterclips + + static const SkScalar gSafeX[] = { + 0, SK_Scalar1/1000, SK_Scalar1/100, SK_Scalar1/10, + }; + did_dx_affect(reporter, gSafeX, SK_ARRAY_COUNT(gSafeX), false); + + static const SkScalar gUnsafeX[] = { + SK_Scalar1/4, SK_Scalar1/3, + }; + did_dx_affect(reporter, gUnsafeX, SK_ARRAY_COUNT(gUnsafeX), true); +} + static void test_regressions(skiatest::Reporter* reporter) { // these should not assert in the debug build // bug was introduced in rev. 3209 @@ -337,6 +398,7 @@ static void TestAAClip(skiatest::Reporter* reporter) { test_rgn(reporter); test_path_with_hole(reporter); test_regressions(reporter); + test_nearly_integral(reporter); } #include "TestClassDef.h" |