enable soft clipping (yikes)
authorreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 24 Oct 2011 12:19:46 +0000 (12:19 +0000)
committerreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 24 Oct 2011 12:19:46 +0000 (12:19 +0000)
git-svn-id: http://skia.googlecode.com/svn/trunk@2515 2bbb7eff-a529-9590-31e7-b0007b416f81

26 files changed:
include/core/SkDraw.h
include/core/SkMaskFilter.h
include/core/SkScan.h
samplecode/SampleAAClip.cpp
samplecode/SampleAAClip2.cpp
samplecode/SampleApp.cpp
samplecode/SampleClip.cpp
samplecode/SampleFuzz.cpp
samplecode/SampleXfermodesBlur.cpp
src/core/SkAAClip.cpp
src/core/SkAAClip.h
src/core/SkCanvas.cpp
src/core/SkDraw.cpp
src/core/SkDrawProcs.h
src/core/SkMaskFilter.cpp
src/core/SkRasterClip.cpp
src/core/SkRasterClip.h
src/core/SkScalerContext.cpp
src/core/SkScan.cpp
src/core/SkScan_AntiPath.cpp
src/core/SkScan_Antihair.cpp
src/core/SkScan_Hairline.cpp
src/core/SkScan_Path.cpp
src/effects/Sk2DPathEffect.cpp
src/effects/SkLayerRasterizer.cpp
tests/FillPathTest.cpp

index eb87247..2ea0740 100644 (file)
@@ -23,6 +23,7 @@ class SkClipStack;
 class SkDevice;
 class SkPath;
 class SkRegion;
