implement region-ops



git-svn-id: http://skia.googlecode.com/svn/trunk@2436 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/samplecode/SampleAAClip2.cpp b/samplecode/SampleAAClip2.cpp
index bdb3741..b3d7b6d 100644
--- a/samplecode/SampleAAClip2.cpp
+++ b/samplecode/SampleAAClip2.cpp
@@ -57,22 +57,19 @@
         this->setBGColor(0xFFDDDDDD);
     }
 
-    void build_rgn(SkAAClip* clip, SkRegion::Op op) {
-        clip->setRect(fBase);
-#if 0
-        SkIRect r = fBase;
-        r.offset(75, 20);
-        rgn->op(r, SkRegion::kUnion_Op);
-#endif
-
+    static void setAAClip(SkAAClip* clip, const SkIRect& rect) {
         SkRect r;
-        r.set(fRect);
+        r.set(rect);
         SkPath path;
-        path.addOval(r);
+        path.addRoundRect(r, SkIntToScalar(5), SkIntToScalar(5));
+        clip->setPath(path);
+    }
+
+    void build_rgn(SkAAClip* clip, SkRegion::Op op) {
+        setAAClip(clip, fBase);
+
         SkAAClip clip2;
-        clip2.setPath(path);
-        // hack
-        op = SkRegion::kIntersect_Op;
+        setAAClip(&clip2, fRect);
         clip->op(clip2, op);
     }
 
@@ -101,6 +98,17 @@
         canvas->drawRect(r, paint);
     }
     
+    static void outer_frame(SkCanvas* canvas, const SkIRect& rect) {
+        SkRect r;
+        r.set(rect);
+        r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
+        
+        SkPaint paint;
+        paint.setColor(SK_ColorGRAY);
+        paint.setStyle(SkPaint::kStroke_Style);
+        canvas->drawRect(r, paint);
+    }
+
     void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
         SkAAClip clip;
 
@@ -115,6 +123,11 @@
         paint.setStyle(SkPaint::kStroke_Style);
         paint.setColor(color);
         paint_rgn(canvas, clip, paint);
