fix winding bug in lineclipper

expose path.dump() all the time
UP arrow now toggles a grid of clip rects in sample app



git-svn-id: http://skia.googlecode.com/svn/trunk@443 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@android.com 2009-11-23 20:10:41 +00:00
parent 90209caa68
commit e522ca5d5f
5 changed files with 72 additions and 33 deletions

View File

@ -547,11 +547,8 @@ public:
Verb autoClose(SkPoint pts[2]); Verb autoClose(SkPoint pts[2]);
}; };
#ifdef SK_DEBUG
/** @cond UNIT_TEST */
void dump(bool forceClose, const char title[] = NULL) const; void dump(bool forceClose, const char title[] = NULL) const;
/** @endcond */ void dump() const;
#endif
void flatten(SkFlattenableWriteBuffer&) const; void flatten(SkFlattenableWriteBuffer&) const;
void unflatten(SkFlattenableReadBuffer&); void unflatten(SkFlattenableReadBuffer&);

View File

@ -96,7 +96,8 @@ public:
void offset(SkScalar dx, SkScalar dy); void offset(SkScalar dx, SkScalar dy);
/** Call this to have the view draw into the specified canvas. */ /** Call this to have the view draw into the specified canvas. */
void draw(SkCanvas* canvas); virtual void draw(SkCanvas* canvas);
/** Call this to invalidate part of all of a view, requesting that the view's /** Call this to invalidate part of all of a view, requesting that the view's
draw method be called. The rectangle parameter specifies the part of the view draw method be called. The rectangle parameter specifies the part of the view
that should be redrawn. If it is null, it specifies the entire view bounds. that should be redrawn. If it is null, it specifies the entire view bounds.

View File

@ -129,6 +129,8 @@ public:
SampleWindow(void* hwnd); SampleWindow(void* hwnd);
virtual ~SampleWindow(); virtual ~SampleWindow();
virtual void draw(SkCanvas* canvas);
protected: protected:
virtual void onDraw(SkCanvas* canvas); virtual void onDraw(SkCanvas* canvas);
virtual bool onHandleKey(SkKey key); virtual bool onHandleKey(SkKey key);
@ -167,6 +169,7 @@ private:
CanvasType fCanvasType; CanvasType fCanvasType;
bool fUseClip; bool fUseClip;
bool fNClip;
bool fRepeatDrawing; bool fRepeatDrawing;
bool fAnimating; bool fAnimating;
bool fRotate; bool fRotate;
@ -210,6 +213,7 @@ SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) {
fCanvasType = kRaster_CanvasType; fCanvasType = kRaster_CanvasType;
fUseClip = false; fUseClip = false;
fNClip = false;
fRepeatDrawing = false; fRepeatDrawing = false;
fAnimating = false; fAnimating = false;
fRotate = false; fRotate = false;
@ -237,6 +241,33 @@ SampleWindow::~SampleWindow() {
delete fGLCanvas; delete fGLCanvas;
} }
#define XCLIP_N 4
#define YCLIP_N 1
void SampleWindow::draw(SkCanvas* canvas) {
if (fNClip) {
// this->INHERITED::draw(canvas);
// SkBitmap orig = capture_bitmap(canvas);
const SkScalar w = this->width();
const SkScalar h = this->height();
const SkScalar cw = w / XCLIP_N;
const SkScalar ch = h / YCLIP_N;
for (int y = 0; y < YCLIP_N; y++) {
for (int x = 0; x < XCLIP_N; x++) {
SkAutoCanvasRestore acr(canvas, true);
SkRect r = {
x * cw, y * ch, (x + 1) * cw, (y + 1) * ch
};
canvas->clipRect(r);
this->INHERITED::draw(canvas);
}
}
} else {
this->INHERITED::draw(canvas);
}
}
void SampleWindow::onDraw(SkCanvas* canvas) { void SampleWindow::onDraw(SkCanvas* canvas) {
if (fRepeatDrawing) { if (fRepeatDrawing) {
this->inval(NULL); this->inval(NULL);
@ -511,7 +542,7 @@ bool SampleWindow::onHandleKey(SkKey key) {
this->inval(NULL); this->inval(NULL);
return true; return true;
case kUp_SkKey: case kUp_SkKey:
fUseClip = !fUseClip; fNClip = !fNClip;
this->updateTitle(); this->updateTitle();
this->inval(NULL); this->inval(NULL);
return true; return true;
@ -604,7 +635,9 @@ void SampleWindow::updateTitle() {
if (fRotate) { if (fRotate) {
title.prepend("<R> "); title.prepend("<R> ");
} }
if (fNClip) {
title.prepend("<C> ");
}
this->setTitle(title.c_str()); this->setTitle(title.c_str());
} }

View File

@ -124,21 +124,26 @@ int SkLineClipper::ClipLine(const SkPoint pts[], const SkRect& clip,
SkPoint resultStorage[kMaxPoints]; SkPoint resultStorage[kMaxPoints];
SkPoint* result; // points to our results, either tmp or resultStorage SkPoint* result; // points to our results, either tmp or resultStorage
int lineCount = 1; int lineCount = 1;
bool reverse;
if (pts[0].fX < pts[1].fX) { if (pts[0].fX < pts[1].fX) {
index0 = 0; index0 = 0;
index1 = 1; index1 = 1;
reverse = false;
} else { } else {
index0 = 1; index0 = 1;
index1 = 0; index1 = 0;
reverse = true;
} }
if (tmp[index1].fX <= clip.fLeft) { // wholly to the left if (tmp[index1].fX <= clip.fLeft) { // wholly to the left
tmp[0].fX = tmp[1].fX = clip.fLeft; tmp[0].fX = tmp[1].fX = clip.fLeft;
result = tmp; result = tmp;
reverse = false;
} else if (tmp[index0].fX >= clip.fRight) { // wholly to the right } else if (tmp[index0].fX >= clip.fRight) { // wholly to the right
tmp[0].fX = tmp[1].fX = clip.fRight; tmp[0].fX = tmp[1].fX = clip.fRight;
result = tmp; result = tmp;
reverse = false;
} else { } else {
result = resultStorage; result = resultStorage;
SkPoint* r = result; SkPoint* r = result;
@ -164,7 +169,7 @@ int SkLineClipper::ClipLine(const SkPoint pts[], const SkRect& clip,
} }
// Now copy the results into the caller's lines[] parameter // Now copy the results into the caller's lines[] parameter
if (0 == index1) { if (reverse) {
// copy the pts in reverse order to maintain winding order // copy the pts in reverse order to maintain winding order
for (int i = 0; i <= lineCount; i++) { for (int i = 0; i <= lineCount; i++) {
lines[lineCount - i] = result[i]; lines[lineCount - i] = result[i];

View File

@ -1222,30 +1222,6 @@ void SkPath::unflatten(SkFlattenableReadBuffer& buffer) {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#ifdef SK_DEBUG
void SkPath::validate() const {
SkASSERT(this != NULL);
SkASSERT((fFillType & ~3) == 0);
fPts.validate();
fVerbs.validate();
if (!fBoundsIsDirty) {
SkRect bounds;
compute_pt_bounds(&bounds, fPts);
if (fPts.count() <= 1) {
// if we're empty, fBounds may be empty but translated, so we can't
// necessarily compare to bounds directly
// try path.addOval(2, 2, 2, 2) which is empty, but the bounds will
// be [2, 2, 2, 2]
SkASSERT(bounds.isEmpty());
SkASSERT(fBounds.isEmpty());
} else {
fBounds.contains(bounds);
}
}
}
void SkPath::dump(bool forceClose, const char title[]) const { void SkPath::dump(bool forceClose, const char title[]) const {
Iter iter(*this, forceClose); Iter iter(*this, forceClose);
SkPoint pts[4]; SkPoint pts[4];
@ -1306,4 +1282,31 @@ void SkPath::dump(bool forceClose, const char title[]) const {
SkDebugf("path: done %s\n", title ? title : ""); SkDebugf("path: done %s\n", title ? title : "");
} }
void SkPath::dump() const {
this->dump(false);
}
#ifdef SK_DEBUG
void SkPath::validate() const {
SkASSERT(this != NULL);
SkASSERT((fFillType & ~3) == 0);
fPts.validate();
fVerbs.validate();
if (!fBoundsIsDirty) {
SkRect bounds;
compute_pt_bounds(&bounds, fPts);
if (fPts.count() <= 1) {
// if we're empty, fBounds may be empty but translated, so we can't
// necessarily compare to bounds directly
// try path.addOval(2, 2, 2, 2) which is empty, but the bounds will
// be [2, 2, 2, 2]
SkASSERT(bounds.isEmpty());
SkASSERT(fBounds.isEmpty());
} else {
fBounds.contains(bounds);
}
}
}
#endif #endif