aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--samplecode/SampleLineClipper.cpp26
-rw-r--r--src/core/SkQuadClipper.cpp91
-rw-r--r--src/core/SkQuadClipper.h2
3 files changed, 105 insertions, 14 deletions
diff --git a/samplecode/SampleLineClipper.cpp b/samplecode/SampleLineClipper.cpp
index ccf4281c1b..9573810da6 100644
--- a/samplecode/SampleLineClipper.cpp
+++ b/samplecode/SampleLineClipper.cpp
@@ -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:
diff --git a/src/core/SkQuadClipper.cpp b/src/core/SkQuadClipper.cpp
index 9d76298cae..5abbe8e4b2 100644
--- a/src/core/SkQuadClipper.cpp
+++ b/src/core/SkQuadClipper.cpp
@@ -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:
diff --git a/src/core/SkQuadClipper.h b/src/core/SkQuadClipper.h
index 9f9a6d5bae..4f38b5d119 100644
--- a/src/core/SkQuadClipper.h
+++ b/src/core/SkQuadClipper.h
@@ -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