add explicit clamping after chopping w/ t to ensure we're in the clip

git-svn-id: http://skia.googlecode.com/svn/trunk@430 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@android.com 2009-11-17 19:39:51 +00:00
Родитель 77f0ef726f
Коммит 3a0cd7f0e8
3 изменённых файлов: 105 добавлений и 14 удалений

Просмотреть файл

@ -34,6 +34,23 @@ static void check_clipper(int count, const SkPoint pts[], const SkRect& clip) {
SkASSERT(pts[i].fY >= clip.fTop);
SkASSERT(pts[i].fY <= clip.fBottom);
}
if (count > 1) {
// now check that we're monotonic in Y
if (pts[0].fY > pts[count - 1].fY) {
for (int i = 1; i < count; i++) {
SkASSERT(pts[i - 1].fY >= pts[i].fY);
}
} else if (pts[0].fY < pts[count - 1].fY) {
for (int i = 1; i < count; i++) {
SkASSERT(pts[i - 1].fY <= pts[i].fY);
}
} else {
for (int i = 1; i < count; i++) {
SkASSERT(pts[i - 1].fY == pts[i].fY);
}
}
}
}
static void line_clipper(const SkPoint src[], const SkRect& clip,
@ -59,9 +76,11 @@ static void quad_clipper(const SkPoint src[], const SkRect& clip,
while ((verb = clipper.next(pts)) != SkPath::kDone_Verb) {
switch (verb) {
case SkPath::kLine_Verb:
check_clipper(2, pts, clip);
canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, p0);
break;
case SkPath::kQuad_Verb:
check_clipper(3, pts, clip);
drawQuad(canvas, pts, p0);
break;
default:
@ -84,6 +103,7 @@ enum {
};
class LineClipperView : public SkView {
int fCounter;
int fProcIndex;
SkRect fClip;
SkRandom fRand;
@ -94,16 +114,18 @@ class LineClipperView : public SkView {
fPts[i].set(fRand.nextUScalar1() * 640,
fRand.nextUScalar1() * 480);
}
fCounter += 1;
}
public:
LineClipperView() {
fProcIndex = 1;
fCounter = 0;
int x = (640 - W)/2;
int y = (480 - H)/2;
fClip.set(x, y, x + W, y + H);
this->randPts();
fProcIndex = 1;
}
protected:

Просмотреть файл

@ -17,6 +17,22 @@
#include "SkQuadClipper.h"
#include "SkGeometry.h"
static bool quick_reject(const SkRect& bounds, const SkRect& clip) {
return bounds.fTop >= clip.fBottom || bounds.fBottom <= clip.fTop;
}
static inline void clamp_le(SkScalar& value, SkScalar max) {
if (value > max) {
value = max;
}
}
static inline void clamp_ge(SkScalar& value, SkScalar min) {
if (value < min) {
value = min;
}
}
static bool chopMonoQuadAt(SkScalar c0, SkScalar c1, SkScalar c2,
SkScalar target, SkScalar* t) {
/* Solve F(t) = y where F(t) := [0](1-t)^2 + 2[1]t(1-t) + [2]t^2
@ -132,6 +148,8 @@ static void chop_quad_in_Y(SkPoint pts[3], const SkRect& clip) {
if (chopMonoQuadAtY(pts, clip.fTop, &t)) {
// take the 2nd chopped quad
SkChopQuadAt(pts, tmp, t);
clamp_ge(tmp[2].fY, clip.fTop);
clamp_ge(tmp[3].fY, clip.fTop);
pts[0] = tmp[2];
pts[1] = tmp[3];
} else {
@ -149,6 +167,8 @@ static void chop_quad_in_Y(SkPoint pts[3], const SkRect& clip) {
if (pts[2].fY > clip.fBottom) {
if (chopMonoQuadAtY(pts, clip.fBottom, &t)) {
SkChopQuadAt(pts, tmp, t);
clamp_le(tmp[1].fY, clip.fBottom);
clamp_le(tmp[2].fY, clip.fBottom);
pts[1] = tmp[1];
pts[2] = tmp[2];
} else {
@ -223,6 +243,8 @@ void SkQuadClipper2::clipMonoQuad(const SkPoint srcPts[3], const SkRect& clip) {
if (chopMonoQuadAtX(pts, clip.fLeft, &t)) {
SkChopQuadAt(pts, tmp, t);
this->appendVLine(clip.fLeft, tmp[0].fY, tmp[2].fY, reverse);
clamp_ge(tmp[2].fX, clip.fLeft);
clamp_ge(tmp[3].fX, clip.fLeft);
pts[0] = tmp[2];
pts[1] = tmp[3];
} else {
@ -236,6 +258,8 @@ void SkQuadClipper2::clipMonoQuad(const SkPoint srcPts[3], const SkRect& clip) {
if (pts[2].fX > clip.fRight) {
if (chopMonoQuadAtX(pts, clip.fRight, &t)) {
SkChopQuadAt(pts, tmp, t);
clamp_le(tmp[1].fX, clip.fRight);
clamp_le(tmp[2].fX, clip.fRight);
this->appendQuad(tmp, reverse);
this->appendVLine(clip.fRight, tmp[2].fY, tmp[4].fY, reverse);
} else {
@ -248,21 +272,14 @@ void SkQuadClipper2::clipMonoQuad(const SkPoint srcPts[3], const SkRect& clip) {
}
}
static bool quick_reject_quad(const SkPoint srcPts[3], const SkRect& clip) {
return (srcPts[0].fY <= clip.fTop &&
srcPts[1].fY <= clip.fTop &&
srcPts[2].fY <= clip.fTop)
||
(srcPts[0].fY >= clip.fBottom &&
srcPts[1].fY >= clip.fBottom &&
srcPts[2].fY >= clip.fBottom);
}
bool SkQuadClipper2::clipQuad(const SkPoint srcPts[3], const SkRect& clip) {
fCurrPoint = fPoints;
fCurrVerb = fVerbs;
if (!quick_reject_quad(srcPts, clip)) {
SkRect bounds;
bounds.set(srcPts, 3);
if (!quick_reject(bounds, clip)) {
SkPoint monoY[5];
int countY = SkChopQuadAtYExtrema(srcPts, monoY);
for (int y = 0; y <= countY; y++) {
@ -283,6 +300,38 @@ bool SkQuadClipper2::clipQuad(const SkPoint srcPts[3], const SkRect& clip) {
return SkPath::kDone_Verb != fVerbs[0];
}
///////////////////////////////////////////////////////////////////////////////
bool SkQuadClipper2::clipCubic(const SkPoint srcPts[4], const SkRect& clip) {
fCurrPoint = fPoints;
fCurrVerb = fVerbs;
SkRect bounds;
bounds.set(srcPts, 4);
if (!quick_reject(bounds, clip)) {
SkPoint monoY[5];
int countY = SkChopQuadAtYExtrema(srcPts, monoY);
for (int y = 0; y <= countY; y++) {
SkPoint monoX[5];
int countX = SkChopQuadAtXExtrema(&monoY[y * 2], monoX);
SkASSERT(countY + countX <= 3);
for (int x = 0; x <= countX; x++) {
this->clipMonoQuad(&monoX[x * 2], clip);
SkASSERT(fCurrVerb - fVerbs < kMaxVerbs);
SkASSERT(fCurrPoint - fPoints <= kMaxPoints);
}
}
}
*fCurrVerb = SkPath::kDone_Verb;
fCurrPoint = fPoints;
fCurrVerb = fVerbs;
return SkPath::kDone_Verb != fVerbs[0];
}
///////////////////////////////////////////////////////////////////////////////
void SkQuadClipper2::appendVLine(SkScalar x, SkScalar y0, SkScalar y1,
bool reverse) {
*fCurrVerb++ = SkPath::kLine_Verb;
@ -297,7 +346,7 @@ void SkQuadClipper2::appendVLine(SkScalar x, SkScalar y0, SkScalar y1,
void SkQuadClipper2::appendQuad(const SkPoint pts[3], bool reverse) {
*fCurrVerb++ = SkPath::kQuad_Verb;
if (reverse) {
fCurrPoint[0] = pts[2];
fCurrPoint[2] = pts[0];
@ -309,6 +358,19 @@ void SkQuadClipper2::appendQuad(const SkPoint pts[3], bool reverse) {
fCurrPoint += 3;
}
void SkQuadClipper2::appendCubic(const SkPoint pts[4], bool reverse) {
*fCurrVerb++ = SkPath::kCubic_Verb;
if (reverse) {
for (int i = 0; i < 4; i++) {
fCurrPoint[i] = pts[3 - i];
}
} else {
memcpy(fCurrPoint, pts, 4 * sizeof(SkPoint));
}
fCurrPoint += 4;
}
SkPath::Verb SkQuadClipper2::next(SkPoint pts[]) {
SkPath::Verb verb = *fCurrVerb;
@ -323,6 +385,11 @@ SkPath::Verb SkQuadClipper2::next(SkPoint pts[]) {
fCurrPoint += 3;
fCurrVerb += 1;
break;
case SkPath::kCubic_Verb:
memcpy(pts, fCurrPoint, 4 * sizeof(SkPoint));
fCurrPoint += 4;
fCurrVerb += 1;
break;
case SkPath::kDone_Verb:
break;
default:

Просмотреть файл

@ -44,6 +44,7 @@ private:
class SkQuadClipper2 {
public:
bool clipQuad(const SkPoint pts[3], const SkRect& clip);
bool clipCubic(const SkPoint pts[4], const SkRect& clip);
SkPath::Verb next(SkPoint pts[]);
@ -61,6 +62,7 @@ private:
void clipMonoQuad(const SkPoint srcPts[3], const SkRect& clip);
void appendVLine(SkScalar x, SkScalar y0, SkScalar y1, bool reverse);
void appendQuad(const SkPoint pts[3], bool reverse);
void appendCubic(const SkPoint pts[4], bool reverse);
};
#endif