enable soft clipping (yikes)
git-svn-id: http://skia.googlecode.com/svn/trunk@2515 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkDraw.h b/include/core/SkDraw.h
index eb87247..2ea0740 100644
--- a/include/core/SkDraw.h
+++ b/include/core/SkDraw.h
@@ -23,6 +23,7 @@
class SkDevice;
class SkPath;
class SkRegion;
+class SkRasterClip;
struct SkDrawProcs;
class SkDraw {
@@ -105,7 +106,8 @@
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
diff --git a/include/core/SkMaskFilter.h b/include/core/SkMaskFilter.h
index fe0c69f..1f1d570 100644
--- a/include/core/SkMaskFilter.h
+++ b/include/core/SkMaskFilter.h
@@ -17,7 +17,7 @@
class SkBounder;
class SkMatrix;
class SkPath;
-class SkRegion;
+class SkRasterClip;
/** \class SkMaskFilter
@@ -55,14 +55,6 @@
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 @@
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
diff --git a/include/core/SkScan.h b/include/core/SkScan.h
index e5ea92d..7b4cdc1 100644
--- a/include/core/SkScan.h
+++ b/include/core/SkScan.h
@@ -24,63 +24,73 @@
class SkScan {
public:
+ 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 SkRasterClip& clip,
+ SkBlitter* blitter) {
+ SkScan::FillXRect(*(const SkXRect*)&rect, clip, blitter);
+ }
+ static void AntiFillRect(const SkRect& rect, const SkRasterClip& clip,
+ SkBlitter* blitter) {
+ SkScan::AntiFillXRect(*(const SkXRect*)&rect, clip, blitter);
+ }
+#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 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*);
+
+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 FillRect(const SkRect& rect, const SkRegion* 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,
- SkBlitter* blitter) {
- SkPoint pts[3];
- pts[0] = a;
- pts[1] = b;
- pts[2] = c;
- FillTriangle(pts, clip, blitter);
- }
-
- static void HairLine(const SkPoint&, const SkPoint&, const SkRegion*,
- SkBlitter*);
- static void HairRect(const SkRect&, const SkRegion* clip, SkBlitter*);
- static void HairPath(const SkPath&, const SkRegion* clip, SkBlitter*);
-
- static void AntiFillXRect(const SkXRect&, const SkRegion* clip, SkBlitter*);
-#ifdef SK_SCALAR_IS_FIXED
static void AntiFillRect(const SkRect& rect, const SkRegion* clip,
- SkBlitter* blitter) {
+ 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
diff --git a/samplecode/SampleAAClip.cpp b/samplecode/SampleAAClip.cpp
index dd6af09..93a77cb 100644
--- a/samplecode/SampleAAClip.cpp
+++ b/samplecode/SampleAAClip.cpp
@@ -16,6 +16,8 @@
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);
diff --git a/samplecode/SampleAAClip2.cpp b/samplecode/SampleAAClip2.cpp
index 6d854e8..e8f5a14 100644
--- a/samplecode/SampleAAClip2.cpp
+++ b/samplecode/SampleAAClip2.cpp
@@ -26,6 +26,8 @@
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 @@
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);
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index bed5459..740047e 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -893,7 +893,7 @@
if (fUseClip) {
canvas->drawColor(0xFFFF88FF);
- canvas->clipPath(fClipPath);
+ canvas->clipPath(fClipPath, SkRegion::kIntersect_Op, true);
}
return canvas;
diff --git a/samplecode/SampleClip.cpp b/samplecode/SampleClip.cpp
index 87ff0b6..570f0b9 100644
--- a/samplecode/SampleClip.cpp
+++ b/samplecode/SampleClip.cpp
@@ -13,58 +13,106 @@
#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());
- 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);
}
}
-typedef void (*CanvasProc)(SkCanvas*);
+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.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);
+ }
+}
+
+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 @@
}
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);
}
diff --git a/samplecode/SampleFuzz.cpp b/samplecode/SampleFuzz.cpp
index 51350be..02b2391 100644
--- a/samplecode/SampleFuzz.cpp
+++ b/samplecode/SampleFuzz.cpp
@@ -354,7 +354,6 @@
}
virtual void onDrawContent(SkCanvas* canvas) {
- SkIRect r = canvas->getTotalClip().getBounds();
do_fuzz(canvas);
this->inval(NULL);
}
diff --git a/samplecode/SampleXfermodesBlur.cpp b/samplecode/SampleXfermodesBlur.cpp
index cce37f5..11b1268 100644
--- a/samplecode/SampleXfermodesBlur.cpp
+++ b/samplecode/SampleXfermodesBlur.cpp
@@ -31,6 +31,11 @@
#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 @@
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:
diff --git a/src/core/SkAAClip.cpp b/src/core/SkAAClip.cpp
index 0ba43b1..485f16a 100644
--- a/src/core/SkAAClip.cpp
+++ b/src/core/SkAAClip.cpp
@@ -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 @@
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 @@
}
}
+#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(const SkAAClip& src) {
+ SkDEBUGCODE(fBounds.setEmpty();) // need this for validate
fRunHead = NULL;
*this = src;
}
@@ -143,6 +273,9 @@
}
SkAAClip& SkAAClip::operator=(const SkAAClip& src) {
+ AUTO_AACLIP_VALIDATE(*this);
+ src.validate();
+
if (this != &src) {
this->freeRuns();
fBounds = src.fBounds;
@@ -155,6 +288,9 @@
}
bool operator==(const SkAAClip& a, const SkAAClip& b) {
+ a.validate();
+ b.validate();
+
if (&a == &b) {
return true;
}
@@ -181,6 +317,9 @@
}
void SkAAClip::swap(SkAAClip& other) {
+ AUTO_AACLIP_VALIDATE(*this);
+ other.validate();
+
SkTSwap(fBounds, other.fBounds);
SkTSwap(fRunHead, other.fRunHead);
}
@@ -202,13 +341,21 @@
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 @@
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 @@
}
if (lastYForRow) {
- *lastYForRow = yoff->fY;
+ *lastYForRow = fBounds.y() + yoff->fY;
}
return fRunHead->data() + yoff->fOffset;
}
@@ -296,9 +447,22 @@
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 @@
SkASSERT(row->fWidth <= fBounds.width());
}
- RunHead* finish() {
+ bool finish(SkAAClip* target) {
this->flushRow(false);
const Row* row = fRows.begin();
@@ -382,6 +546,10 @@
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 @@
row += 1;
}
- return head;
+ target->freeRuns();
+ target->fBounds = fBounds;
+ target->fRunHead = head;
+ return target->trimBounds();
}
void dump() {
@@ -419,26 +590,6 @@
}
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 @@
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 @@
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 @@
};
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 @@
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 @@
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 @@
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 @@
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::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 @@
}
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 @@
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 @@
srcRuns += srcN;
srcAA += srcN;
srcN = srcRuns[0]; // reload
+ if (0 == srcN) {
+ break;
+ }
}
if (0 == (rowN -= minN)) {
row += 2;
@@ -1105,18 +1380,27 @@
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::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);
+}
+
+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));
+}
+
+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];
+ }
+}
+
+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;
+ }
+}
+
+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 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 SkAAClipBlitter::blitMask(const SkMask& origMask, const SkIRect& clip) {
+ SkASSERT(fAAClip->getBounds().contains(clip));
+
+ if (fAAClip->quickContains(clip)) {
+ fBlitter->blitMask(origMask, clip);
+ return;
+ }
+
+ const SkMask* mask = &origMask;
+
+ // 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);
+
+ 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;
}
-///////////////////////////////////////////////////////////////////////////////
-
-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();
- }
-}
-
diff --git a/src/core/SkAAClip.h b/src/core/SkAAClip.h
index d2f5bec..5cc2a9e 100644
--- a/src/core/SkAAClip.h
+++ b/src/core/SkAAClip.h
@@ -57,6 +57,10 @@
// 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 @@
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 @@
class SkAAClipBlitter : public SkBlitter {
public:
- SkAAClipBlitter() : fRuns(NULL) {}
+ SkAAClipBlitter() : fScanlineScratch(NULL) {}
virtual ~SkAAClipBlitter();
void init(SkBlitter* blitter, const SkAAClip* aaclip) {
@@ -103,9 +114,15 @@
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();
};
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index a77d5d9..293b10f 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -66,7 +66,7 @@
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 @@
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 @@
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 @@
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::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 @@
fExternalInverse);
}
} else {
- SkRegion clip;
- clip = totalClip; // make a copy
+ SkRasterClip clip(totalClip);
do {
layer->updateMC(totalMatrix, clip, fClipStack, &clip);
if (fUseExternalMatrix) {
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index ed21f65..83ccc9e 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -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 @@
void SkDraw::drawPaint(const SkPaint& paint) const {
SkDEBUGCODE(this->validate();)
- if (fClip->isEmpty()) {
+ if (fRC->isEmpty()) {
return;
}
@@ -260,29 +261,32 @@
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
+ 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(fRC->bwRgn());
+ while (!iter.done()) {
+ CallBitmapXferProc(*fBitmap, iter.rect(), proc, procData);
+ iter.next();
+ }
return;
}
-
- SkRegion::Iterator iter(*fClip);
- while (!iter.done()) {
- CallBitmapXferProc(*fBitmap, iter.rect(), proc, procData);
- iter.next();
- }
- } 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 @@
SkCanvas::PointMode fMode;
const SkPaint* fPaint;
const SkRegion* fClip;
+ const SkRasterClip* fRC;
// computed values
SkFixed fRadius;
@@ -299,8 +304,11 @@
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_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_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 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 @@
r.fRight = x + radius;
r.fBottom = y + radius;
- SkScan::FillXRect(r, rec.fClip, blitter);
+ SkScan::FillXRect(r, *rec.fRC, blitter);
}
}
@@ -412,13 +420,13 @@
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 @@
if (0 == width) {
fMode = mode;
fPaint = &paint;
- fClip = clip;
+ fClip = NULL;
+ fRC = rc;
fRadius = SK_Fixed1 >> 1;
return true;
}
@@ -441,7 +450,8 @@
fMode = mode;
fPaint = &paint;
- fClip = clip;
+ fClip = NULL;
+ fRC = rc;
fRadius = SkScalarToFixed(SkScalarMul(width, sx)) >> 1;
return true;
}
@@ -449,9 +459,19 @@
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 @@
SkDEBUGCODE(this->validate();)
// nothing to draw
- if (fClip->isEmpty()) {
+ if (fRC->isEmpty()) {
return;
}
@@ -545,13 +565,13 @@
}
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 @@
SkDEBUGCODE(this->validate();)
// nothing to draw
- if (fClip->isEmpty()) {
+ if (fRC->isEmpty()) {
return;
}
@@ -708,7 +728,7 @@
rtype = kPath_RectType;
}
#endif
-
+
if (kPath_RectType == rtype) {
SkPath tmp;
tmp.addRect(rect);
@@ -739,13 +759,13 @@
// 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 @@
return;
}
- SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
+ SkAutoBlitterChoose blitterChooser(*fBitmap, *fMatrix, paint);
+ SkBlitter* blitter = blitterChooser.get();
- blitter->blitMaskRegion(*mask, *fClip);
+ SkAAClipBlitterWrapper wrapper;
+ const SkRegion* clipRgn;
+
+ 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 @@
SkDEBUGCODE(this->validate();)
// nothing to draw
- if (fClip->isEmpty()) {
+ if (fRC->isEmpty()) {
return;
}
@@ -932,7 +963,7 @@
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 @@
// 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 @@
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 @@
}
}
-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 @@
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 @@
return;
}
- if (clipped_out(matrix, *fClip, bitmap.width(), bitmap.height())) {
+ if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) {
return;
}
@@ -1137,31 +1176,22 @@
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);
+ 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());
+ 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());
+ 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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_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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
-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 @@
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 @@
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 @@
} 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 @@
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 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);
diff --git a/src/core/SkDrawProcs.h b/src/core/SkDrawProcs.h
index 82ee9ba..74aa9bb 100644
--- a/src/core/SkDrawProcs.h
+++ b/src/core/SkDrawProcs.h
@@ -10,12 +10,14 @@
#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;
diff --git a/src/core/SkMaskFilter.cpp b/src/core/SkMaskFilter.cpp
index 980c350..3bdca10 100644
--- a/src/core/SkMaskFilter.cpp
+++ b/src/core/SkMaskFilter.cpp
@@ -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::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 @@
}
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();
diff --git a/src/core/SkRasterClip.cpp b/src/core/SkRasterClip.cpp
index 5588dfb..9bf39fa 100644
--- a/src/core/SkRasterClip.cpp
+++ b/src/core/SkRasterClip.cpp
@@ -13,6 +13,8 @@
}
SkRasterClip::SkRasterClip(const SkRasterClip& src) {
+ AUTO_RASTERCLIP_VALIDATE(src);
+
fIsBW = src.fIsBW;
if (fIsBW) {
fBW = src.fBW;
@@ -25,7 +27,9 @@
fIsBW = true;
}
-SkRasterClip::~SkRasterClip() {}
+SkRasterClip::~SkRasterClip() {
+ AUTO_RASTERCLIP_VALIDATE(*this);
+}
bool SkRasterClip::isEmpty() const {
return fIsBW ? fBW.isEmpty() : fAA.isEmpty();
@@ -44,6 +48,8 @@
}
bool SkRasterClip::setEmpty() {
+ AUTO_RASTERCLIP_VALIDATE(*this);
+
fIsBW = true;
fBW.setEmpty();
fAA.setEmpty();
@@ -51,12 +57,16 @@
}
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::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 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 @@
}
}
-// 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 @@
return;
}
+ AUTO_RASTERCLIP_VALIDATE(*this);
+
if (this->isEmpty()) {
dst->setEmpty();
return;
@@ -174,9 +195,15 @@
}
}
+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 @@
}
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;
+ }
+}
+
diff --git a/src/core/SkRasterClip.h b/src/core/SkRasterClip.h
index 2467120..8f18270 100644
--- a/src/core/SkRasterClip.h
+++ b/src/core/SkRasterClip.h
@@ -45,6 +45,11 @@
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 @@
// 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 @@
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
diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp
index a814719..27481f8 100644
--- a/src/core/SkScalerContext.cpp
+++ b/src/core/SkScalerContext.cpp
@@ -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 @@
}
}
- 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 @@
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);
diff --git a/src/core/SkScan.cpp b/src/core/SkScan.cpp
index ce46669..cee328f 100644
--- a/src/core/SkScan.cpp
+++ b/src/core/SkScan.cpp
@@ -78,12 +78,41 @@
return;
}
- const SkAAClip* aaClip = &clip.aaRgn();
- SkRegion tmp;
- SkAAClipBlitter aaBlitter;
-
- tmp.setRect(aaClip->getBounds());
- aaBlitter.init(blitter, aaClip);
- FillIRect(r, &tmp, &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;
+ }
+
+ 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
+
diff --git a/src/core/SkScan_AntiPath.cpp b/src/core/SkScan_AntiPath.cpp
index 9497f60..fae5cb2 100644
--- a/src/core/SkScan_AntiPath.cpp
+++ b/src/core/SkScan_AntiPath.cpp
@@ -58,6 +58,7 @@
SkDEBUGCODE(int fCurrX;)
int fCurrY;
+ int fTop;
};
BaseSuperBlitter::BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
@@ -72,8 +73,14 @@
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 @@
}
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;)
}
}
diff --git a/src/core/SkScan_Antihair.cpp b/src/core/SkScan_Antihair.cpp
index 34ca47b..bb81cd6 100644
--- a/src/core/SkScan_Antihair.cpp
+++ b/src/core/SkScan_Antihair.cpp
@@ -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 @@
}
}
-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 @@
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 @@
///////////////////////////////////////////////////////////////////////////////
-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();
+ SkIRect outerBounds;
+ XRect_roundOut(xr, &outerBounds);
- 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);
- }
- }
+ 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& 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 @@
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());
+ }
+}
+
diff --git a/src/core/SkScan_Hairline.cpp b/src/core/SkScan_Hairline.cpp
index 0a0aa21..412ec03 100644
--- a/src/core/SkScan_Hairline.cpp
+++ b/src/core/SkScan_Hairline.cpp
@@ -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 @@
} 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 @@
// 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 @@
(SkScalarToFixed(rect.fRight) >> 16) + 1,
(SkScalarToFixed(rect.fBottom) >> 16) + 1);
- if (clip) {
- if (clip->quickReject(r)) {
- return;
+ 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();
}
- if (!clip->quickContains(r)) {
- blitter = clipper.apply(blitter, clip);
- }
+ blitter = clipper.apply(blitter, clipRgn);
}
int width = r.width();
@@ -238,27 +245,34 @@
#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 @@
}
}
-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 @@
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);
+ }
+}
diff --git a/src/core/SkScan_Path.cpp b/src/core/SkScan_Path.cpp
index 06f89ce..1e2105a 100644
--- a/src/core/SkScan_Path.cpp
+++ b/src/core/SkScan_Path.cpp
@@ -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 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 @@
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 @@
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);
diff --git a/src/effects/Sk2DPathEffect.cpp b/src/effects/Sk2DPathEffect.cpp
index 95f425f..ee081f1 100644
--- a/src/effects/Sk2DPathEffect.cpp
+++ b/src/effects/Sk2DPathEffect.cpp
@@ -39,12 +39,8 @@
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;
diff --git a/src/effects/SkLayerRasterizer.cpp b/src/effects/SkLayerRasterizer.cpp
index 5a7be9d..fd73ffd 100644
--- a/src/effects/SkLayerRasterizer.cpp
+++ b/src/effects/SkLayerRasterizer.cpp
@@ -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 @@
}
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 @@
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;
diff --git a/tests/FillPathTest.cpp b/tests/FillPathTest.cpp
index 8621c8e..8271851 100644
--- a/tests/FillPathTest.cpp
+++ b/tests/FillPathTest.cpp
@@ -32,12 +32,12 @@
// 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();