add isRect() check to AAClip, to detect if a soft-clip is really just an irect
authorreed <reed@google.com>
Thu, 7 Aug 2014 18:48:10 +0000 (11:48 -0700)
committerCommit bot <commit-bot@chromium.org>
Thu, 7 Aug 2014 18:48:10 +0000 (11:48 -0700)
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
src/core/SkAAClip.h
src/core/SkRasterClip.cpp
src/core/SkRasterClip.h
tests/AAClipTest.cpp

index 14152f8..5d21a47 100644 (file)
@@ -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();
index f2cde62..c36a3e9 100644 (file)
@@ -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);
index 664211f..d1615a3 100644 (file)
@@ -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
index 0c27233..29a925f 100644 (file)
@@ -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;
     }
index 26c1ec1..776cd52 100644 (file)
@@ -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);
 }