зеркало из https://github.com/mozilla/moz-skia.git
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:
Родитель
77f0ef726f
Коммит
3a0cd7f0e8
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче