From 202ab2a5cabaf25a1e6ec47c0003da3213a79864 Mon Sep 17 00:00:00 2001 From: reed Date: Thu, 7 Aug 2014 11:48:10 -0700 Subject: [PATCH] add isRect() check to AAClip, to detect if a soft-clip is really just an irect taken from (https://codereview.chromium.org/445233006/) fix: don't assume that the first yoffset is 0, since we may have performed a translate and not re-alloced our data. This reverts commit 0aeea6d344f12e35e29a79f4bbc48af88f913204. TBR= Author: reed@google.com Review URL: https://codereview.chromium.org/443353004 --- src/core/SkAAClip.cpp | 28 ++++++++++++++++++++++++++++ src/core/SkAAClip.h | 4 ++++ src/core/SkRasterClip.cpp | 5 ++++- src/core/SkRasterClip.h | 12 ++++++++++-- tests/AAClipTest.cpp | 25 +++++++++++++++++++++++++ 5 files changed, 71 insertions(+), 3 deletions(-) diff --git a/src/core/SkAAClip.cpp b/src/core/SkAAClip.cpp index 14152f8..5d21a47 100644 --- a/src/core/SkAAClip.cpp +++ b/src/core/SkAAClip.cpp @@ -684,6 +684,34 @@ bool SkAAClip::setRect(const SkIRect& bounds) { #endif } +bool SkAAClip::isRect() const { + if (this->isEmpty()) { + return false; + } + + const RunHead* head = fRunHead; + if (head->fRowCount != 1) { + return false; + } + const YOffset* yoff = head->yoffsets(); + if (yoff->fY != fBounds.fBottom - 1) { + return false; + } + + const uint8_t* row = head->data() + yoff->fOffset; + int width = fBounds.width(); + do { + if (row[1] != 0xFF) { + return false; + } + int n = row[0]; + SkASSERT(n <= width); + width -= n; + row += 2; + } while (width > 0); + return true; +} + bool SkAAClip::setRect(const SkRect& r, bool doAA) { if (r.isEmpty()) { return this->setEmpty(); diff --git a/src/core/SkAAClip.h b/src/core/SkAAClip.h index f2cde62..c36a3e9 100644 --- a/src/core/SkAAClip.h +++ b/src/core/SkAAClip.h @@ -29,6 +29,10 @@ public: bool isEmpty() const { return NULL == fRunHead; } const SkIRect& getBounds() const { return fBounds; } + // Returns true iff the clip is not empty, and is just a hard-edged rect (no partial alpha). + // If true, getBounds() can be used in place of this clip. + bool isRect() const; + bool setEmpty(); bool setRect(const SkIRect&); bool setRect(const SkRect&, bool doAA = true); diff --git a/src/core/SkRasterClip.cpp b/src/core/SkRasterClip.cpp index 664211f..d1615a3 100644 --- a/src/core/SkRasterClip.cpp +++ b/src/core/SkRasterClip.cpp @@ -222,7 +222,10 @@ void SkRasterClip::convertToAA() { SkASSERT(fIsBW); fAA.setRegion(fBW); fIsBW = false; - (void)this->updateCacheAndReturnNonEmpty(); + + // since we are being explicitly asked to convert-to-aa, we pass false so we don't "optimize" + // ourselves back to BW. + (void)this->updateCacheAndReturnNonEmpty(false); } #ifdef SK_DEBUG diff --git a/src/core/SkRasterClip.h b/src/core/SkRasterClip.h index 0c27233..29a925f 100644 --- a/src/core/SkRasterClip.h +++ b/src/core/SkRasterClip.h @@ -89,11 +89,19 @@ private: } bool computeIsRect() const { - return fIsBW ? fBW.isRect() : false; + return fIsBW ? fBW.isRect() : fAA.isRect(); } - bool updateCacheAndReturnNonEmpty() { + bool updateCacheAndReturnNonEmpty(bool detectAARect = true) { fIsEmpty = this->computeIsEmpty(); + + // detect that our computed AA is really just a (hard-edged) rect + if (detectAARect && !fIsEmpty && !fIsBW && fAA.isRect()) { + fBW.setRect(fAA.getBounds()); + fAA.setEmpty(); // don't need this guy anymore + fIsBW = true; + } + fIsRect = this->computeIsRect(); return !fIsEmpty; } diff --git a/tests/AAClipTest.cpp b/tests/AAClipTest.cpp index 26c1ec1..776cd52 100644 --- a/tests/AAClipTest.cpp +++ b/tests/AAClipTest.cpp @@ -318,6 +318,30 @@ static void test_path_with_hole(skiatest::Reporter* reporter) { } } +static void test_really_a_rect(skiatest::Reporter* reporter) { + SkRRect rrect; + rrect.setRectXY(SkRect::MakeWH(100, 100), 5, 5); + + SkPath path; + path.addRRect(rrect); + + SkAAClip clip; + clip.setPath(path); + + REPORTER_ASSERT(reporter, clip.getBounds() == SkIRect::MakeWH(100, 100)); + REPORTER_ASSERT(reporter, !clip.isRect()); + + // This rect should intersect the clip, but slice-out all of the "soft" parts, + // leaving just a rect. + const SkIRect ir = SkIRect::MakeLTRB(10, -10, 50, 90); + + clip.op(ir, SkRegion::kIntersect_Op); + + REPORTER_ASSERT(reporter, clip.getBounds() == SkIRect::MakeLTRB(10, 0, 50, 90)); + // the clip recognized that that it is just a rect! + REPORTER_ASSERT(reporter, clip.isRect()); +} + #include "SkRasterClip.h" static void copyToMask(const SkRasterClip& rc, SkMask* mask) { @@ -404,4 +428,5 @@ DEF_TEST(AAClip, reporter) { test_path_with_hole(reporter); test_regressions(); test_nearly_integral(reporter); + test_really_a_rect(reporter); } -- 2.7.4