+        
+        SkAAClip clip2(clip);
+        clip2.offset(0, 80);
+        outer_frame(canvas, clip2.getBounds());
+        paint_rgn(canvas, clip2, paint);
     }
     
     virtual void onDrawContent(SkCanvas* canvas) {
@@ -135,10 +148,6 @@
         textPaint.setTextSize(SK_Scalar1*24);
 
         this->drawOrig(canvas, false);
-        canvas->save();
-            canvas->translate(SkIntToScalar(200), 0);
-            this->drawRgnOped(canvas, SkRegion::kUnion_Op, SK_ColorBLACK);
-        canvas->restore();
         
         canvas->translate(0, SkIntToScalar(200));
 
diff --git a/src/core/SkAAClip.cpp b/src/core/SkAAClip.cpp
index ff5715e..3e74031 100644
--- a/src/core/SkAAClip.cpp
+++ b/src/core/SkAAClip.cpp
@@ -12,6 +12,8 @@
 #include "SkScan.h"
 #include "SkThread.h"
 
+#define kMaxInt32   0x7FFFFFFF
+
 static inline bool x_in_rect(int x, const SkIRect& rect) {
     return (unsigned)(x - rect.fLeft) < (unsigned)rect.width();
 }
@@ -62,9 +64,9 @@
     Iter(const SkAAClip&);
 
     bool done() const { return fDone; }
-    int top() const { SkASSERT(!fDone); return fTop; }
-    int bottom() const { SkASSERT(!fDone); return fBottom; }
-    const uint8_t* data() const { SkASSERT(!fDone); return fData; }
+    int top() const { return fTop; }
+    int bottom() const { return fBottom; }
+    const uint8_t* data() const { return fData; }
     void next();
 
 private:
@@ -79,6 +81,8 @@
 SkAAClip::Iter::Iter(const SkAAClip& clip) {
     if (clip.isEmpty()) {
         fDone = true;
+        fTop = fBottom = clip.fBounds.fBottom;
+        fData = NULL;
         return;
     }
     
@@ -94,18 +98,21 @@
 }
 
 void SkAAClip::Iter::next() {
-    SkASSERT(!fDone);
+    if (!fDone) {
+        const YOffset* prev = fCurrYOff;
+        const YOffset* curr = prev + 1;
+        SkASSERT(curr <= fStopYOff);
 
-    const YOffset* prev = fCurrYOff;
-    const YOffset* curr = prev + 1;
-
-    if (curr >= fStopYOff) {
-        fDone = true;
-    } else {
         fTop = fBottom;
-        fBottom += curr->fY - prev->fY;
-        fData += curr->fOffset - prev->fOffset;
-        fCurrYOff = curr;
+        if (curr >= fStopYOff) {
+            fDone = true;
+            fBottom = kMaxInt32;
+            fData = NULL;
+        } else {
+            fBottom += curr->fY - prev->fY;
+            fData += curr->fOffset - prev->fOffset;
+            fCurrYOff = curr;
+        }
     }
 }
 
@@ -395,7 +402,7 @@
             SkDebugf("\n");
         }
 
-#if 1
+#if 0
         int prevY = -1;
         for (y = 0; y < fRows.count(); ++y) {
             const Row& row = fRows[y];
@@ -635,25 +642,36 @@
     RowIter(const uint8_t* row, const SkIRect& bounds) {
         fRow = row;
         fLeft = bounds.fLeft;
-        fRight = bounds.fLeft + row[0];
         fBoundsRight = bounds.fRight;
-        SkASSERT(fRight <= fBoundsRight);
-        fDone = false;
+        if (row) {
+            fRight = bounds.fLeft + row[0];
+            SkASSERT(fRight <= fBoundsRight);
+            fAlpha = row[1];
+            fDone = false;
+        } else {
+            fDone = true;
+            fRight = kMaxInt32;
+            fAlpha = 0;
+        }
     }
 
     bool done() const { return fDone; }
-    int left() const { SkASSERT(!done()); return fLeft; }
-    int right() const { SkASSERT(!done()); return fRight; }
-    U8CPU alpha() const { SkASSERT(!done()); return fRow[1]; }
+    int left() const { return fLeft; }
+    int right() const { return fRight; }
+    U8CPU alpha() const { return fAlpha; }
     void next() {
-        SkASSERT(!done());
-        if (fRight == fBoundsRight) {
-            fDone = true;
-        } else {
-            fRow += 2;
+        if (!fDone) {
             fLeft = fRight;
-            fRight += fRow[0];
-            SkASSERT(fRight <= fBoundsRight);
+            if (fRight == fBoundsRight) {
+                fDone = true;
+                fRight = kMaxInt32;
+                fAlpha = 0;
+            } else {
+                fRow += 2;
+                fRight += fRow[0];
+                fAlpha = fRow[1];
+                SkASSERT(fRight <= fBoundsRight);
+            }
         }
     }
 
@@ -663,99 +681,94 @@
     int             fRight;
     int             fBoundsRight;
     bool            fDone;
+    uint8_t         fAlpha;
 };
 
-static void adjust_row(RowIter& iter, int& leftA, int& riteA,
-                       int left, int rite) {
-    if (leftA == left) {
-        leftA = rite;
-        if (leftA == riteA) {
-            if (iter.done()) {
-                leftA = 0x7FFFFFFF;
-                riteA = 0x7FFFFFFF;
-            } else {
-                iter.next();
-                leftA = iter.left();
-                riteA = iter.right();
-            }
-        }
+static void adjust_row(RowIter& iter, int& leftA, int& riteA, int rite) {
+    if (rite == riteA) {
+        iter.next();
+        leftA = iter.left();
+        riteA = iter.right();
     }
 }
 
+static bool intersect(int& min, int& max, int boundsMin, int boundsMax) {
+    SkASSERT(min < max);
+    SkASSERT(boundsMin < boundsMax);
+    if (min >= boundsMax || max <= boundsMin) {
+        return false;
+    }
+    if (min < boundsMin) {
+        min = boundsMin;
+    }
+    if (max > boundsMax) {
+        max = boundsMax;
+    }
+    return true;
+}
+
 static void operatorX(SkAAClip::Builder& builder, int lastY,
                       RowIter& iterA, RowIter& iterB,
                       AlphaProc proc, const SkIRect& bounds) {
-    SkASSERT(!iterA.done());
     int leftA = iterA.left();
     int riteA = iterA.right();
-    SkASSERT(!iterB.done());
     int leftB = iterB.left();
     int riteB = iterB.right();
 
-    for (;;) {
+    int prevRite = bounds.fLeft;
+
+    do {
         U8CPU alphaA = 0;
         U8CPU alphaB = 0;
-        
         int left, rite;
-        if (riteA <= leftB) {         // all A
+ 
+        if (leftA < leftB) {
             left = leftA;
-            rite = riteA;
             alphaA = iterA.alpha();
-        } else if (riteB <= leftA) {  // all B
-            left = leftB;
-            rite = riteB;
-            alphaB = iterB.alpha();
-        } else {
-            // some overlap
-            alphaA = iterA.alpha();
-            alphaB = iterB.alpha();
-            if (leftA <= leftB) {
-                left = leftA;
-                if (leftA == leftB) {
-                    rite = SkMin32(riteA, riteB);
-                } else{
-                    rite = leftB;
-                }
-            } else {    // leftB < leftA
-                left = leftB;
-                rite = leftA;
+            if (riteA <= leftB) {
+                rite = riteA;
+            } else {
+                rite = leftA = leftB;
             }
+        } else if (leftB < leftA) {
+            left = leftB;
+            alphaB = iterB.alpha();
+            if (riteB <= leftA) {
+                rite = riteB;
+            } else {
+                rite = leftB = leftA;
+            }
+        } else {
+            left = leftA;   // or leftB, since leftA == leftB
+            rite = leftA = leftB = SkMin32(riteA, riteB);
+            alphaA = iterA.alpha();
+            alphaB = iterB.alpha();
         }
 
         if (left >= bounds.fRight) {
             break;
         }
-        
-        SkASSERT(rite <= bounds.fRight);
         if (left >= bounds.fLeft) {
+            SkASSERT(rite > left);
             builder.addRun(left, lastY, proc(alphaA, alphaB), rite - left);
-        } else {
-            SkASSERT(rite <= bounds.fLeft);
+            prevRite = rite;
         }
-        
-        if (rite == bounds.fRight) {
-            break;
-        }
-        
-        adjust_row(iterA, leftA, riteA, left, rite);
-        adjust_row(iterB, leftB, riteB, left, rite);
+
+        adjust_row(iterA, leftA, riteA, rite);
+        adjust_row(iterB, leftB, riteB, rite);
+    } while (!iterA.done() || !iterB.done());
+
+    if (prevRite < bounds.fRight) {
+        builder.addRun(prevRite, lastY, 0, bounds.fRight - prevRite);
     }
 }
 
-static void adjust_iter(SkAAClip::Iter& iter, int& topA, int& botA,
-                        int top, int bot) {
-    if (topA == top) {
-        topA = bot;
-        if (topA == botA) {
-            if (iter.done()) {
-                topA = 0x7FFFFFFF;
-                botA = 0x7FFFFFFF;
-            } else {
-                iter.next();
-                topA = iter.top();
-                botA = iter.bottom();
-            }
-        }
+static void adjust_iter(SkAAClip::Iter& iter, int& topA, int& botA, int bot) {
+    if (bot == botA) {
+        iter.next();
+        topA = botA;
+        SkASSERT(botA == iter.top());
+        botA = iter.bottom();
     }
 }
 
@@ -774,61 +787,50 @@
     int topB = iterB.top();
     int botB = iterB.bottom();
 
-    for (;;) {
-        SkASSERT(topA < botA);
-        SkASSERT(topB < botB);
-
-        const uint8_t* rowA = gEmptyRow;
-        const uint8_t* rowB = gEmptyRow;
-
-        // find the vertical
+    do {
+        const uint8_t* rowA = NULL;
+        const uint8_t* rowB = NULL;
         int top, bot;
-        if (botA <= topB) {         // all A
+
+        if (topA < topB) {
             top = topA;
-            bot = botA;
             rowA = iterA.data();
-        } else if (botB <= topA) {  // all B
-            top = topB;
-            bot = botB;
-            rowB = iterB.data();
-        } else {
-            // some overlap
-            rowA = iterA.data();
-            rowB = iterB.data();
-            if (topA <= topB) {
-                top = topA;
-                if (topA == topB) {
-                    bot = SkMin32(botA, botB);
-                } else{
-                    bot = topB;
-                }
-            } else {    // topB < topA
-                top = topB;
-                bot = topA;
+            if (botA <= topB) {
+                bot = botA;
+            } else {
+                bot = topA = topB;
             }
+            
+        } else if (topB < topA) {
+            top = topB;
+            rowB = iterB.data();
+            if (botB <= topA) {
+                bot = botB;
+            } else {
+                bot = topB = topA;
+            }
+        } else {
+            top = topA;   // or topB, since topA == topB
+            bot = topA = topB = SkMin32(botA, botB);
+            rowA = iterA.data();
+            rowB = iterB.data();
         }
 
         if (top >= bounds.fBottom) {
             break;
         }
-
-        SkASSERT(bot <= bounds.fBottom);
-        if (top >= bounds.fTop) {
-            RowIter rowIterA(rowA, A.getBounds());
-            RowIter rowIterB(rowB, B.getBounds());
+        if (!rowA && !rowB) {
+            builder.addRun(bounds.fLeft, bot - 1, 0, bounds.width());
+        } else if (top >= bounds.fTop) {
+            SkASSERT(bot <= bounds.fBottom);
+            RowIter rowIterA(rowA, rowA ? A.getBounds() : bounds);
+            RowIter rowIterB(rowB, rowB ? B.getBounds() : bounds);
             operatorX(builder, bot - 1, rowIterA, rowIterB, proc, bounds);
-        } else {
-            SkASSERT(bot <= bounds.fTop);
         }
 
-        if (bot == bounds.fBottom) {
-            break;
-        }
-        
-        adjust_iter(iterA, topA, botA, top, bot);
-        adjust_iter(iterB, topB, botB, top, bot);
-    }
-    
+        adjust_iter(iterA, topA, botA, bot);
+        adjust_iter(iterB, topB, botB, bot);
+    } while (!iterA.done() || !iterB.done());
 }
 
 bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig,
@@ -884,7 +886,6 @@
             return !this->isEmpty();
     }
 
-    SkASSERT(SkIRect::Intersects(clipA->fBounds, clipB->fBounds));
     SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
     SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
 
@@ -1078,6 +1079,32 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+bool SkAAClip::offset(int dx, int dy) {
+    if (this->isEmpty()) {
+        return false;
+    }
+
+    fBounds.offset(dx, dy);
+    return true;
+}
+
+bool SkAAClip::offset(int dx, int dy, SkAAClip* dst) const {
+    if (this == dst) {
+        return dst->offset(dx, dy);
+    }
+
+    dst->setEmpty();
+    if (this->isEmpty()) {
+        return false;
+    }
+
+    sk_atomic_inc(&fRunHead->fRefCnt);
+    dst->fRunHead = fRunHead;
+    dst->fBounds = fBounds;
+    dst->fBounds.offset(dx, dy);
+    return true;
+}
+
 static void expand_row_to_mask(uint8_t* SK_RESTRICT mask,
                                const uint8_t* SK_RESTRICT row,
                                int width) {
diff --git a/src/core/SkAAClip.h b/src/core/SkAAClip.h
index cebe97c..dadf951 100644
--- a/src/core/SkAAClip.h
+++ b/src/core/SkAAClip.h
@@ -42,6 +42,9 @@
     bool op(const SkRect&, SkRegion::Op);
     bool op(const SkAAClip&, SkRegion::Op);
 
+    bool offset(int dx, int dy);
+    bool offset(int dx, int dy, SkAAClip* dst) const;
+
     /**
      *  Allocates a mask the size of the aaclip, and expands its data into
      *  the mask, using kA8_Format