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