diff options
-rw-r--r-- | samplecode/SampleLineClipper.cpp | 26 | ||||
-rw-r--r-- | src/core/SkQuadClipper.cpp | 91 | ||||
-rw-r--r-- | src/core/SkQuadClipper.h | 2 |
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 |