aaclip needs to handle paths with holes
authorreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 16 Feb 2012 18:56:17 +0000 (18:56 +0000)
committerreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 16 Feb 2012 18:56:17 +0000 (18:56 +0000)
Review URL: https://codereview.appspot.com/5671066

git-svn-id: http://skia.googlecode.com/svn/trunk@3209 2bbb7eff-a529-9590-31e7-b0007b416f81

src/core/SkAAClip.cpp
tests/AAClipTest.cpp

index 096fd6bcf8b1dc0d7a348e51ff5443989fb6981d..5402bcf8324ef7a90db6d57d7b573132795f6737 100644 (file)
@@ -893,10 +893,10 @@ public:
         SkASSERT(count > 0);
         SkASSERT(fBounds.contains(x, y));
         SkASSERT(fBounds.contains(x + count - 1, y));
-
+        
         x -= fBounds.left();
         y -= fBounds.top();
-
+                             
         Row* row = fCurrRow;
         if (y != fPrevY) {
             SkASSERT(y > fPrevY);
@@ -1142,12 +1142,33 @@ private:
 };
 
 class SkAAClip::BuilderBlitter : public SkBlitter {
+    int fLastY;
+
+    /*
+        If we see a gap of 1 or more empty scanlines while building in Y-order,
+        we inject an explicit empty scanline (alpha==0)
+     
+        See AAClipTest.cpp : test_path_with_hole()
+     */
+    void checkForYGap(int y) {
+        SkASSERT(y >= fLastY);
+        if (fLastY > -SK_MaxS32) {
+            int gap = y - fLastY;
+            if (gap > 1) {
+                fBuilder->addRun(fLeft, y - 1, 0, fRight - fLeft);
+            }
+        }
+        fLastY = y;
+    }
+
 public:
+
     BuilderBlitter(Builder* builder) {
         fBuilder = builder;
         fLeft = builder->getBounds().fLeft;
         fRight = builder->getBounds().fRight;
         fMinY = SK_MaxS32;
+        fLastY = -SK_MaxS32;    // sentinel
     }
 
     void finish() {
@@ -1170,6 +1191,7 @@ public:
 
     virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE {
         this->recordMinY(y);
+        this->checkForYGap(y);
         fBuilder->addRectRun(x, y, width, height);
     }
 
@@ -1188,12 +1210,14 @@ public:
 
     virtual void blitH(int x, int y, int width) SK_OVERRIDE {
         this->recordMinY(y);
+        this->checkForYGap(y);
         fBuilder->addRun(x, y, 0xFF, width);
     }
 
     virtual void blitAntiH(int x, int y, const SkAlpha alpha[],
                            const int16_t runs[]) SK_OVERRIDE {
         this->recordMinY(y);
+        this->checkForYGap(y);
         for (;;) {
             int count = *runs;
             if (count <= 0) {
index b3051fdd826ab69e445cb4250c1b25ad7706de05..194b92680c94230b1fb737a13bdfd24bf5fe6fe2 100644 (file)
@@ -272,15 +272,53 @@ static void test_irect(skiatest::Reporter* reporter) {
             }
             REPORTER_ASSERT(reporter, nonEmptyAA == nonEmptyBW);
             REPORTER_ASSERT(reporter, clip2.getBounds() == rgn2.getBounds());
+            
+            SkMask maskBW, maskAA;
+            copyToMask(rgn2, &maskBW);
+            clip2.copyToMask(&maskAA);
+            REPORTER_ASSERT(reporter, maskBW == maskAA);
         }
     }
 }
 
+static void test_path_with_hole(skiatest::Reporter* reporter) {
+    static const uint8_t gExpectedImage[] = {
+        0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF,
+        0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00,
+        0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF,
+    };
+    SkMask expected;
+    expected.fBounds.set(0, 0, 4, 6);
+    expected.fRowBytes = 4;
+    expected.fFormat = SkMask::kA8_Format;
+    expected.fImage = (uint8_t*)gExpectedImage;
+
+    SkPath path;
+    path.addRect(SkRect::MakeXYWH(0, 0,
+                                  SkIntToScalar(4), SkIntToScalar(2)));
+    path.addRect(SkRect::MakeXYWH(0, SkIntToScalar(4),
+                                  SkIntToScalar(4), SkIntToScalar(2)));
+
+    for (int i = 0; i < 2; ++i) {
+        SkAAClip clip;
+        clip.setPath(path, NULL, 1 == i);
+        
+        SkMask mask;
+        clip.copyToMask(&mask);
+        
+        REPORTER_ASSERT(reporter, expected == mask);
+    }
+}
+
 static void TestAAClip(skiatest::Reporter* reporter) {
     test_empty(reporter);
     test_path_bounds(reporter);
     test_irect(reporter);
     test_rgn(reporter);
+    test_path_with_hole(reporter);
 }
 
 #include "TestClassDef.h"