+class SkRasterClip;
 struct SkDrawProcs;
 
 class SkDraw {
@@ -105,7 +106,8 @@ private:
 public:
     const SkBitmap* fBitmap;        // required
     const SkMatrix* fMatrix;        // required
-    const SkRegion* fClip;          // required
+    const SkRegion* fClip;          // DEPRECATED
+    const SkRasterClip* fRC;        // required
 
     const SkClipStack* fClipStack;  // optional
     SkDevice*       fDevice;        // optional
index fe0c69f..1f1d570 100644 (file)
@@ -17,7 +17,7 @@ class SkBlitter;
 class SkBounder;
 class SkMatrix;
 class SkPath;
-class SkRegion;
+class SkRasterClip;
 
 /** \class SkMaskFilter
 
@@ -55,14 +55,6 @@ public:
     virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
                             SkIPoint* margin);
 
-    /** Helper method that, given a path in device space, will rasterize it into a kA8_Format mask
-        and then call filterMask(). If this returns true, the specified blitter will be called
-        to render that mask. Returns false if filterMask() returned false.
-        This method is not exported to java.
-    */
-    bool filterPath(const SkPath& devPath, const SkMatrix& devMatrix,
-                    const SkRegion& devClip, SkBounder*, SkBlitter* blitter);
-
     virtual void flatten(SkFlattenableWriteBuffer& ) {}
 
     enum BlurType {
@@ -90,6 +82,17 @@ public:
 protected:
     // empty for now, but lets get our subclass to remember to init us for the future
     SkMaskFilter(SkFlattenableReadBuffer&) {}
+
+private:
+    friend class SkDraw;
+
+    /** Helper method that, given a path in device space, will rasterize it into a kA8_Format mask
+     and then call filterMask(). If this returns true, the specified blitter will be called
+     to render that mask. Returns false if filterMask() returned false.
+     This method is not exported to java.
+     */
+    bool filterPath(const SkPath& devPath, const SkMatrix& devMatrix,
+                    const SkRasterClip&, SkBounder*, SkBlitter* blitter);
 };
 
 #endif
index e5ea92d..7b4cdc1 100644 (file)
@@ -24,63 +24,73 @@ typedef SkIRect SkXRect;
 
 class SkScan {
 public:
-    static void FillIRect(const SkIRect&, const SkRegion* clip, SkBlitter*);
-    static void FillXRect(const SkXRect&, const SkRegion* clip, SkBlitter*);
+    static void FillPath(const SkPath&, const SkIRect&, SkBlitter*);
+
+    ///////////////////////////////////////////////////////////////////////////
+    // rasterclip
 
+    static void FillIRect(const SkIRect&, const SkRasterClip&, SkBlitter*);
+    static void FillXRect(const SkXRect&, const SkRasterClip&, SkBlitter*);
 #ifdef SK_SCALAR_IS_FIXED
-    static void FillRect(const SkRect& rect, const SkRegion* clip,
+    static void FillRect(const SkRect& rect, const SkRasterClip& clip,
                          SkBlitter* blitter) {
         SkScan::FillXRect(*(const SkXRect*)&rect, clip, blitter);
     }
-#else
-    static void FillRect(const SkRect&, const SkRegion* clip, SkBlitter*);
-#endif
-    static void FillPath(const SkPath&, const SkRegion& clip, SkBlitter*);
-
-    static void FillTriangle(const SkPoint pts[], const SkRegion*, SkBlitter*);
-    static void FillTriangle(const SkPoint& a, const SkPoint& b,
-                             const SkPoint& c, const SkRegion* clip,
+    static void AntiFillRect(const SkRect& rect, const SkRasterClip& clip,
                              SkBlitter* blitter) {
-        SkPoint pts[3];
-        pts[0] = a;
-        pts[1] = b;
-        pts[2] = c;
-        FillTriangle(pts, clip, blitter);
+        SkScan::AntiFillXRect(*(const SkXRect*)&rect, clip, blitter);
     }
-
-    static void HairLine(const SkPoint&, const SkPoint&, const SkRegion*,
+#else
+    static void FillRect(const SkRect&, const SkRasterClip&, SkBlitter*);
+    static void AntiFillRect(const SkRect&, const SkRasterClip&, SkBlitter*);
+#endif
+    static void AntiFillXRect(const SkXRect&, const SkRasterClip&, SkBlitter*);
+    static void FillPath(const SkPath&, const SkRasterClip&, SkBlitter*);
+    static void AntiFillPath(const SkPath&, const SkRasterClip&, SkBlitter*);
+    static void FrameRect(const SkRect&, const SkPoint& strokeSize,
+                          const SkRasterClip&, SkBlitter*);
+    static void AntiFrameRect(const SkRect&, const SkPoint& strokeSize,
+                              const SkRasterClip&, SkBlitter*);
+    static void FillTriangle(const SkPoint pts[], const SkRasterClip&, SkBlitter*);
+    static void HairLine(const SkPoint&, const SkPoint&, const SkRasterClip&,
                          SkBlitter*);
-    static void HairRect(const SkRect&, const SkRegion* clip, SkBlitter*);
-    static void HairPath(const SkPath&, const SkRegion* clip, SkBlitter*);
+    static void AntiHairLine(const SkPoint&, const SkPoint&, const SkRasterClip&,
+                             SkBlitter*);
+    static void HairRect(const SkRect&, const SkRasterClip&, SkBlitter*);
+    static void AntiHairRect(const SkRect&, const SkRasterClip&, SkBlitter*);
+    static void HairPath(const SkPath&, const SkRasterClip&, SkBlitter*);
+    static void AntiHairPath(const SkPath&, const SkRasterClip&, SkBlitter*);
 
-    static void AntiFillXRect(const SkXRect&, const SkRegion* clip, SkBlitter*);
+private:
+    friend class SkAAClip;
+    friend class SkRegion;
+
+    static void FillIRect(const SkIRect&, const SkRegion* clip, SkBlitter*);
+    static void FillXRect(const SkXRect&, const SkRegion* clip, SkBlitter*);
 #ifdef SK_SCALAR_IS_FIXED
-    static void AntiFillRect(const SkRect& rect, const SkRegion* clip,
+    static void FillRect(const SkRect& rect, const SkRegion* clip,
                          SkBlitter* blitter) {
+        SkScan::FillXRect(*(const SkXRect*)&rect, clip, blitter);
+    }
+    static void AntiFillRect(const SkRect& rect, const SkRegion* clip,
+                             SkBlitter* blitter) {
         SkScan::AntiFillXRect(*(const SkXRect*)&rect, clip, blitter);
     }
 #else
+    static void FillRect(const SkRect&, const SkRegion* clip, SkBlitter*);
     static void AntiFillRect(const SkRect&, const SkRegion* clip, SkBlitter*);
 #endif
-    
+    static void FillPath(const SkPath&, const SkRegion& clip, SkBlitter*);
     static void AntiFillPath(const SkPath&, const SkRegion& clip, SkBlitter*,
                              bool forceRLE = false);
-
-    static void AntiHairLine(const SkPoint&, const SkPoint&, const SkRegion*,
-                             SkBlitter*);
-    static void AntiHairRect(const SkRect&, const SkRegion* clip, SkBlitter*);
-    static void AntiHairPath(const SkPath&, const SkRegion* clip, SkBlitter*);
-
-    // draws with a miter-join
-    static void FrameRect(const SkRect&, const SkPoint& strokeSize,
-                          const SkRegion*, SkBlitter*);
+    static void FillTriangle(const SkPoint pts[], const SkRegion*, SkBlitter*);
+    
     static void AntiFrameRect(const SkRect&, const SkPoint& strokeSize,
                               const SkRegion*, SkBlitter*);
-
-    // rasterclip
-    static void FillIRect(const SkIRect&, const SkRasterClip&, SkBlitter*);
-    static void FillPath(const SkPath&, const SkRasterClip&, SkBlitter*);
-    static void AntiFillPath(const SkPath&, const SkRasterClip&, SkBlitter*);
+    static void HairLineRgn(const SkPoint&, const SkPoint&, const SkRegion*,
+                         SkBlitter*);
+    static void AntiHairLineRgn(const SkPoint&, const SkPoint&, const SkRegion*,
+                             SkBlitter*);
 };
 
 /** Assign an SkXRect from a SkIRect, by promoting the src rect's coordinates
index dd6af09..93a77cb 100644 (file)
@@ -16,6 +16,8 @@ static void drawClip(SkCanvas* canvas, const SkAAClip& clip) {
     SkBitmap bm;
     
     clip.copyToMask(&mask);
+    SkAutoMaskFreeImage amfi(mask.fImage);
+
     bm.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(),
                  mask.fBounds.height(), mask.fRowBytes);
     bm.setPixels(mask.fImage);
index 6d854e8..e8f5a14 100644 (file)
@@ -26,6 +26,8 @@ static void drawClip(SkCanvas* canvas, const SkAAClip& clip) {
     SkBitmap bm;
     
     clip.copyToMask(&mask);
+    SkAutoMaskFreeImage amfi(mask.fImage);
+
     bm.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(),
                  mask.fBounds.height(), mask.fRowBytes);
     bm.setPixels(mask.fImage);
@@ -40,6 +42,8 @@ static void paint_rgn(SkCanvas* canvas, const SkAAClip& clip,
     SkBitmap bm;
     
     clip.copyToMask(&mask);
+    SkAutoMaskFreeImage amfi(mask.fImage);
+
     bm.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(),
                  mask.fBounds.height(), mask.fRowBytes);
     bm.setPixels(mask.fImage);
index bed5459..740047e 100644 (file)
@@ -893,7 +893,7 @@ SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
 
     if (fUseClip) {
         canvas->drawColor(0xFFFF88FF);
-        canvas->clipPath(fClipPath);
+        canvas->clipPath(fClipPath, SkRegion::kIntersect_Op, true);
     }
 
     return canvas;
index 87ff0b6..570f0b9 100644 (file)
 #include "SkPaint.h"
 #include "SkRandom.h"
 
-#define W   270
+#define W   150
 #define H   200
 
-static void show_text(SkCanvas* canvas) {
+static void show_text(SkCanvas* canvas, bool doAA) {
     SkRandom rand;
     SkPaint paint;
-    paint.setAntiAlias(true);
+    paint.setAntiAlias(doAA);
+    paint.setLCDRenderText(true);
     paint.setTextSize(SkIntToScalar(20));
     
-    for (int i = 0; i < 300; ++i) {
+    for (int i = 0; i < 200; ++i) {
         paint.setColor((SK_A32_MASK << SK_A32_SHIFT) | rand.nextU());
         canvas->drawText("Hamburgefons", 12,
-                         rand.nextSScalar1() * W, rand.nextSScalar1() * H,
+                         rand.nextSScalar1() * W, rand.nextSScalar1() * H + 20,
                          paint);
     }
 }
 
-static void show_geo(SkCanvas* canvas) {
+static bool valid(int i) {
+    return i < 15 && i > 7;
+}
+
+static void show_fill(SkCanvas* canvas, bool doAA) {
     SkRandom rand;
     SkPaint paint;
-    paint.setAntiAlias(true);
+    paint.setAntiAlias(doAA);
     
-    for (int i = 0; i < 30; ++i) {
+    for (int i = 0; i < 50; ++i) {
         SkRect r;
         SkPath p;
-
+        
         r.setXYWH(rand.nextSScalar1() * W, rand.nextSScalar1() * H,
                   rand.nextUScalar1() * W, rand.nextUScalar1() * H);
-        paint.setStyle(SkPaint::kFill_Style);
         paint.setColor(rand.nextU());
         canvas->drawRect(r, paint);
         
         r.setXYWH(rand.nextSScalar1() * W, rand.nextSScalar1() * H,
                   rand.nextUScalar1() * W, rand.nextUScalar1() * H);
-        paint.setStyle(SkPaint::kStroke_Style);
+        paint.setColor(rand.nextU());
+        p.addOval(r);
+        canvas->drawPath(p, paint);
+    }
+}
+
+static SkScalar randRange(SkRandom& rand, SkScalar min, SkScalar max) {
+    SkASSERT(min <= max);
+    return min + SkScalarMul(rand.nextUScalar1(), max - min);
+}
+
+static void show_stroke(SkCanvas* canvas, bool doAA, SkScalar strokeWidth, int n) {
+    SkRandom rand;
+    SkPaint paint;
+    paint.setAntiAlias(doAA);
+    paint.setStyle(SkPaint::kStroke_Style);
+    paint.setStrokeWidth(strokeWidth);
+    
+    for (int i = 0; i < n; ++i) {
+        SkRect r;
+        SkPath p;
+        
+        r.setXYWH(rand.nextSScalar1() * W, rand.nextSScalar1() * H,
+                  rand.nextUScalar1() * W, rand.nextUScalar1() * H);
         paint.setColor(rand.nextU());
         canvas->drawRect(r, paint);
         
         r.setXYWH(rand.nextSScalar1() * W, rand.nextSScalar1() * H,
                   rand.nextUScalar1() * W, rand.nextUScalar1() * H);
-        paint.setStyle(SkPaint::kFill_Style);
         paint.setColor(rand.nextU());
         p.addOval(r);
         canvas->drawPath(p, paint);
+
+        const SkScalar minx = -SkIntToScalar(W)/4;
+        const SkScalar maxx = 5*SkIntToScalar(W)/4;
+        const SkScalar miny = -SkIntToScalar(H)/4;
+        const SkScalar maxy = 5*SkIntToScalar(H)/4;
+        paint.setColor(rand.nextU());
+        canvas->drawLine(randRange(rand, minx, maxx), randRange(rand, miny, maxy),
+                         randRange(rand, minx, maxx), randRange(rand, miny, maxy),
+                         paint);
     }
 }
 
-typedef void (*CanvasProc)(SkCanvas*);
+static void show_hair(SkCanvas* canvas, bool doAA) {
+    show_stroke(canvas, doAA, 0, 150);
+}
+
+static void show_thick(SkCanvas* canvas, bool doAA) {
+    show_stroke(canvas, doAA, SkIntToScalar(5), 50);
+}
+
+typedef void (*CanvasProc)(SkCanvas*, bool);
+
+#include "SkAAClip.h"
 
 class ClipView : public SampleView {
 public:
     ClipView() {
+        SkAAClip clip;
+        SkIRect r = { -2, -3, 842, 18 };
+        clip.setRect(r);
     }
 
     virtual ~ClipView() {
@@ -81,25 +129,27 @@ protected:
     }
 
     virtual void onDrawContent(SkCanvas* canvas) {
-        canvas->drawColor(SK_ColorLTGRAY);
+        canvas->drawColor(SK_ColorWHITE);
         canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
 
         static const CanvasProc gProc[] = {
-            show_text, show_geo
+            show_text, show_thick, show_hair, show_fill
         };
         
         SkRect r = { 0, 0, SkIntToScalar(W), SkIntToScalar(H) };
         SkPath clipPath;
         r.inset(SK_Scalar1 / 4, SK_Scalar1 / 4);
-        clipPath.addRoundRect(r, SkIntToScalar(16), SkIntToScalar(16));
+        clipPath.addRoundRect(r, SkIntToScalar(20), SkIntToScalar(20));
+
+//        clipPath.toggleInverseFillType();
 
         for (int aa = 0; aa <= 1; ++aa) {
             canvas->save();
             for (size_t i = 0; i < SK_ARRAY_COUNT(gProc); ++i) {
                 canvas->save();
-                canvas->clipPath(clipPath);
-                canvas->drawColor(SK_ColorWHITE);
-                gProc[i](canvas);
+                canvas->clipPath(clipPath, SkRegion::kIntersect_Op, true);
+//                canvas->drawColor(SK_ColorWHITE);
+                gProc[i](canvas, SkToBool(aa));
                 canvas->restore();
                 canvas->translate(W * SK_Scalar1 * 8 / 7, 0);
             }
index 51350be..02b2391 100644 (file)
@@ -354,7 +354,6 @@ protected:
     }
     
     virtual void onDrawContent(SkCanvas* canvas) {
-        SkIRect r = canvas->getTotalClip().getBounds();
         do_fuzz(canvas);
         this->inval(NULL);
     }
index cce37f5..11b1268 100644 (file)
 #include "SkImageDecoder.h"
 #include "SkBlurMaskFilter.h"
 
+#ifdef SK_BUILD_FOR_MAC
+#import <ApplicationServices/ApplicationServices.h>
+SkTypeface* SkCreateTypefaceFromCTFont(CTFontRef fontRef);
+#endif
+
 static void setNamedTypeface(SkPaint* paint, const char name[]) {
     SkTypeface* face = SkTypeface::CreateFromName(name, SkTypeface::kNormal);
     paint->setTypeface(face);
@@ -68,6 +73,26 @@ class XfermodesBlurView : public SampleView {
         r.set(ww/3, hh/3, ww*19/20, hh*19/20);
         r.offset(x, y);
         canvas->drawRect(r, p);
+
+#ifdef SK_BUILD_FOR_MAC
+        static const char* gNames[] = { "Arial", "Times", "Courier", "Lucida" };
+        for (int j = 0; j < SK_ARRAY_COUNT(gNames); ++j) {
+            CFStringRef name = CFStringCreateWithCString(NULL, gNames[j], kCFStringEncodingUTF8);
+            CTFontRef font = CTFontCreateWithName(name, 0, NULL);
+            SkTypeface* face = SkCreateTypefaceFromCTFont(font);
+            SkDebugf("%s ct:%p face:%p ats:%p\n", gNames[j], font, face, CTFontGetPlatformFont(font, NULL));
+            for (int i = 9; i <= 24; ++i) {
+                CTFontRef newFont = CTFontCreateCopyWithAttributes(font, i, NULL, NULL);
+                SkTypeface* newFace = SkCreateTypefaceFromCTFont(newFont);
+                SkDebugf("size:%d ct:%p face:%p ats:%p\n", i, newFont, newFace, CTFontGetPlatformFont(newFont, NULL));
+                newFace->unref();
+                CFRelease(newFont);
+            }
+            face->unref();
+            CFRelease(font);
+            CFRelease(name);
+        }
+#endif
     }
 
 public:
index 0ba43b1..485f16a 100644 (file)
@@ -8,11 +8,32 @@
 
 #include "SkAAClip.h"
 #include "SkBlitter.h"
+#include "SkColorPriv.h"
 #include "SkPath.h"
 #include "SkScan.h"
 #include "SkThread.h"
 #include "SkUtils.h"
 
+class AutoAAClipValidate {
+public:
+    AutoAAClipValidate(const SkAAClip& clip) : fClip(clip) {
+        fClip.validate();
+    }
+    ~AutoAAClipValidate() {
+        fClip.validate();
+    }
+private:
+    const SkAAClip& fClip;
+};
+
+#ifdef SK_DEBUG
+    #define AUTO_AACLIP_VALIDATE(clip)  AutoAAClipValidate acv(clip)
+#else
+    #define AUTO_AACLIP_VALIDATE(clip)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
 #define kMaxInt32   0x7FFFFFFF
 
 static inline bool x_in_rect(int x, const SkIRect& rect) {
@@ -58,6 +79,36 @@ struct SkAAClip::RunHead {
         head->fDataSize = dataSize;
         return head;
     }
+
+    static int ComputeRowSizeForWidth(int width) {
+        // 2 bytes per segment, where each segment can store up to 255 for count
+        int segments = 0;
+        while (width > 0) {
+            segments += 1;
+            int n = SkMin32(width, 255);
+            width -= n;
+        }
+        return segments * 2;    // each segment is row[0] + row[1] (n + alpha)
+    }
+
+    static RunHead* AllocRect(const SkIRect& bounds) {
+        SkASSERT(!bounds.isEmpty());
+        int width = bounds.width();
+        size_t rowSize = ComputeRowSizeForWidth(width);
+        RunHead* head = RunHead::Alloc(1, rowSize);
+        YOffset* yoff = head->yoffsets();
+        yoff->fY = bounds.height() - 1;
+        yoff->fOffset = 0;
+        uint8_t* row = head->data();
+        while (width > 0) {
+            int n = SkMin32(width, 255);
+            row[0] = n;
+            row[1] = 0xFF;
+            width -= n;
+            row += 2;
+        }
+        return head;
+    }
 };
 
 class SkAAClip::Iter {
@@ -117,6 +168,84 @@ void SkAAClip::Iter::next() {
     }
 }
 
+#ifdef SK_DEBUG
+static size_t compute_row_length(const uint8_t row[], int width) {
+    const uint8_t* origRow = row;
+    while (width > 0) {
+        int n = row[0];
+        SkASSERT(n <= width);
+        row += 2;
+        width -= n;
+    }
+    SkASSERT(0 == width);
+    return row - origRow;
+}
+
+void SkAAClip::validate() const {
+    if (NULL == fRunHead) {
+        SkASSERT(fBounds.isEmpty());
+        return;
+    }
+
+    const RunHead* head = fRunHead;
+    SkASSERT(head->fRefCnt > 0);
+    SkASSERT(head->fRowCount > 0);
+    SkASSERT(head->fDataSize > 0);
+
+    const YOffset* yoff = head->yoffsets();
+    const YOffset* ystop = yoff + head->fRowCount;
+    const uint8_t* row = head->data();
+    SkASSERT(0 == yoff->fOffset);
+    // y values must be monotonic
+    int y = -1;
+    int32_t offset = -1;
+    size_t computedOffset = 0;
+    while (yoff < ystop) {
+        SkASSERT(y < yoff->fY);
+        y = yoff->fY;
+        SkASSERT(offset < (int32_t)yoff->fOffset);
+        offset = yoff->fOffset;
+        SkASSERT(yoff->fOffset == computedOffset);
+        yoff += 1;
+        
+        size_t rowLength = compute_row_length(row, fBounds.width());
+        row += rowLength;
+        computedOffset += rowLength;
+    }
+    SkASSERT(head->fDataSize == computedOffset);
+    // check the last entry;
+    --yoff;
+    SkASSERT(yoff->fY == fBounds.height() - 1);
+
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
+// can't validate before we're done, since trimming is part of the process of
+// making us valid after the Builder. Since we build from top to bottom, its
+// possible our fBounds.fBottom is bigger than our last scanline of data, so
+// we trim fBounds.fBottom back up.
+//
+// TODO: look to trim our bounds on top, left, right.
+// TODO: check for duplicates in X and Y to further compress our data
+//
+bool SkAAClip::trimBounds() {
+    if (this->isEmpty()) {
+        return false;
+    }
+
+    const RunHead* head = fRunHead;
+    const YOffset* yoff = head->yoffsets();
+
+    SkASSERT(head->fRowCount > 0);
+    const YOffset& lastY = yoff[head->fRowCount - 1];
+    SkASSERT(lastY.fY + 1 <= fBounds.height());
+    fBounds.fBottom = fBounds.fTop + lastY.fY + 1;
+    SkASSERT(lastY.fY + 1 == fBounds.height());
+    return true;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 void SkAAClip::freeRuns() {
@@ -134,6 +263,7 @@ SkAAClip::SkAAClip() {
 }
 
 SkAAClip::SkAAClip(const SkAAClip& src) {
+    SkDEBUGCODE(fBounds.setEmpty();)    // need this for validate
     fRunHead = NULL;
     *this = src;
 }
@@ -143,6 +273,9 @@ SkAAClip::~SkAAClip() {
 }
 
 SkAAClip& SkAAClip::operator=(const SkAAClip& src) {
+    AUTO_AACLIP_VALIDATE(*this);
+    src.validate();
+
     if (this != &src) {
         this->freeRuns();
         fBounds = src.fBounds;
@@ -155,6 +288,9 @@ SkAAClip& SkAAClip::operator=(const SkAAClip& src) {
 }
 
 bool operator==(const SkAAClip& a, const SkAAClip& b) {
+    a.validate();
+    b.validate();
+
     if (&a == &b) {
         return true;
     }
@@ -181,6 +317,9 @@ bool operator==(const SkAAClip& a, const SkAAClip& b) {
 }
 
 void SkAAClip::swap(SkAAClip& other) {
+    AUTO_AACLIP_VALIDATE(*this);
+    other.validate();
+
     SkTSwap(fBounds, other.fBounds);
     SkTSwap(fRunHead, other.fRunHead);
 }
@@ -202,13 +341,21 @@ bool SkAAClip::setRect(const SkIRect& bounds) {
         return this->setEmpty();
     }
 
-    // TODO: special case this
+    AUTO_AACLIP_VALIDATE(*this);
 
+#if 0
     SkRect r;
     r.set(bounds);
     SkPath path;
     path.addRect(r);
     return this->setPath(path);
+#else
+    this->freeRuns();
+    fBounds = bounds;
+    fRunHead = RunHead::AllocRect(bounds);
+    SkASSERT(!this->isEmpty());
+    return true;
+#endif
 }
 
 bool SkAAClip::setRect(const SkRect& r, bool doAA) {
@@ -216,6 +363,10 @@ bool SkAAClip::setRect(const SkRect& r, bool doAA) {
         return this->setEmpty();
     }
 
+    AUTO_AACLIP_VALIDATE(*this);
+
+    // TODO: special case this
+
     SkPath path;
     path.addRect(r);
     return this->setPath(path, NULL, doAA);
@@ -255,7 +406,7 @@ const uint8_t* SkAAClip::findRow(int y, int* lastYForRow) const {
     }
 
     if (lastYForRow) {
-        *lastYForRow = yoff->fY;
+        *lastYForRow = fBounds.y() + yoff->fY;
     }
     return fRunHead->data() + yoff->fOffset;
 }
@@ -296,9 +447,22 @@ bool SkAAClip::quickContains(int left, int top, int right, int bottom) const {
         return false;
     }
     // now just need to check in X
-    int initialCount;
-    row = this->findX(row, left, &initialCount);
-    return initialCount >= (right - left) && 0xFF == row[1];
+    int count;
+    row = this->findX(row, left, &count);
+#if 0
+    return count >= (right - left) && 0xFF == row[1];
+#else
+    int rectWidth = right - left;
+    while (0xFF == row[1]) {
+        if (count >= rectWidth) {
+            return true;
+        }
+        rectWidth -= count;
+        row += 2;
+        count = row[0];
+    }
+    return false;
+#endif
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -370,7 +534,7 @@ public:
         SkASSERT(row->fWidth <= fBounds.width());
     }
 
-    RunHead* finish() {
+    bool finish(SkAAClip* target) {
         this->flushRow(false);
 
         const Row* row = fRows.begin();
@@ -382,6 +546,10 @@ public:
             row += 1;
         }
 
+        if (0 == dataSize) {
+            return target->setEmpty();
+        }
+
         RunHead* head = RunHead::Alloc(fRows.count(), dataSize);
         YOffset* yoffset = head->yoffsets();
         uint8_t* data = head->data();
@@ -400,7 +568,10 @@ public:
             row += 1;
         }
 
-        return head;
+        target->freeRuns();
+        target->fBounds = fBounds;
+        target->fRunHead = head;
+        return target->trimBounds();
     }
 
     void dump() {
@@ -419,26 +590,6 @@ public:
             }
             SkDebugf("\n");
         }
-
-#if 0
-        int prevY = -1;
-        for (y = 0; y < fRows.count(); ++y) {
-            const Row& row = fRows[y];
-            const SkTDArray<uint8_t>& data = *row.fData;
-            int count = data.count();
-            for (int n = prevY; n < row.fY; ++n) {
-                const uint8_t* ptr = data.begin();
-                for (int x = 0; x < count; x += 2) {
-                    for (int i = 0; i < ptr[0]; ++i) {
-                        SkDebugf("%02X", ptr[1]);
-                    }
-                    ptr += 2;
-                }
-                SkDebugf("\n");
-            }
-            prevY = row.fY;
-        }
-#endif
     }
 
     void validate() {
@@ -472,6 +623,7 @@ private:
             Row* curr = &fRows[count - 1];
             if (curr->fWidth < fWidth) {
                 AppendRun(*curr->fData, 0, fWidth - curr->fWidth);
+                curr->fWidth = fWidth;
             }
         }
         if (count > 1) {
@@ -528,8 +680,10 @@ public:
 
     virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE
         { unexpected(); }
-    virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE
-        { unexpected(); }
+
+    //  let the default impl call blitH
+//    virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE
+
     virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE
         { unexpected(); }
 
@@ -590,6 +744,8 @@ private:
 };
 
 bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) {
+    AUTO_AACLIP_VALIDATE(*this);
+
     if (clip && clip->isEmpty()) {
         return this->setEmpty();
     }
@@ -603,7 +759,9 @@ bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) {
         clip = &tmpClip;
     }
     
-    if (!path.isInverseFillType()) {
+    if (path.isInverseFillType()) {
+        ibounds = clip->getBounds();
+    } else {
         if (ibounds.isEmpty() || !ibounds.intersect(clip->getBounds())) {
             return this->setEmpty();
         }
@@ -618,12 +776,7 @@ bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) {
         SkScan::FillPath(path, *clip, &blitter);
     }
 
-    this->freeRuns();
-    fBounds = ibounds;
-    fRunHead = builder.finish();
-
-    //builder.dump();
-    return !this->isEmpty();
+    return builder.finish(this);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -895,6 +1048,8 @@ static void operateY(SkAAClip::Builder& builder, const SkAAClip& A,
 
 bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig,
                   SkRegion::Op op) {
+    AUTO_AACLIP_VALIDATE(*this);
+    
     if (SkRegion::kReplace_Op == op) {
         return this->set(clipBOrig);
     }
@@ -951,23 +1106,76 @@ bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig,
 
     Builder builder(bounds);
     operateY(builder, *clipA, *clipB, op);
-    // don't free us until now, since we might be clipA or clipB
-    this->freeRuns();
-    fBounds = bounds;
-    fRunHead = builder.finish();
-    
-    return !this->isEmpty();
+
+    return builder.finish(this);
 }
 
-bool SkAAClip::op(const SkIRect& r, SkRegion::Op op) {
+/*
+ *  It can be expensive to build a local aaclip before applying the op, so
+ *  we first see if we can restrict the bounds of new rect to our current
+ *  bounds, or note that the new rect subsumes our current clip.
+ */
+
+bool SkAAClip::op(const SkIRect& rOrig, SkRegion::Op op) {
+    SkIRect        rStorage;
+    const SkIRect* r = &rOrig;
+
+    switch (op) {
+        case SkRegion::kIntersect_Op:
+            if (!rStorage.intersect(rOrig, fBounds)) {
+                // no overlap, so we're empty
+                return this->setEmpty();
+            }
+            if (rStorage == fBounds) {
+                // we were wholly inside the rect, no change
+                return !this->isEmpty();
+            }
+            if (this->quickContains(rStorage)) {
+                // the intersection is wholly inside us, we're a rect
+                return this->setRect(rStorage);
+            }
+            r = &rStorage;   // use the intersected bounds
+            break;
+        case SkRegion::kDifference_Op:
+            break;
+        case SkRegion::kUnion_Op:
+            if (rOrig.contains(fBounds)) {
+                return this->setRect(rOrig);
+            }
+            break;
+        default:
+            break;
+    }
+
     SkAAClip clip;
-    clip.setRect(r);
+    clip.setRect(*r);
     return this->op(*this, clip, op);
 }
 
-bool SkAAClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
+bool SkAAClip::op(const SkRect& rOrig, SkRegion::Op op, bool doAA) {
+    SkRect        rStorage, boundsStorage;
+    const SkRect* r = &rOrig;
+    
+    boundsStorage.set(fBounds);
+    switch (op) {
+        case SkRegion::kIntersect_Op:
+        case SkRegion::kDifference_Op:
+            if (!rStorage.intersect(rOrig, boundsStorage)) {
+                return this->setEmpty();
+            }
+            r = &rStorage;   // use the intersected bounds
+            break;
+        case SkRegion::kUnion_Op:
+            if (rOrig.contains(boundsStorage)) {
+                return this->setRect(rOrig);
+            }
+            break;
+        default:
+            break;
+    }
+    
     SkAAClip clip;
-    clip.setRect(r, doAA);
+    clip.setRect(*r, doAA);
     return this->op(*this, clip, op);
 }
 
@@ -976,6 +1184,67 @@ bool SkAAClip::op(const SkAAClip& clip, SkRegion::Op op) {
 }
 
 ///////////////////////////////////////////////////////////////////////////////
+
+bool SkAAClip::translate(int dx, int dy, SkAAClip* dst) const {
+    if (NULL == dst) {
+        return !this->isEmpty();
+    }
+    
+    if (this->isEmpty()) {
+        return dst->setEmpty();
+    }
+    
+    if (this != dst) {
+        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) {
+    while (width > 0) {
+        int n = row[0];
+        SkASSERT(width >= n);
+        memset(mask, row[1], n);
+        mask += n;
+        row += 2;
+        width -= n;
+    }
+}
+
+void SkAAClip::copyToMask(SkMask* mask) const {
+    mask->fFormat = SkMask::kA8_Format;
+    if (this->isEmpty()) {
+        mask->fBounds.setEmpty();
+        mask->fImage = NULL;
+        mask->fRowBytes = 0;
+        return;
+    }
+    
+    mask->fBounds = fBounds;
+    mask->fRowBytes = fBounds.width();
+    size_t size = mask->computeImageSize();
+    mask->fImage = SkMask::AllocImage(size);
+    
+    Iter iter(*this);
+    uint8_t* dst = mask->fImage;
+    const int width = fBounds.width();
+    
+    int y = fBounds.fTop;
+    while (!iter.done()) {
+        do {
+            expand_row_to_mask(dst, iter.data(), width);
+            dst += mask->fRowBytes;
+        } while (++y < iter.bottom());
+        iter.next();
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 
 static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int width,
@@ -1006,18 +1275,19 @@ static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int
 }
 
 SkAAClipBlitter::~SkAAClipBlitter() {
-    sk_free(fRuns);
+    sk_free(fScanlineScratch);
 }
 
 void SkAAClipBlitter::ensureRunsAndAA() {
-    if (NULL == fRuns) {
+    if (NULL == fScanlineScratch) {
         // add 1 so we can store the terminating run count of 0
         int count = fAAClipBounds.width() + 1;
-        fRuns = (int16_t*)sk_malloc_throw(count * sizeof(int16_t) +
-                                          count * sizeof(SkAlpha));
+        // we use this either for fRuns + fAA, or a scaline of a mask
+        // which may be as deep as 32bits
+        fScanlineScratch = sk_malloc_throw(count * sizeof(SkPMColor));
+        fRuns = (int16_t*)fScanlineScratch;
         fAA = (SkAlpha*)(fRuns + count);
     }
-    SkDEBUGCODE(sk_memset16((uint16_t*)fRuns, 0xFFFF, fAAClipBounds.width() + 1);)
 }
 
 void SkAAClipBlitter::blitH(int x, int y, int width) {
@@ -1055,10 +1325,12 @@ static void merge(const uint8_t* SK_RESTRICT row, int rowN,
                   int width) {
     SkDEBUGCODE(int accumulated = 0;)
     int srcN = srcRuns[0];
+    // do we need this check?
+    if (0 == srcN) {
+        return;
+    }
+
     for (;;) {
-        if (0 == srcN) {
-            break;
-        }
         SkASSERT(rowN > 0);
         SkASSERT(srcN > 0);
 
@@ -1074,6 +1346,9 @@ static void merge(const uint8_t* SK_RESTRICT row, int rowN,
             srcRuns += srcN;
             srcAA += srcN;
             srcN = srcRuns[0];  // reload
+            if (0 == srcN) {
+                break;
+            }
         }
         if (0 == (rowN -= minN)) {
             row += 2;
@@ -1105,18 +1380,27 @@ void SkAAClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
         return;
     }
 
-    int stopY = y + height;
-    do {
+    for (;;) {
         int lastY;
         const uint8_t* row = fAAClip->findRow(y, &lastY);
+        int dy = lastY - y + 1;
+        if (dy > height) {
+            dy = height;
+        }
+        height -= dy;
+
         int initialCount;
         row = fAAClip->findX(row, x, &initialCount);
         SkAlpha newAlpha = SkMulDiv255Round(alpha, row[1]);
         if (newAlpha) {
-            fBlitter->blitV(x, y, lastY - y + 1, newAlpha);
+            fBlitter->blitV(x, y, dy, newAlpha);
+        }
+        SkASSERT(height >= 0);
+        if (height <= 0) {
+            break;
         }
         y = lastY + 1;
-    } while (y < stopY);
+    }
 }
 
 void SkAAClipBlitter::blitRect(int x, int y, int width, int height) {
@@ -1131,72 +1415,208 @@ void SkAAClipBlitter::blitRect(int x, int y, int width, int height) {
     }
 }
 
-void SkAAClipBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
-    fBlitter->blitMask(mask, clip);
+typedef void (*MergeAAProc)(const void* src, int width, const uint8_t* row,
+                            int initialRowCount, void* dst);
+
+static void small_memcpy(void* dst, const void* src, size_t n) {
+    memcpy(dst, src, n);
 }
 
-const SkBitmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) {
-    return NULL;
+static void small_bzero(void* dst, size_t n) {
+    sk_bzero(dst, n);
 }
 
-///////////////////////////////////////////////////////////////////////////////
+static inline uint8_t mergeOne(uint8_t value, unsigned alpha) {
+    return SkMulDiv255Round(value, alpha);
+}
+static inline uint16_t mergeOne(uint16_t value, unsigned alpha) {
+    unsigned r = SkGetPackedR16(value);
+    unsigned g = SkGetPackedG16(value);
+    unsigned b = SkGetPackedB16(value);
+    return SkPackRGB16(SkMulDiv255Round(r, alpha),
+                       SkMulDiv255Round(r, alpha),
+                       SkMulDiv255Round(r, alpha));
+}
+static inline SkPMColor mergeOne(SkPMColor value, unsigned alpha) {
+    unsigned a = SkGetPackedA32(value);
+    unsigned r = SkGetPackedR32(value);
+    unsigned g = SkGetPackedG32(value);
+    unsigned b = SkGetPackedB32(value);
+    return SkPackARGB32(SkMulDiv255Round(a, alpha),
+                        SkMulDiv255Round(r, alpha),
+                        SkMulDiv255Round(g, alpha),
+                        SkMulDiv255Round(b, alpha));
+}
 
-bool SkAAClip::translate(int dx, int dy, SkAAClip* dst) const {
-    if (NULL == dst) {
-        return !this->isEmpty();
+template <typename T> void mergeT(const T* SK_RESTRICT src, int srcN,
+                                 const uint8_t* SK_RESTRICT row, int rowN,
+                                 T* SK_RESTRICT dst) {
+    SkDEBUGCODE(int accumulated = 0;)
+    for (;;) {
+        SkASSERT(rowN > 0);
+        SkASSERT(srcN > 0);
+        
+        int n = SkMin32(rowN, srcN);
+        unsigned rowA = row[1];
+        if (0xFF == rowA) {
+            small_memcpy(dst, src, n * sizeof(T));
+        } else if (0 == rowA) {
+            small_bzero(dst, n * sizeof(T));
+        } else {
+            for (int i = 0; i < n; ++i) {
+                dst[i] = mergeOne(src[i], rowA);
+            }
+        }
+        
+        if (0 == (srcN -= n)) {
+            break;
+        }
+        
+        src += n;
+        dst += n;
+        
+        SkASSERT(rowN == n);
+        row += 2;
+        rowN = row[0];
     }
+}
 
-    if (this->isEmpty()) {
-        return dst->setEmpty();
+static MergeAAProc find_merge_aa_proc(SkMask::Format format) {
+    switch (format) {
+        case SkMask::kBW_Format:
+            SkASSERT(!"unsupported");
+            return NULL;
+        case SkMask::kA8_Format:
+        case SkMask::k3D_Format: {
+            void (*proc8)(const uint8_t*, int, const uint8_t*, int, uint8_t*) = mergeT;
+            return (MergeAAProc)proc8;
+        }
+        case SkMask::kLCD16_Format: {
+            void (*proc16)(const uint16_t*, int, const uint8_t*, int, uint16_t*) = mergeT;
+            return (MergeAAProc)proc16;
+        }
+        case SkMask::kLCD32_Format: {
+            void (*proc32)(const SkPMColor*, int, const uint8_t*, int, SkPMColor*) = mergeT;
+            return (MergeAAProc)proc32;
+        }
+        default:
+            SkASSERT(!"unsupported");
+            return NULL;
     }
+}
 
-    if (this != dst) {
-        sk_atomic_inc(&fRunHead->fRefCnt);
-        dst->fRunHead = fRunHead;
-        dst->fBounds = fBounds;
-    }
-    dst->fBounds.offset(dx, dy);
-    return true;
+static U8CPU bit2byte(int bitInAByte) {
+    SkASSERT(bitInAByte <= 0xFF);
+    // negation turns any non-zero into 0xFFFFFF??, so we just shift down
+    // some value >= 8 to get a full FF value
+    return -bitInAByte >> 8;
 }
 
-static void expand_row_to_mask(uint8_t* SK_RESTRICT mask,
-                               const uint8_t* SK_RESTRICT row,
-                               int width) {
-    while (width > 0) {
-        int n = row[0];
-        SkASSERT(width >= n);
-        memset(mask, row[1], n);
-        mask += n;
-        row += 2;
-        width -= n;
+static void upscaleBW2A8(SkMask* dstMask, const SkMask& srcMask) {
+    SkASSERT(SkMask::kBW_Format == srcMask.fFormat);
+    SkASSERT(SkMask::kA8_Format == dstMask->fFormat);
+
+    const int width = srcMask.fBounds.width();
+    const int height = srcMask.fBounds.height();
+
+    const uint8_t* SK_RESTRICT src = (const uint8_t*)srcMask.fImage;
+    const size_t srcRB = srcMask.fRowBytes;
+    uint8_t* SK_RESTRICT dst = (uint8_t*)dstMask->fImage;
+    const size_t dstRB = dstMask->fRowBytes;
+
+    const int wholeBytes = width >> 3;
+    const int leftOverBits = width & 7;
+
+    for (int y = 0; y < height; ++y) {
+        uint8_t* SK_RESTRICT d = dst;
+        for (int i = 0; i < wholeBytes; ++i) {
+            int srcByte = src[i];
+            d[0] = bit2byte(srcByte & (1 << 7));
+            d[1] = bit2byte(srcByte & (1 << 6));
+            d[2] = bit2byte(srcByte & (1 << 5));
+            d[3] = bit2byte(srcByte & (1 << 4));
+            d[4] = bit2byte(srcByte & (1 << 3));
+            d[5] = bit2byte(srcByte & (1 << 2));
+            d[6] = bit2byte(srcByte & (1 << 1));
+            d[7] = bit2byte(srcByte & (1 << 0));
+            d += 8;
+        }
+        if (leftOverBits) {
+            int srcByte = src[wholeBytes];
+            for (int x = 0; x < leftOverBits; ++x) {
+                *d++ = bit2byte(srcByte & 0x80);
+                srcByte <<= 1;
+            }
+        }
+        src += srcRB;
+        dst += dstRB;
     }
 }
 
-void SkAAClip::copyToMask(SkMask* mask) const {
-    mask->fFormat = SkMask::kA8_Format;
-    if (this->isEmpty()) {
-        mask->fBounds.setEmpty();
-        mask->fImage = NULL;
-        mask->fRowBytes = 0;
+void SkAAClipBlitter::blitMask(const SkMask& origMask, const SkIRect& clip) {
+    SkASSERT(fAAClip->getBounds().contains(clip));
+
+    if (fAAClip->quickContains(clip)) {
+        fBlitter->blitMask(origMask, clip);
         return;
     }
 
-    mask->fBounds = fBounds;
-    mask->fRowBytes = fBounds.width();
-    size_t size = mask->computeImageSize();
-    mask->fImage = SkMask::AllocImage(size);
+    const SkMask* mask = &origMask;
 
-    Iter iter(*this);
-    uint8_t* dst = mask->fImage;
-    const int width = fBounds.width();
+    // if we're BW, we need to upscale to A8 (ugh)
+    SkMask  grayMask;
+    grayMask.fImage = NULL;
+    if (SkMask::kBW_Format == origMask.fFormat) {
+        grayMask.fFormat = SkMask::kA8_Format;
+        grayMask.fBounds = origMask.fBounds;
+        grayMask.fRowBytes = origMask.fBounds.width();
+        size_t size = grayMask.computeImageSize();
+        grayMask.fImage = (uint8_t*)fGrayMaskScratch.reset(size,
+                                               SkAutoMalloc::kReuse_OnShrink);
 
-    int y = fBounds.fTop;
-    while (!iter.done()) {
-        do {
-            expand_row_to_mask(dst, iter.data(), width);
-            dst += mask->fRowBytes;
-        } while (++y < iter.bottom());
-        iter.next();
+        upscaleBW2A8(&grayMask, origMask);
+        mask = &grayMask;
     }
+
+    this->ensureRunsAndAA();
+
+    // HACK -- we are devolving 3D into A8, need to copy the rest of the 3D
+    // data into a temp block to support it better (ugh)
+
+    const void* src = mask->getAddr(clip.fLeft, clip.fTop);
+    const size_t srcRB = mask->fRowBytes;
+    const int width = clip.width();
+    MergeAAProc mergeProc = find_merge_aa_proc(mask->fFormat);
+
+    SkMask rowMask;
+    rowMask.fFormat = SkMask::k3D_Format == mask->fFormat ? SkMask::kA8_Format : mask->fFormat;
+    rowMask.fBounds.fLeft = clip.fLeft;
+    rowMask.fBounds.fRight = clip.fRight;
+    rowMask.fRowBytes = mask->fRowBytes; // doesn't matter, since our height==1
+    rowMask.fImage = (uint8_t*)fScanlineScratch;
+
+    int y = clip.fTop;
+    const int stopY = y + clip.height();
+
+    do {
+        int localStopY;
+        const uint8_t* row = fAAClip->findRow(y, &localStopY);
+        // findRow returns last Y, not stop, so we add 1
+        localStopY = SkMin32(localStopY + 1, stopY);
+
+        int initialCount;
+        row = fAAClip->findX(row, clip.fLeft, &initialCount);
+        do {
+            mergeProc(src, width, row, initialCount, rowMask.fImage);
+            rowMask.fBounds.fTop = y;
+            rowMask.fBounds.fBottom = y + 1;
+            fBlitter->blitMask(rowMask, rowMask.fBounds);
+            src = (const void*)((const char*)src + srcRB);
+        } while (++y < localStopY);
+    } while (y < stopY);
+}
+
+const SkBitmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) {
+    return NULL;
 }
 
index d2f5bec..5cc2a9e 100644 (file)
@@ -57,6 +57,10 @@ public:
     // called internally
     
     bool quickContains(int left, int top, int right, int bottom) const;
+    bool quickContains(const SkIRect& r) const {
+        return this->quickContains(r.fLeft, r.fTop, r.fRight, r.fBottom);
+    }
+
     const uint8_t* findRow(int y, int* lastYForRow) const;
     const uint8_t* findX(const uint8_t data[], int x, int* initialCount) const;
 
@@ -65,11 +69,18 @@ public:
     struct YOffset;
     class Builder;
 
+#ifdef SK_DEBUG
+    void validate() const;
+#else
+    void validate() const {}
+#endif
+
 private:
     SkIRect  fBounds;
     RunHead* fRunHead;
 
     void freeRuns();
+    bool trimBounds();
 
     friend class Builder;
     class BuilderBlitter;
@@ -80,7 +91,7 @@ private:
 
 class SkAAClipBlitter : public SkBlitter {
 public:
-    SkAAClipBlitter() : fRuns(NULL) {}
+    SkAAClipBlitter() : fScanlineScratch(NULL) {}
     virtual ~SkAAClipBlitter();
 
     void init(SkBlitter* blitter, const SkAAClip* aaclip) {
@@ -103,9 +114,15 @@ private:
     const SkAAClip* fAAClip;
     SkIRect         fAAClipBounds;
 
-    // lazily allocated
+    // point into fScanlineScratch
     int16_t*        fRuns;
-    SkAlpha*        fAA;    // points into fRuns allocation
+    SkAlpha*        fAA;
+
+    enum {
+        kSize = 32 * 32
+    };
+    SkAutoSMalloc<kSize> fGrayMaskScratch;  // used for blitMask
+    void* fScanlineScratch;  // enough for a mask at 32bit, or runs+aa
 
     void ensureRunsAndAA();
 };
index a77d5d9..293b10f 100644 (file)
@@ -66,7 +66,7 @@ static SkCanvas::EdgeType paint2EdgeType(const SkPaint* paint) {
 struct DeviceCM {
     DeviceCM*           fNext;
     SkDevice*           fDevice;
-    SkRegion            fClip;
+    SkRasterClip        fClip;
     const SkMatrix*     fMatrix;
     SkPaint*            fPaint; // may be null (in the future)
     // optional, related to canvas' external matrix
@@ -91,8 +91,8 @@ struct DeviceCM {
         SkDELETE(fPaint);
     }
 
-    void updateMC(const SkMatrix& totalMatrix, const SkRegion& totalClip,
-                  const SkClipStack& clipStack, SkRegion* updateClip) {
+    void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
+                  const SkClipStack& clipStack, SkRasterClip* updateClip) {
         int x = fDevice->getOrigin().x();
         int y = fDevice->getOrigin().y();
         int width = fDevice->width();
@@ -110,16 +110,16 @@ struct DeviceCM {
             totalClip.translate(-x, -y, &fClip);
         }
 
-        fClip.op(0, 0, width, height, SkRegion::kIntersect_Op);
+        fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
 
         // intersect clip, but don't translate it (yet)
 
         if (updateClip) {
-            updateClip->op(x, y, x + width, y + height,
+            updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
                            SkRegion::kDifference_Op);
         }
 
-        fDevice->setMatrixClip(*fMatrix, fClip, clipStack);
+        fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
 
 #ifdef SK_DEBUG
         if (!fClip.isEmpty()) {
@@ -235,7 +235,8 @@ public:
             const DeviceCM* rec = fCurrLayer;
 
             fMatrix = rec->fMatrix;
-            fClip   = &rec->fClip;
+            fClip   = &((SkRasterClip*)&rec->fClip)->forceGetBW();
+            fRC     = &rec->fClip;
             fDevice = rec->fDevice;
             fBitmap = &fDevice->accessBitmap(true);
             fPaint  = rec->fPaint;
@@ -576,7 +577,7 @@ void SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
 void SkCanvas::updateDeviceCMCache() {
     if (fDeviceCMDirty) {
         const SkMatrix& totalMatrix = this->getTotalMatrix();
-        const SkRegion& totalClip = this->getTotalClip();
+        const SkRasterClip& totalClip = *fMCRec->fRasterClip;
         DeviceCM*       layer = fMCRec->fTopLayer;
 
         if (NULL == layer->fNext) {   // only one layer
@@ -586,8 +587,7 @@ void SkCanvas::updateDeviceCMCache() {
                                             fExternalInverse);
             }
         } else {
-            SkRegion clip;
-            clip = totalClip;  // make a copy
+            SkRasterClip clip(totalClip);
             do {
                 layer->updateMC(totalMatrix, clip, fClipStack, &clip);
                 if (fUseExternalMatrix) {
index ed21f65..83ccc9e 100644 (file)
@@ -16,6 +16,7 @@
 #include "SkMaskFilter.h"
 #include "SkPaint.h"
 #include "SkPathEffect.h"
+#include "SkRasterClip.h"
 #include "SkRasterizer.h"
 #include "SkScan.h"
 #include "SkShader.h"
@@ -250,7 +251,7 @@ static void CallBitmapXferProc(const SkBitmap& bitmap, const SkIRect& rect,
 void SkDraw::drawPaint(const SkPaint& paint) const {
     SkDEBUGCODE(this->validate();)
 
-    if (fClip->isEmpty()) {
+    if (fRC->isEmpty()) {
         return;
     }
 
@@ -260,29 +261,32 @@ void SkDraw::drawPaint(const SkPaint& paint) const {
         return;
     }
 
-    /*  If we don't have a shader (i.e. we're just a solid color) we may
-        be faster to operate directly on the device bitmap, rather than invoking
-        a blitter. Esp. true for xfermodes, which require a colorshader to be
-        present, which is just redundant work. Since we're drawing everywhere
-        in the clip, we don't have to worry about antialiasing.
-    */
-    uint32_t procData = 0;  // to avoid the warning
-    BitmapXferProc proc = ChooseBitmapXferProc(*fBitmap, paint, &procData);
-    if (proc) {
-        if (D_Dst_BitmapXferProc == proc) { // nothing to do
-            return;
-        }
+    if (fRC->isBW()) {
+        /*  If we don't have a shader (i.e. we're just a solid color) we may
+            be faster to operate directly on the device bitmap, rather than invoking
+            a blitter. Esp. true for xfermodes, which require a colorshader to be
+            present, which is just redundant work. Since we're drawing everywhere
+            in the clip, we don't have to worry about antialiasing.
+        */
+        uint32_t procData = 0;  // to avoid the warning
+        BitmapXferProc proc = ChooseBitmapXferProc(*fBitmap, paint, &procData);
+        if (proc) {
+            if (D_Dst_BitmapXferProc == proc) { // nothing to do
+                return;
+            }
 
-        SkRegion::Iterator iter(*fClip);
-        while (!iter.done()) {
-            CallBitmapXferProc(*fBitmap, iter.rect(), proc, procData);
-            iter.next();
+            SkRegion::Iterator iter(fRC->bwRgn());
+            while (!iter.done()) {
+                CallBitmapXferProc(*fBitmap, iter.rect(), proc, procData);
+                iter.next();
+            }
+            return;
         }
-    } else {
-        // normal case: use a blitter
-        SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
-        SkScan::FillIRect(devRect, fClip, blitter.get());
     }
+
+    // normal case: use a blitter
+    SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
+    SkScan::FillIRect(devRect, *fRC, blitter.get());
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -291,6 +295,7 @@ struct PtProcRec {
     SkCanvas::PointMode fMode;
     const SkPaint*  fPaint;
     const SkRegion* fClip;
+    const SkRasterClip* fRC;
 
     // computed values
     SkFixed fRadius;
@@ -299,8 +304,11 @@ struct PtProcRec {
                          SkBlitter*);
 
     bool init(SkCanvas::PointMode, const SkPaint&, const SkMatrix* matrix,
-              const SkRegion* clip);
-    Proc chooseProc(SkBlitter* blitter);
+              const SkRasterClip*);
+    Proc chooseProc(SkBlitter** blitter);
+
+private:
+    SkAAClipBlitterWrapper fWrapper;
 };
 
 static void bw_pt_rect_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
@@ -320,8 +328,8 @@ static void bw_pt_rect_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
 static void bw_pt_rect_16_hair_proc(const PtProcRec& rec,
                                     const SkPoint devPts[], int count,
                                     SkBlitter* blitter) {
-    SkASSERT(rec.fClip->isRect());
-    const SkIRect& r = rec.fClip->getBounds();
+    SkASSERT(rec.fRC->isRect());
+    const SkIRect& r = rec.fRC->getBounds();
     uint32_t value;
     const SkBitmap* bitmap = blitter->justAnOpaqueColor(&value);
     SkASSERT(bitmap);
@@ -353,14 +361,14 @@ static void bw_pt_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
 static void bw_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
                               int count, SkBlitter* blitter) {
     for (int i = 0; i < count; i += 2) {
-        SkScan::HairLine(devPts[i], devPts[i+1], rec.fClip, blitter);
+        SkScan::HairLine(devPts[i], devPts[i+1], *rec.fRC, blitter);
     }
 }
 
 static void bw_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
                               int count, SkBlitter* blitter) {
     for (int i = 0; i < count - 1; i++) {
-        SkScan::HairLine(devPts[i], devPts[i+1], rec.fClip, blitter);
+        SkScan::HairLine(devPts[i], devPts[i+1], *rec.fRC, blitter);
     }
 }
 
@@ -369,14 +377,14 @@ static void bw_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
 static void aa_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
                               int count, SkBlitter* blitter) {
     for (int i = 0; i < count; i += 2) {
-        SkScan::AntiHairLine(devPts[i], devPts[i+1], rec.fClip, blitter);
+        SkScan::AntiHairLine(devPts[i], devPts[i+1], *rec.fRC, blitter);
     }
 }
 
 static void aa_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
                               int count, SkBlitter* blitter) {
     for (int i = 0; i < count - 1; i++) {
-        SkScan::AntiHairLine(devPts[i], devPts[i+1], rec.fClip, blitter);
+        SkScan::AntiHairLine(devPts[i], devPts[i+1], *rec.fRC, blitter);
     }
 }
 
@@ -395,7 +403,7 @@ static void bw_square_proc(const PtProcRec& rec, const SkPoint devPts[],
         r.fRight = x + radius;
         r.fBottom = y + radius;
 
-        SkScan::FillXRect(r, rec.fClip, blitter);
+        SkScan::FillXRect(r, *rec.fRC, blitter);
     }
 }
 
@@ -412,13 +420,13 @@ static void aa_square_proc(const PtProcRec& rec, const SkPoint devPts[],
         r.fRight = x + radius;
         r.fBottom = y + radius;
 
-        SkScan::AntiFillXRect(r, rec.fClip, blitter);
+        SkScan::AntiFillXRect(r, *rec.fRC, blitter);
     }
 }
 
 // If this guy returns true, then chooseProc() must return a valid proc
 bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint,
-                     const SkMatrix* matrix, const SkRegion* clip) {
+                     const SkMatrix* matrix, const SkRasterClip* rc) {
     if (paint.getPathEffect()) {
         return false;
     }
@@ -426,7 +434,8 @@ bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint,
     if (0 == width) {
         fMode = mode;
         fPaint = &paint;
-        fClip = clip;
+        fClip = NULL;
+        fRC = rc;
         fRadius = SK_Fixed1 >> 1;
         return true;
     }
@@ -441,7 +450,8 @@ bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint,
 
             fMode = mode;
             fPaint = &paint;
-            fClip = clip;
+            fClip = NULL;
+            fRC = rc;
             fRadius = SkScalarToFixed(SkScalarMul(width, sx)) >> 1;
             return true;
         }
@@ -449,9 +459,19 @@ bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint,
     return false;
 }
 
-PtProcRec::Proc PtProcRec::chooseProc(SkBlitter* blitter) {
+PtProcRec::Proc PtProcRec::chooseProc(SkBlitter** blitterPtr) {
     Proc proc = NULL;
 
+    SkBlitter* blitter = *blitterPtr;
+    if (fRC->isBW()) {
+        fClip = &fRC->bwRgn();
+    } else {
+        fWrapper.init(*fRC, blitter);
+        fClip = &fWrapper.getRgn();
+        blitter = fWrapper.getBlitter();
+        *blitterPtr = blitter;
+    }
+
     // for our arrays
     SkASSERT(0 == SkCanvas::kPoints_PointMode);
     SkASSERT(1 == SkCanvas::kLines_PointMode);
@@ -527,7 +547,7 @@ void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count,
     SkDEBUGCODE(this->validate();)
 
      // nothing to draw
-    if (fClip->isEmpty()) {
+    if (fRC->isEmpty()) {
         return;
     }
 
@@ -545,13 +565,13 @@ void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count,
     }
     
     PtProcRec rec;
-    if (!forceUseDevice && rec.init(mode, paint, fMatrix, fClip)) {
+    if (!forceUseDevice && rec.init(mode, paint, fMatrix, fRC)) {
         SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
 
         SkPoint             devPts[MAX_DEV_PTS];
         const SkMatrix*     matrix = fMatrix;
         SkBlitter*          bltr = blitter.get();
-        PtProcRec::Proc     proc = rec.chooseProc(bltr);
+        PtProcRec::Proc     proc = rec.chooseProc(&bltr);
         // we have to back up subsequent passes if we're in polygon mode
         const size_t backup = (SkCanvas::kPolygon_PointMode == mode);
 
@@ -696,7 +716,7 @@ void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const {
     SkDEBUGCODE(this->validate();)
 
     // nothing to draw
-    if (fClip->isEmpty()) {
+    if (fRC->isEmpty()) {
         return;
     }
 
@@ -708,7 +728,7 @@ void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const {
         rtype = kPath_RectType;
     }
 #endif
-        
+
     if (kPath_RectType == rtype) {
         SkPath  tmp;
         tmp.addRect(rect);
@@ -739,13 +759,13 @@ void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const {
             // extra space for hairlines
             ir.inset(-1, -1);
         }
-        if (fClip->quickReject(ir))
+        if (fRC->quickReject(ir))
             return;
     }
 
     SkAutoBlitterChoose blitterStorage(*fBitmap, matrix, paint);
+    const SkRasterClip& clip = *fRC;
     SkBlitter*          blitter = blitterStorage.get();
-    const SkRegion*     clip = fClip;
 
     // we want to "fill" if we are kFill or kStrokeAndFill, since in the latter
     // case we are also hairline (if we've gotten to here), which devolves to
@@ -797,9 +817,20 @@ void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const {
         return;
     }
 
-    SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
+    SkAutoBlitterChoose blitterChooser(*fBitmap, *fMatrix, paint);
+    SkBlitter* blitter = blitterChooser.get();
+
+    SkAAClipBlitterWrapper wrapper;
+    const SkRegion* clipRgn;
 
-    blitter->blitMaskRegion(*mask, *fClip);
+    if (fRC->isBW()) {
+        clipRgn = &fRC->bwRgn();
+    } else {
+        wrapper.init(*fRC, blitter);
+        clipRgn = &wrapper.getRgn();
+        blitter = wrapper.getBlitter();
+    }
+    blitter->blitMaskRegion(*mask, *clipRgn);
 }
 
 static SkScalar fast_len(const SkVector& vec) {
@@ -879,7 +910,7 @@ void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
     SkDEBUGCODE(this->validate();)
 
     // nothing to draw
-    if (fClip->isEmpty()) {
+    if (fRC->isEmpty()) {
         return;
     }
 
@@ -932,7 +963,7 @@ void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
     if (paint->getRasterizer()) {
         SkMask  mask;
         if (paint->getRasterizer()->rasterize(*pathPtr, *matrix,
-                            &fClip->getBounds(), paint->getMaskFilter(), &mask,
+                            &fRC->getBounds(), paint->getMaskFilter(), &mask,
                             SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
             this->drawDevMask(mask, *paint);
             SkMask::FreeImage(mask.fImage);
@@ -950,7 +981,7 @@ void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
 
     // how does filterPath() know to fill or hairline the path??? <mrr>
     if (paint->getMaskFilter() &&
-            paint->getMaskFilter()->filterPath(*devPathPtr, *fMatrix, *fClip,
+            paint->getMaskFilter()->filterPath(*devPathPtr, *fMatrix, *fRC,
                                                fBounder, blitter.get())) {
         return; // filterPath() called the blitter, so we're done
     }
@@ -959,19 +990,21 @@ void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
         return;
     }
 
+    void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*);
     if (doFill) {
         if (paint->isAntiAlias()) {
-            SkScan::AntiFillPath(*devPathPtr, *fClip, blitter.get());
+            proc = SkScan::AntiFillPath;
         } else {
-            SkScan::FillPath(*devPathPtr, *fClip, blitter.get());
+            proc = SkScan::FillPath;
         }
     } else {    // hairline
         if (paint->isAntiAlias()) {
-            SkScan::AntiHairPath(*devPathPtr, fClip, blitter.get());
+            proc = SkScan::AntiHairPath;
         } else {
-            SkScan::HairPath(*devPathPtr, fClip, blitter.get());
+            proc = SkScan::HairPath;
         }
     }
+    proc(*devPathPtr, *fRC, blitter.get());
 }
 
 /** For the purposes of drawing bitmaps, if a matrix is "almost" translate
@@ -1071,7 +1104,7 @@ void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap,
     }
 }
 
-static bool clipped_out(const SkMatrix& m, const SkRegion& c,
+static bool clipped_out(const SkMatrix& m, const SkRasterClip& c,
                         const SkRect& srcR) {
     SkRect  dstR;
     SkIRect devIR;
@@ -1081,19 +1114,25 @@ static bool clipped_out(const SkMatrix& m, const SkRegion& c,
     return c.quickReject(devIR);
 }
 
-static bool clipped_out(const SkMatrix& matrix, const SkRegion& clip,
+static bool clipped_out(const SkMatrix& matrix, const SkRasterClip& clip,
                         int width, int height) {
     SkRect  r;
     r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height));
     return clipped_out(matrix, clip, r);
 }
 
+static bool clipHandlesSprite(const SkRasterClip& clip, int x, int y,
+                              const SkBitmap& bitmap) {
+    return clip.isBW() ||
+           clip.quickContains(x, y, x + bitmap.width(), y + bitmap.height());
+}
+
 void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
                         const SkPaint& origPaint) const {
     SkDEBUGCODE(this->validate();)
 
     // nothing to draw
-    if (fClip->isEmpty() ||
+    if (fRC->isEmpty() ||
             bitmap.width() == 0 || bitmap.height() == 0 ||
             bitmap.getConfig() == SkBitmap::kNo_Config) {
         return;
@@ -1114,7 +1153,7 @@ void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
         return;
     }
 
-    if (clipped_out(matrix, *fClip, bitmap.width(), bitmap.height())) {
+    if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) {
         return;
     }
 
@@ -1137,31 +1176,22 @@ void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
 
     if (bitmap.getConfig() != SkBitmap::kA8_Config &&
             just_translate(matrix, bitmap)) {
-        int         ix = SkScalarRound(matrix.getTranslateX());
-        int         iy = SkScalarRound(matrix.getTranslateY());
-        uint32_t    storage[kBlitterStorageLongCount];
-        SkBlitter*  blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap,
-                                            ix, iy, storage, sizeof(storage));
-        if (blitter) {
-            SkAutoTPlacementDelete<SkBlitter>   ad(blitter, storage);
-
-            SkIRect    ir;
-            ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height());
-
-            SkRegion::Cliperator iter(*fClip, ir);
-            const SkIRect&       cr = iter.rect();
-
-            for (; !iter.done(); iter.next()) {
-                SkASSERT(!cr.isEmpty());
-                blitter->blitRect(cr.fLeft, cr.fTop, cr.width(), cr.height());
+        int ix = SkScalarRound(matrix.getTranslateX());
+        int iy = SkScalarRound(matrix.getTranslateY());
+        if (clipHandlesSprite(*fRC, ix, iy, bitmap)) {
+            uint32_t    storage[kBlitterStorageLongCount];
+            SkBlitter*  blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap,
+                                                ix, iy, storage, sizeof(storage));
+            if (blitter) {
+                SkAutoTPlacementDelete<SkBlitter>   ad(blitter, storage);
+
+                SkIRect    ir;
+                ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height());
+
+                SkScan::FillIRect(ir, *fRC, blitter);
+                return;
             }
-            return;
         }
-#if 0
-        SkDebugf("---- MISSING sprite case: config=%d [%d %d], device=%d, xfer=%p, alpha=0x%X colorFilter=%p\n",
-                bitmap.config(), bitmap.width(), bitmap.height(), fBitmap->config(),
-                paint.getXfermode(), paint.getAlpha(), paint.getColorFilter());
-#endif
     }
 
     // now make a temp draw on the stack, and use it
@@ -1187,7 +1217,7 @@ void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y,
     SkDEBUGCODE(this->validate();)
 
     // nothing to draw
-    if (fClip->isEmpty() ||
+    if (fRC->isEmpty() ||
             bitmap.width() == 0 || bitmap.height() == 0 ||
             bitmap.getConfig() == SkBitmap::kNo_Config) {
         return;
@@ -1196,14 +1226,14 @@ void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y,
     SkIRect    bounds;
     bounds.set(x, y, x + bitmap.width(), y + bitmap.height());
 
-    if (fClip->quickReject(bounds)) {
+    if (fRC->quickReject(bounds)) {
         return; // nothing to draw
     }
 
     SkPaint paint(origPaint);
     paint.setStyle(SkPaint::kFill_Style);
 
-    if (NULL == paint.getColorFilter()) {
+    if (NULL == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, bitmap)) {
         uint32_t    storage[kBlitterStorageLongCount];
         SkBlitter*  blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap,
                                                 x, y, storage, sizeof(storage));
@@ -1215,13 +1245,7 @@ void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y,
                 return;
             }
 
-            SkRegion::Cliperator iter(*fClip, bounds);
-            const SkIRect&       cr = iter.rect();
-
-            for (; !iter.done(); iter.next()) {
-                SkASSERT(!cr.isEmpty());
-                blitter->blitRect(cr.fLeft, cr.fTop, cr.width(), cr.height());
-            }
+            SkScan::FillIRect(bounds, *fRC, blitter);
             return;
         }
     }
@@ -1313,9 +1337,9 @@ static void D1G_NoBounder_RectClip(const SkDraw1Glyph& state,
     int left = SkFixedFloor(fx);
     int top = SkFixedFloor(fy);
     SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
-       SkASSERT(state.fClip->isRect());
        SkASSERT(NULL == state.fBounder);
-       SkASSERT(state.fClipBounds == state.fClip->getBounds());
+    SkASSERT(NULL == state.fClip && state.fAAClip ||
+             state.fClip && NULL == state.fAAClip && state.fClip->isRect());
 
     left += glyph.fLeft;
     top  += glyph.fTop;
@@ -1394,15 +1418,15 @@ static void D1G_Bounder(const SkDraw1Glyph& state,
     int left = SkFixedFloor(fx);
     int top = SkFixedFloor(fy);
     SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
-
+    
     SkMask  mask;
-
+    
     left += glyph.fLeft;
     top  += glyph.fTop;
-
+    
     mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight);
     SkRegion::Cliperator clipper(*state.fClip, mask.fBounds);
-
+    
        if (!clipper.done()) {
                const SkIRect&  cr = clipper.rect();
                const uint8_t*  aa = (const uint8_t*)glyph.fImage;
@@ -1412,7 +1436,7 @@ static void D1G_Bounder(const SkDraw1Glyph& state,
                                return;
             }
                }
-
+        
         // we need to pass the origin, which we approximate with our
         // (unadjusted) left,top coordinates (the caller called fixedfloor)
                if (state.fBounder->doIRectGlyph(cr,
@@ -1429,6 +1453,19 @@ static void D1G_Bounder(const SkDraw1Glyph& state,
        }
 }
 
+static void D1G_Bounder_AAClip(const SkDraw1Glyph& state,
+                               SkFixed fx, SkFixed fy,
+                               const SkGlyph& glyph) {
+    int left = SkFixedFloor(fx);
+    int top = SkFixedFloor(fy);
+    SkIRect bounds;
+    bounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight);
+
+    if (state.fBounder->doIRectGlyph(bounds, left, top, glyph)) {
+        D1G_NoBounder_RectClip(state, fx, fy, glyph);
+    }
+}
+
 static bool hasCustomD1GProc(const SkDraw& draw) {
     return draw.fProcs && draw.fProcs->fD1GProc;
 }
@@ -1441,23 +1478,38 @@ SkDraw1Glyph::Proc SkDraw1Glyph::init(const SkDraw* draw, SkBlitter* blitter,
                                       SkGlyphCache* cache) {
     fDraw = draw;
        fBounder = draw->fBounder;
-       fClip = draw->fClip;
-    fClipBounds = fClip->getBounds();
        fBlitter = blitter;
        fCache = cache;
 
     if (hasCustomD1GProc(*draw)) {
+        // todo: fix this assumption about clips w/ custom
+        fClip = draw->fClip;
+        fClipBounds = fClip->getBounds();
         return draw->fProcs->fD1GProc;
     }
 
-    if (NULL == fBounder) {
-        if (fClip->isRect()) {
+    if (draw->fRC->isBW()) {
+        fAAClip = NULL;
+        fClip = &draw->fRC->bwRgn();
+        fClipBounds = fClip->getBounds();
+        if (NULL == fBounder) {
+            if (fClip->isRect()) {
+                return D1G_NoBounder_RectClip;
+            } else {
+                return D1G_NoBounder_RgnClip;
+            }
+        } else {
+            return D1G_Bounder;
+        }
+    } else {    // aaclip
+        fAAClip = &draw->fRC->aaRgn();
+        fClip = NULL;
+        fClipBounds = fAAClip->getBounds();
+        if (NULL == fBounder) {
             return D1G_NoBounder_RectClip;
         } else {
-            return D1G_NoBounder_RgnClip;
+            return D1G_Bounder_AAClip;
         }
-    } else {
-        return D1G_Bounder;
     }
 }
 
@@ -1470,7 +1522,7 @@ void SkDraw::drawText(const char text[], size_t byteLength,
     SkDEBUGCODE(this->validate();)
 
     // nothing to draw
-    if (text == NULL || byteLength == 0 || fClip->isEmpty()) {
+    if (text == NULL || byteLength == 0 || fRC->isEmpty()) {
         return;
     }
 
@@ -1537,14 +1589,21 @@ void SkDraw::drawText(const char text[], size_t byteLength,
     fx += SK_FixedHalf;
     fy += SK_FixedHalf;
 
-    SkAutoBlitterChoose blitter;
+    SkAAClipBlitter     aaBlitter;
+    SkAutoBlitterChoose blitterChooser;
+    SkBlitter*          blitter = NULL;
     if (needsRasterTextBlit(*this)) {
-        blitter.choose(*fBitmap, *matrix, paint);
+        blitterChooser.choose(*fBitmap, *matrix, paint);
+        blitter = blitterChooser.get();
+        if (fRC->isAA()) {
+            aaBlitter.init(blitter, &fRC->aaRgn());
+            blitter = &aaBlitter;
+        }
     }
 
     SkAutoKern          autokern;
     SkDraw1Glyph        d1g;
-    SkDraw1Glyph::Proc  proc = d1g.init(this, blitter.get(), cache);
+    SkDraw1Glyph::Proc  proc = d1g.init(this, blitter, cache);
 
     while (text < stop) {
         const SkGlyph& glyph  = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
@@ -1660,7 +1719,7 @@ void SkDraw::drawPosText(const char text[], size_t byteLength,
     SkDEBUGCODE(this->validate();)
 
     // nothing to draw
-    if (text == NULL || byteLength == 0 || fClip->isEmpty()) {
+    if (text == NULL || byteLength == 0 || fRC->isEmpty()) {
         return;
     }
 
@@ -1684,15 +1743,22 @@ void SkDraw::drawPosText(const char text[], size_t byteLength,
     SkAutoGlyphCache    autoCache(paint, matrix);
     SkGlyphCache*       cache = autoCache.getCache();
 
-    SkAutoBlitterChoose blitter;
+    SkAAClipBlitterWrapper wrapper;
+    SkAutoBlitterChoose blitterChooser;
+    SkBlitter* blitter = NULL;
     if (needsRasterTextBlit(*this)) {
-        blitter.choose(*fBitmap, *matrix, paint);
+        blitterChooser.choose(*fBitmap, *matrix, paint);
+        blitter = blitterChooser.get();
+        if (fRC->isAA()) {
+            wrapper.init(*fRC, blitter);
+            blitter = wrapper.getBlitter();
+        }
     }
     
     const char*        stop = text + byteLength;
     AlignProc          alignProc = pick_align_proc(paint.getTextAlign());
        SkDraw1Glyph       d1g;
-       SkDraw1Glyph::Proc  proc = d1g.init(this, blitter.get(), cache);
+       SkDraw1Glyph::Proc  proc = d1g.init(this, blitter, cache);
     TextMapState       tms(*matrix, constY);
     TextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition);
 
@@ -1866,7 +1932,7 @@ void SkDraw::drawTextOnPath(const char text[], size_t byteLength,
     SkASSERT(byteLength == 0 || text != NULL);
 
     // nothing to draw
-    if (text == NULL || byteLength == 0 || fClip->isEmpty()) {
+    if (text == NULL || byteLength == 0 || fRC->isEmpty()) {
         return;
     }
 
@@ -1912,7 +1978,7 @@ void SkDraw::drawPosTextOnPath(const char text[], size_t byteLength,
                                const SkPoint pos[], const SkPaint& paint,
                                const SkPath& path, const SkMatrix* matrix) const {
     // nothing to draw
-    if (text == NULL || byteLength == 0 || fClip->isEmpty()) {
+    if (text == NULL || byteLength == 0 || fRC->isEmpty()) {
         return;
     }
 
@@ -2099,7 +2165,7 @@ VertState::Proc VertState::chooseProc(SkCanvas::VertexMode mode) {
     }
 }
 
-typedef void (*HairProc)(const SkPoint&, const SkPoint&, const SkRegion*,
+typedef void (*HairProc)(const SkPoint&, const SkPoint&, const SkRasterClip&,
                          SkBlitter*);
 
 static HairProc ChooseHairProc(bool doAntiAlias) {
@@ -2210,7 +2276,7 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
     SkASSERT(0 == count || NULL != vertices);
 
     // abort early if there is nothing to draw
-    if (count < 3 || (indices && indexCount < 3) || fClip->isEmpty()) {
+    if (count < 3 || (indices && indexCount < 3) || fRC->isEmpty()) {
         return;
     }
 
@@ -2307,8 +2373,11 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
                     continue;
                 }
             }
-            SkScan::FillTriangle(devVerts[state.f0], devVerts[state.f1],
-                                 devVerts[state.f2], fClip, blitter.get());
+
+            SkPoint tmp[] = {
+                devVerts[state.f0], devVerts[state.f1], devVerts[state.f2]
+            };
+            SkScan::FillTriangle(tmp, *fRC, blitter.get());
         }
         // now restore the shader's original local matrix
         if (NULL != shader) {
@@ -2321,10 +2390,11 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
     } else {
         // no colors[] and no texture
         HairProc hairProc = ChooseHairProc(paint.isAntiAlias());
+        const SkRasterClip& clip = *fRC;
         while (vertProc(&state)) {
-            hairProc(devVerts[state.f0], devVerts[state.f1], fClip, blitter.get());
-            hairProc(devVerts[state.f1], devVerts[state.f2], fClip, blitter.get());
-            hairProc(devVerts[state.f2], devVerts[state.f0], fClip, blitter.get());
+            hairProc(devVerts[state.f0], devVerts[state.f1], clip, blitter.get());
+            hairProc(devVerts[state.f1], devVerts[state.f2], clip, blitter.get());
+            hairProc(devVerts[state.f2], devVerts[state.f0], clip, blitter.get());
         }
     }
 }
@@ -2338,8 +2408,9 @@ void SkDraw::validate() const {
     SkASSERT(fBitmap != NULL);
     SkASSERT(fMatrix != NULL);
     SkASSERT(fClip != NULL);
+    SkASSERT(fRC != NULL);
 
-    const SkIRect&  cr = fClip->getBounds();
+    const SkIRect&  cr = fRC->getBounds();
     SkIRect         br;
 
     br.set(0, 0, fBitmap->width(), fBitmap->height());
@@ -2499,21 +2570,22 @@ static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds,
 }
 
 static void draw_into_mask(const SkMask& mask, const SkPath& devPath) {
-    SkBitmap    bm;
-    SkDraw      draw;
-    SkRegion    clipRgn;
-    SkMatrix    matrix;
-    SkPaint     paint;
+    SkBitmap        bm;
+    SkDraw          draw;
+    SkRasterClip    clip;
+    SkMatrix        matrix;
+    SkPaint         paint;
 
     bm.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(), mask.fBounds.height(), mask.fRowBytes);
     bm.setPixels(mask.fImage);
 
-    clipRgn.setRect(0, 0, mask.fBounds.width(), mask.fBounds.height());
+    clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height()));
     matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
                         -SkIntToScalar(mask.fBounds.fTop));
 
     draw.fBitmap    = &bm;
-    draw.fClip      = &clipRgn;
+    draw.fRC        = &clip;
+    draw.fClip      = &clip.bwRgn();
     draw.fMatrix    = &matrix;
     draw.fBounder   = NULL;
     paint.setAntiAlias(true);
index 82ee9ba..74aa9bb 100644 (file)
 
 #include "SkDraw.h"
 
+class SkAAClip;
 class SkBlitter;
 
 struct SkDraw1Glyph {
     const SkDraw*   fDraw;
        SkBounder*              fBounder;
        const SkRegion* fClip;
+       const SkAAClip* fAAClip;
        SkBlitter*              fBlitter;
        SkGlyphCache*   fCache;
        SkIRect                 fClipBounds;
index 980c350..3bdca10 100644 (file)
@@ -12,7 +12,7 @@
 #include "SkBounder.h"
 #include "SkBuffer.h"
 #include "SkDraw.h"
-#include "SkRegion.h"
+#include "SkRasterClip.h"
 
 bool SkMaskFilter::filterMask(SkMask*, const SkMask&, const SkMatrix&,
                               SkIPoint*) {
@@ -20,7 +20,7 @@ bool SkMaskFilter::filterMask(SkMask*, const SkMask&, const SkMatrix&,
 }
 
 bool SkMaskFilter::filterPath(const SkPath& devPath, const SkMatrix& matrix,
-                              const SkRegion& clip, SkBounder* bounder,
+                              const SkRasterClip& clip, SkBounder* bounder,
                               SkBlitter* blitter) {
     SkMask  srcM, dstM;
 
@@ -35,7 +35,11 @@ bool SkMaskFilter::filterPath(const SkPath& devPath, const SkMatrix& matrix,
     }
     SkAutoMaskFreeImage autoDst(dstM.fImage);
 
-    SkRegion::Cliperator    clipper(clip, dstM.fBounds);
+    // if we get here, we need to (possibly) resolve the clip and blitter
+    SkAAClipBlitterWrapper wrapper(clip, blitter);
+    blitter = wrapper.getBlitter();
+
+    SkRegion::Cliperator clipper(wrapper.getRgn(), dstM.fBounds);
 
     if (!clipper.done() && (bounder == NULL || bounder->doIRect(dstM.fBounds))) {
         const SkIRect& cr = clipper.rect();
index 5588dfb..9bf39fa 100644 (file)
@@ -13,6 +13,8 @@ SkRasterClip::SkRasterClip() {
 }
 
 SkRasterClip::SkRasterClip(const SkRasterClip& src) {
+    AUTO_RASTERCLIP_VALIDATE(src);
+    
     fIsBW = src.fIsBW;
     if (fIsBW) {
         fBW = src.fBW;
@@ -25,7 +27,9 @@ SkRasterClip::SkRasterClip(const SkIRect& bounds) : fBW(bounds) {
     fIsBW = true;
 }
 
-SkRasterClip::~SkRasterClip() {}
+SkRasterClip::~SkRasterClip() {
+    AUTO_RASTERCLIP_VALIDATE(*this);
+}
 
 bool SkRasterClip::isEmpty() const {
     return fIsBW ? fBW.isEmpty() : fAA.isEmpty();
@@ -44,6 +48,8 @@ const SkIRect& SkRasterClip::getBounds() const {
 }
 
 bool SkRasterClip::setEmpty() {
+    AUTO_RASTERCLIP_VALIDATE(*this);
+
     fIsBW = true;
     fBW.setEmpty();
     fAA.setEmpty();
@@ -51,12 +57,16 @@ bool SkRasterClip::setEmpty() {
 }
 
 bool SkRasterClip::setRect(const SkIRect& rect) {
+    AUTO_RASTERCLIP_VALIDATE(*this);
+    
     fIsBW = true;
     fAA.setEmpty();
     return fBW.setRect(rect);
 }
 
 bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) {
+    AUTO_RASTERCLIP_VALIDATE(*this);
+
     if (this->isBW() && !doAA) {
         return fBW.setPath(path, clip);
     } else {
@@ -88,10 +98,14 @@ bool SkRasterClip::setPath(const SkPath& path, const SkRasterClip& clip,
 }
 
 bool SkRasterClip::op(const SkIRect& rect, SkRegion::Op op) {
+    AUTO_RASTERCLIP_VALIDATE(*this);
+    
     return fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
 }
 
 bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
+    AUTO_RASTERCLIP_VALIDATE(*this);
+    
     if (fIsBW) {
         return fBW.op(rgn, op);
     } else {
@@ -102,6 +116,9 @@ bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
 }
 
 bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
+    AUTO_RASTERCLIP_VALIDATE(*this);
+    clip.validate();
+
     if (this->isBW() && clip.isBW()) {
         return fBW.op(clip.fBW, op);
     } else {
@@ -121,15 +138,17 @@ bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
     }
 }
 
-// return true if x is nearly integral (within 1/256) since that is the highest
+// 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 / 256);
+    return SkScalarAbs(sx - x) < (SK_Scalar1 / 16);
 }
 
 bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
+    AUTO_RASTERCLIP_VALIDATE(*this);
+    
     if (doAA) {
         // check that the rect really needs aa
         if (is_integral(r.fLeft) && is_integral(r.fTop) &&
@@ -155,6 +174,8 @@ void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
         return;
     }
 
+    AUTO_RASTERCLIP_VALIDATE(*this);
+    
     if (this->isEmpty()) {
         dst->setEmpty();
         return;
@@ -174,9 +195,15 @@ void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
     }
 }
 
+bool SkRasterClip::quickContains(const SkIRect& ir) const {
+    return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 const SkRegion& SkRasterClip::forceGetBW() {
+    AUTO_RASTERCLIP_VALIDATE(*this);
+    
     if (!fIsBW) {
         fBW.setRect(fAA.getBounds());
     }
@@ -184,8 +211,60 @@ const SkRegion& SkRasterClip::forceGetBW() {
 }
 
 void SkRasterClip::convertToAA() {
+    AUTO_RASTERCLIP_VALIDATE(*this);
+    
     SkASSERT(fIsBW);
     fAA.setRegion(fBW);
     fIsBW = false;
 }
 
+#ifdef SK_DEBUG
+void SkRasterClip::validate() const {
+    // can't ever assert that fBW is empty, since we may have called forceGetBW
+    if (fIsBW) {
+        SkASSERT(fAA.isEmpty());
+    }
+
+    fBW.validate();
+    fAA.validate();
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
+    SkDEBUGCODE(fClipRgn = NULL;)
+    SkDEBUGCODE(fBlitter = NULL;)
+}
+
+SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
+                                               SkBlitter* blitter) {
+    this->init(clip, blitter);
+}
+
+SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip,
+                                               SkBlitter* blitter) {
+    SkASSERT(blitter);
+    SkASSERT(aaclip);
+    fBWRgn.setRect(aaclip->getBounds());
+    fAABlitter.init(blitter, aaclip);
+    // now our return values
+    fClipRgn = &fBWRgn;
+    fBlitter = &fAABlitter;
+}
+
+void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) {
+    SkASSERT(blitter);
+    if (clip.isBW()) {
+        fClipRgn = &clip.bwRgn();
+        fBlitter = blitter;
+    } else {
+        const SkAAClip& aaclip = clip.aaRgn();
+        fBWRgn.setRect(aaclip.getBounds());
+        fAABlitter.init(blitter, &aaclip);
+        // now our return values
+        fClipRgn = &fBWRgn;
+        fBlitter = &fAABlitter;
+    }
+}
+
index 2467120..8f18270 100644 (file)
@@ -45,6 +45,11 @@ public:
         this->translate(dx, dy, this);
     }
 
+    bool quickContains(const SkIRect& rect) const;
+    bool quickContains(int left, int top, int right, int bottom) const {
+        return quickContains(SkIRect::MakeLTRB(left, top, right, bottom));
+    }
+    
     /**
      *  Return true if this region is empty, or if the specified rectangle does
      *  not intersect the region. Returning false is not a guarantee that they
@@ -58,6 +63,12 @@ public:
     // hack for SkCanvas::getTotalClip
     const SkRegion& forceGetBW();
 
+#ifdef SK_DEBUG
+    void validate() const;
+#else
+    void validate() const {}
+#endif
+
 private:
     SkRegion    fBW;
     SkAAClip    fAA;
@@ -66,4 +77,63 @@ private:
     void convertToAA();
 };
 
+class SkAutoRasterClipValidate : SkNoncopyable {
+public:
+    SkAutoRasterClipValidate(const SkRasterClip& rc) : fRC(rc) {
+        fRC.validate();
+    }
+    ~SkAutoRasterClipValidate() {
+        fRC.validate();
+    }
+private:
+    const SkRasterClip& fRC;
+};
+
+#ifdef SK_DEBUG
+    #define AUTO_RASTERCLIP_VALIDATE(rc)    SkAutoRasterClipValidate arcv(rc)
+#else
+    #define AUTO_RASTERCLIP_VALIDATE(rc)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ *  Encapsulates the logic of deciding if we need to change/wrap the blitter
+ *  for aaclipping. If so, getRgn and getBlitter return modified values. If
+ *  not, they return the raw blitter and (bw) clip region.
+ *
+ *  We need to keep the constructor/destructor cost as small as possible, so we
+ *  can freely put this guy on the stack, and not pay too much for the case when
+ *  we're really BW anyways.
+ */
+class SkAAClipBlitterWrapper {
+public:
+    SkAAClipBlitterWrapper();
+    SkAAClipBlitterWrapper(const SkRasterClip&, SkBlitter*);
+    SkAAClipBlitterWrapper(const SkAAClip*, SkBlitter*);
+    
+    void init(const SkRasterClip&, SkBlitter*);
+
+    const SkIRect& getBounds() const {
+        SkASSERT(fClipRgn);
+        return fClipRgn->getBounds();
+    }
+    const SkRegion& getRgn() const {
+        SkASSERT(fClipRgn);
+        return *fClipRgn;
+    }
+    SkBlitter* getBlitter() {
+        SkASSERT(fBlitter);
+        return fBlitter;
+    }
+    
+private:
+    const SkAAClip* fAAClip;
+    SkRegion        fBWRgn;
+    SkAAClipBlitter fAABlitter;
+    // what we return
+    const SkRegion* fClipRgn;
+    SkBlitter* fBlitter;
+};
+
 #endif
index a814719..27481f8 100644 (file)
@@ -15,7 +15,7 @@
 #include "SkMaskFilter.h"
 #include "SkPathEffect.h"
 #include "SkRasterizer.h"
-#include "SkRegion.h"
+#include "SkRasterClip.h"
 #include "SkStroke.h"
 #include "SkThread.h"
 
@@ -448,8 +448,8 @@ static void generateMask(const SkMask& mask, const SkPath& path) {
         }
     }
 
-    SkRegion    clip;
-    clip.setRect(0, 0, dstW, dstH);
+    SkRasterClip clip;
+    clip.setRect(SkIRect::MakeWH(dstW, dstH));
 
     SkBitmap bm;
     bm.setConfig(config, dstW, dstH, dstRB);
@@ -464,7 +464,8 @@ static void generateMask(const SkMask& mask, const SkPath& path) {
     
     SkDraw  draw;
     sk_bzero(&draw, sizeof(draw));
-    draw.fClip  = &clip;
+    draw.fRC    = &clip;
+    draw.fClip  = &clip.bwRgn();
     draw.fMatrix = &matrix;
     draw.fBitmap = &bm;
     draw.drawPath(path, paint);
index ce46669..cee328f 100644 (file)
@@ -78,12 +78,41 @@ void SkScan::FillIRect(const SkIRect& r, const SkRasterClip& clip,
         return;
     }
 
-    const SkAAClip* aaClip = &clip.aaRgn();
-    SkRegion        tmp;
-    SkAAClipBlitter aaBlitter;
+    SkAAClipBlitterWrapper wrapper(clip, blitter);
+    FillIRect(r, &wrapper.getRgn(), wrapper.getBlitter());
+}
+
+void SkScan::FillXRect(const SkXRect& xr, const SkRasterClip& clip,
+                       SkBlitter* blitter) {
+    if (clip.isEmpty() || xr.isEmpty()) {
+        return;
+    }
     
-    tmp.setRect(aaClip->getBounds());
-    aaBlitter.init(blitter, aaClip);
-    FillIRect(r, &tmp, &aaBlitter);
+    if (clip.isBW()) {
+        FillXRect(xr, &clip.bwRgn(), blitter);
+        return;
+    }
+
+    SkAAClipBlitterWrapper wrapper(clip, blitter);
+    FillXRect(xr, &wrapper.getRgn(), wrapper.getBlitter());
 }
 
+#ifdef SK_SCALAR_IS_FLOAT
+
+void SkScan::FillRect(const SkRect& r, const SkRasterClip& clip,
+                      SkBlitter* blitter) {
+    if (clip.isEmpty() || r.isEmpty()) {
+        return;
+    }
+    
+    if (clip.isBW()) {
+        FillRect(r, &clip.bwRgn(), blitter);
+        return;
+    }
+
+    SkAAClipBlitterWrapper wrapper(clip, blitter);
+    FillRect(r, &wrapper.getRgn(), wrapper.getBlitter());
+}
+
+#endif
+
index 9497f60..fae5cb2 100644 (file)
@@ -58,6 +58,7 @@ protected:
 
     SkDEBUGCODE(int fCurrX;)
     int fCurrY;
+    int fTop;
 };
 
 BaseSuperBlitter::BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
@@ -72,8 +73,14 @@ BaseSuperBlitter::BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
     fLeft = left;
     fSuperLeft = left << SHIFT;
     fWidth = right - left;
+#if 0
     fCurrIY = -1;
     fCurrY = -1;
+#else
+    fTop = ir.fTop;
+    fCurrIY = ir.fTop - 1;
+    fCurrY = (ir.fTop << SHIFT) - 1;
+#endif
     SkDEBUGCODE(fCurrX = -1;)
 }
 
@@ -111,14 +118,14 @@ SuperBlitter::SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
 }
 
 void SuperBlitter::flush() {
-    if (fCurrIY >= 0) {
+    if (fCurrIY >= fTop) {
         if (!fRuns.empty()) {
         //  SkDEBUGCODE(fRuns.dump();)
             fRealBlitter->blitAntiH(fLeft, fCurrIY, fRuns.fAlpha, fRuns.fRuns);
             fRuns.reset(fWidth);
             fOffsetX = 0;
         }
-        fCurrIY = -1;
+        fCurrIY = fTop - 1;
         SkDEBUGCODE(fCurrX = -1;)
     }
 }
index 34ca47b..bb81cd6 100644 (file)
@@ -11,7 +11,7 @@
 #include "SkBlitter.h"
 #include "SkColorPriv.h"
 #include "SkLineClipper.h"
-#include "SkRegion.h"
+#include "SkRasterClip.h"
 #include "SkFDot6.h"
 
 /*  Our attempt to compute the worst case "bounds" for the horizontal and
@@ -387,8 +387,8 @@ static void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1,
     }
 }
 
-void SkScan::AntiHairLine(const SkPoint& pt0, const SkPoint& pt1,
-                          const SkRegion* clip, SkBlitter* blitter) {
+void SkScan::AntiHairLineRgn(const SkPoint& pt0, const SkPoint& pt1,
+                             const SkRegion* clip, SkBlitter* blitter) {
     if (clip && clip->isEmpty()) {
         return;
     }
@@ -455,7 +455,7 @@ void SkScan::AntiHairLine(const SkPoint& pt0, const SkPoint& pt1,
     do_anti_hairline(x0, y0, x1, y1, NULL, blitter);
 }
 
-void SkScan::AntiHairRect(const SkRect& rect, const SkRegion* clip,
+void SkScan::AntiHairRect(const SkRect& rect, const SkRasterClip& clip,
                           SkBlitter* blitter) {
     SkPoint p0, p1;
 
@@ -556,42 +556,42 @@ static void antifillrect(const SkXRect& xr, SkBlitter* blitter) {
 
 ///////////////////////////////////////////////////////////////////////////////
 
-void SkScan::AntiFillXRect(const SkXRect& xr, const SkRegion* clip,
+void SkScan::AntiFillXRect(const SkXRect& xr, const SkRasterClip& clip,
                           SkBlitter* blitter) {
-    if (clip) {
-        SkIRect outerBounds;
-        XRect_roundOut(xr, &outerBounds);
+    SkAAClipBlitterWrapper wrapper(clip, blitter);
+    const SkRegion* clipRgn = &wrapper.getRgn();
+    blitter = wrapper.getBlitter();
 
-        if (clip->isRect()) {
-            const SkIRect& clipBounds = clip->getBounds();
-
-            if (clipBounds.contains(outerBounds)) {
-                antifillrect(xr, blitter);
-            } else {
-                SkXRect tmpR;
-                // this keeps our original edges fractional
-                XRect_set(&tmpR, clipBounds);
-                if (tmpR.intersect(xr)) {
-                    antifillrect(tmpR, blitter);
-                }
-            }
+    SkIRect outerBounds;
+    XRect_roundOut(xr, &outerBounds);
+
+    if (clipRgn->isRect()) {
+        const SkIRect& clipBounds = clipRgn->getBounds();
+
+        if (clipBounds.contains(outerBounds)) {
+            antifillrect(xr, blitter);
         } else {
-            SkRegion::Cliperator clipper(*clip, outerBounds);
-            const SkIRect&       rr = clipper.rect();
-            
-            while (!clipper.done()) {
-                SkXRect  tmpR;
-                
-                // this keeps our original edges fractional
-                XRect_set(&tmpR, rr);
-                if (tmpR.intersect(xr)) {
-                    antifillrect(tmpR, blitter);
-                }
-                clipper.next();
+            SkXRect tmpR;
+            // this keeps our original edges fractional
+            XRect_set(&tmpR, clipBounds);
+            if (tmpR.intersect(xr)) {
+                antifillrect(tmpR, blitter);
             }
         }
     } else {
-        antifillrect(xr, blitter);
+        SkRegion::Cliperator clipper(*clipRgn, outerBounds);
+        const SkIRect&       rr = clipper.rect();
+        
+        while (!clipper.done()) {
+            SkXRect  tmpR;
+            
+            // this keeps our original edges fractional
+            XRect_set(&tmpR, rr);
+            if (tmpR.intersect(xr)) {
+                antifillrect(tmpR, blitter);
+            }
+            clipper.next();
+        }
     }
 }
 
@@ -645,6 +645,16 @@ void SkScan::AntiFillRect(const SkRect& origR, const SkRegion* clip,
     }
 }
 
+void SkScan::AntiFillRect(const SkRect& r, const SkRasterClip& clip,
+                          SkBlitter* blitter) {
+    if (clip.isBW()) {
+        AntiFillRect(r, &clip.bwRgn(), blitter);
+    } else {
+        SkAAClipBlitterWrapper wrap(clip, blitter);
+        AntiFillRect(r, &wrap.getRgn(), wrap.getBlitter());
+    }
+}
+
 #endif // SK_SCALAR_IS_FLOAT
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -805,3 +815,14 @@ void SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize,
         innerstrokedot8(L, T, R, B, blitter);
     }
 }
+
+void SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize,
+                           const SkRasterClip& clip, SkBlitter* blitter) {
+    if (clip.isBW()) {
+        AntiFrameRect(r, strokeSize, &clip.bwRgn(), blitter);
+    } else {
+        SkAAClipBlitterWrapper wrap(clip, blitter);
+        AntiFrameRect(r, strokeSize, &wrap.getRgn(), wrap.getBlitter());
+    }
+}
+
index 0a0aa21..412ec03 100644 (file)
@@ -9,7 +9,7 @@
 
 #include "SkScan.h"
 #include "SkBlitter.h"
-#include "SkRegion.h"
+#include "SkRasterClip.h"
 #include "SkFDot6.h"
 #include "SkLineClipper.h"
 
@@ -33,8 +33,8 @@ static void vertline(int y, int stopy, SkFixed fx, SkFixed dx,
     } while (++y < stopy);
 }
 
-void SkScan::HairLine(const SkPoint& pt0, const SkPoint& pt1,
-                      const SkRegion* clip, SkBlitter* blitter) {
+void SkScan::HairLineRgn(const SkPoint& pt0, const SkPoint& pt1,
+                         const SkRegion* clip, SkBlitter* blitter) {
     SkBlitterClipper    clipper;
     SkRect  r;
     SkIRect clipR, ptsR;
@@ -120,8 +120,9 @@ void SkScan::HairLine(const SkPoint& pt0, const SkPoint& pt1,
 // we don't just draw 4 lines, 'cause that can leave a gap in the bottom-right
 // and double-hit the top-left.
 // TODO: handle huge coordinates on rect (before calling SkScalarToFixed)
-void SkScan::HairRect(const SkRect& rect, const SkRegion* clip,
+void SkScan::HairRect(const SkRect& rect, const SkRasterClip& clip,
                       SkBlitter* blitter) {
+    SkAAClipBlitterWrapper wrapper;
     SkBlitterClipper    clipper;
     SkIRect             r;
 
@@ -130,13 +131,19 @@ void SkScan::HairRect(const SkRect& rect, const SkRegion* clip,
           (SkScalarToFixed(rect.fRight) >> 16) + 1,
           (SkScalarToFixed(rect.fBottom) >> 16) + 1);
 
-    if (clip) {
-        if (clip->quickReject(r)) {
-            return;
-        }
-        if (!clip->quickContains(r)) {
-            blitter = clipper.apply(blitter, clip);
+    if (clip.quickReject(r)) {
+        return;
+    }
+    if (!clip.quickContains(r)) {
+        const SkRegion* clipRgn;
+        if (clip.isBW()) {
+            clipRgn = &clip.bwRgn();
+        } else {
+            wrapper.init(clip, blitter);
+            clipRgn = &wrapper.getRgn();
+            blitter = wrapper.getBlitter();
         }
+        blitter = clipper.apply(blitter, clipRgn);
     }
 
     int width = r.width();
@@ -238,27 +245,34 @@ static void haircubic(const SkPoint pts[4], const SkRegion* clip, SkBlitter* bli
 #define kMaxCubicSubdivideLevel 6
 #define kMaxQuadSubdivideLevel  5
 
-static void hair_path(const SkPath& path, const SkRegion* clip, SkBlitter* blitter,
+static void hair_path(const SkPath& path, const SkRasterClip& rclip, SkBlitter* blitter,
                       void (*lineproc)(const SkPoint&, const SkPoint&, const SkRegion*, SkBlitter*))
 {
     if (path.isEmpty()) {
         return;
     }
 
+    SkAAClipBlitterWrapper wrap;
     const SkIRect* clipR = NULL;
+    const SkRegion* clip = NULL;
 
-    if (clip) {
+    {
         SkIRect ibounds;
         path.getBounds().roundOut(&ibounds);
         ibounds.inset(-1, -1);
 
-        if (clip->quickReject(ibounds)) {
+        if (rclip.quickReject(ibounds)) {
             return;
         }
-        if (clip->quickContains(ibounds)) {
-            clip = NULL;
-        } else {
-            clipR = &clip->getBounds();
+        if (!rclip.quickContains(ibounds)) {
+            clipR = &rclip.getBounds();
+            if (rclip.isBW()) {
+                clip = &rclip.bwRgn();
+            } else {
+                wrap.init(rclip, blitter);
+                blitter = wrap.getBlitter();
+                clip = &wrap.getRgn();
+            }
         }
     }
 
@@ -296,20 +310,20 @@ static void hair_path(const SkPath& path, const SkRegion* clip, SkBlitter* blitt
     }
 }
 
-void SkScan::HairPath(const SkPath& path, const SkRegion* clip,
+void SkScan::HairPath(const SkPath& path, const SkRasterClip& clip,
                       SkBlitter* blitter) {
-    hair_path(path, clip, blitter, SkScan::HairLine);
+    hair_path(path, clip, blitter, SkScan::HairLineRgn);
 }
 
-void SkScan::AntiHairPath(const SkPath& path, const SkRegion* clip,
+void SkScan::AntiHairPath(const SkPath& path, const SkRasterClip& clip,
                           SkBlitter* blitter) {
-    hair_path(path, clip, blitter, SkScan::AntiHairLine);
+    hair_path(path, clip, blitter, SkScan::AntiHairLineRgn);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 void SkScan::FrameRect(const SkRect& r, const SkPoint& strokeSize,
-                       const SkRegion* clip, SkBlitter* blitter) {
+                       const SkRasterClip& clip, SkBlitter* blitter) {
     SkASSERT(strokeSize.fX >= 0 && strokeSize.fY >= 0);
 
     if (strokeSize.fX < 0 || strokeSize.fY < 0) {
@@ -343,3 +357,48 @@ void SkScan::FrameRect(const SkRect& r, const SkPoint& strokeSize,
     SkScan::FillRect(tmp, clip, blitter);
 }
 
+void SkScan::HairLine(const SkPoint& p0, const SkPoint& p1,
+                      const SkRasterClip& clip, SkBlitter* blitter) {
+    if (clip.isBW()) {
+        HairLineRgn(p0, p1, &clip.bwRgn(), blitter);
+    } else {
+        const SkRegion* clipRgn = NULL;
+        SkRect r;
+        SkIRect ir;
+        r.set(p0.fX, p0.fY, p1.fX, p1.fY);
+        r.sort();
+        r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
+        r.roundOut(&ir);
+
+        SkAAClipBlitterWrapper wrap;
+        if (!clip.quickContains(ir)) {
+            wrap.init(clip, blitter);
+            blitter = wrap.getBlitter();
+            clipRgn = &wrap.getRgn();
+        }
+        HairLineRgn(p0, p1, clipRgn, blitter);
+    }
+}
+
+void SkScan::AntiHairLine(const SkPoint& p0, const SkPoint& p1,
+                          const SkRasterClip& clip, SkBlitter* blitter) {
+    if (clip.isBW()) {
+        AntiHairLineRgn(p0, p1, &clip.bwRgn(), blitter);
+    } else {
+        const SkRegion* clipRgn = NULL;
+        SkRect r;
+        SkIRect ir;
+        r.set(p0.fX, p0.fY, p1.fX, p1.fY);
+        r.sort();
+        r.roundOut(&ir);
+        ir.inset(-1, -1);
+        
+        SkAAClipBlitterWrapper wrap;
+        if (!clip.quickContains(ir)) {
+            wrap.init(clip, blitter);
+            blitter = wrap.getBlitter();
+            clipRgn = &wrap.getRgn();
+        }
+        AntiHairLineRgn(p0, p1, clipRgn, blitter);
+    }
+}
index 06f89ce..1e2105a 100644 (file)
@@ -14,6 +14,7 @@
 #include "SkGeometry.h"
 #include "SkPath.h"
 #include "SkQuadClipper.h"
+#include "SkRasterClip.h"
 #include "SkRegion.h"
 #include "SkTemplates.h"
 
@@ -474,6 +475,12 @@ void SkScan::FillPath(const SkPath& path, const SkRegion& origClip,
     }
 }
 
+void SkScan::FillPath(const SkPath& path, const SkIRect& ir,
+                      SkBlitter* blitter) {
+    SkRegion rgn(ir);
+    FillPath(path, rgn, blitter);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 static int build_tri_edges(SkEdge edge[], const SkPoint pts[],
@@ -535,9 +542,9 @@ static void sk_fill_triangle(const SkPoint pts[], const SkIRect* clipRect,
     walk_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y, NULL);
 }
 
-void SkScan::FillTriangle(const SkPoint pts[], const SkRegion* clip,
+void SkScan::FillTriangle(const SkPoint pts[], const SkRasterClip& clip,
                           SkBlitter* blitter) {
-    if (clip && clip->isEmpty()) {
+    if (clip.isEmpty()) {
         return;
     }
 
@@ -545,12 +552,21 @@ void SkScan::FillTriangle(const SkPoint pts[], const SkRegion* clip,
     SkIRect ir;
     r.set(pts, 3);
     r.round(&ir);
-    if (ir.isEmpty()) {
+    if (ir.isEmpty() || !SkIRect::Intersects(ir, clip.getBounds())) {
         return;
     }
 
-    SkScanClipper   clipper(blitter, clip, ir);
+    SkAAClipBlitterWrapper wrap;
+    const SkRegion* clipRgn;
+    if (clip.isBW()) {
+        clipRgn = &clip.bwRgn();
+    } else {
+        wrap.init(clip, blitter);
+        clipRgn = &wrap.getRgn();
+        blitter = wrap.getBlitter();
+    }
 
+    SkScanClipper clipper(blitter, clipRgn, ir);
     blitter = clipper.getBlitter();
     if (NULL != blitter) {
         sk_fill_triangle(pts, clipper.getClipRect(), blitter, ir);
index 95f425f..ee081f1 100644 (file)
@@ -39,12 +39,8 @@ bool Sk2DPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
     src.transform(fInverse, &tmp);
     tmp.getBounds().round(&ir);
     if (!ir.isEmpty()) {
-        // need to pass a clip to fillpath, required for inverse filltypes,
-        // even though those do not make sense for this patheffect
-        SkRegion clip(ir);
-        
         this->begin(ir, dst);
-        SkScan::FillPath(tmp, clip, &blitter);
+        SkScan::FillPath(tmp, ir, &blitter);
         this->end(dst);
     }
     return true;
index 5a7be9d..fd73ffd 100644 (file)
@@ -14,7 +14,7 @@
 #include "SkMaskFilter.h"
 #include "SkPaint.h"
 #include "SkPath.h"
-#include "SkRegion.h"
+#include "../core/SkRasterClip.h"
 #include "SkXfermode.h"
 #include <new>
 
@@ -107,13 +107,13 @@ bool SkLayerRasterizer::onRasterize(const SkPath& path, const SkMatrix& matrix,
     }
 
     if (SkMask::kJustComputeBounds_CreateMode != mode) {
-        SkBitmap device;
-        SkDraw   draw;
-        SkMatrix translatedMatrix;  // this translates us to our local pixels
-        SkMatrix drawMatrix;        // this translates the path by each layer's offset
-        SkRegion rectClip;
+        SkBitmap        device;
+        SkRasterClip    rectClip;
+        SkDraw          draw;
+        SkMatrix        translatedMatrix;  // this translates us to our local pixels
+        SkMatrix        drawMatrix;        // this translates the path by each layer's offset
 
-        rectClip.setRect(0, 0, mask->fBounds.width(), mask->fBounds.height());
+        rectClip.setRect(SkIRect::MakeWH(mask->fBounds.width(), mask->fBounds.height()));
 
         translatedMatrix = matrix;
         translatedMatrix.postTranslate(-SkIntToScalar(mask->fBounds.fLeft),
@@ -124,7 +124,8 @@ bool SkLayerRasterizer::onRasterize(const SkPath& path, const SkMatrix& matrix,
 
         draw.fBitmap    = &device;
         draw.fMatrix    = &drawMatrix;
-        draw.fClip      = &rectClip;
+        draw.fRC        = &rectClip;
+        draw.fClip      = &rectClip.bwRgn();
         // we set the matrixproc in the loop, as the matrix changes each time (potentially)
         draw.fBounder   = NULL;
 
index 8621c8e..8271851 100644 (file)
@@ -32,12 +32,12 @@ struct FakeBlitter : public SkBlitter {
 // but skipped after tessellation, should be cleared by the blitter.
 static void TestFillPathInverse(skiatest::Reporter* reporter) {
   FakeBlitter blitter;
-  SkRegion clip;
+  SkIRect clip;
   SkPath path;
   int height = 100;
   int width  = 200;
   int expected_lines = 5;
-  clip.setRect(0, height - expected_lines, width, height);
+  clip.set(0, height - expected_lines, width, height);
   path.moveTo(0.0, 0.0);
   path.quadTo(width/2, height, width, 0.0);
   path.close();