Fix inverse scanconversion -- be sure to keep our calls to SkBlitter in scanline

order (top to bottom), since the region blitter explicitly requires this.



git-svn-id: http://skia.googlecode.com/svn/trunk@876 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@google.com 2011-03-02 15:58:18 +00:00
parent 7239aab311
commit 55b6b58d8f
4 changed files with 88 additions and 74 deletions

View File

@ -25,14 +25,14 @@ static const struct {
{ SkPaint::kStrokeAndFill_Style, SkPaint::kMiter_Join, 10 }, { SkPaint::kStrokeAndFill_Style, SkPaint::kMiter_Join, 10 },
}; };
#define TEST_INVERSE 0 #define TEST_INVERSE 1
class ComplexClipView : public SkView { class ComplexClipView : public SkView {
SkScalar fWidth; SkScalar fWidth;
public: public:
ComplexClipView() { ComplexClipView() {
} }
protected: protected:
// overrides from SkEventSink // overrides from SkEventSink
virtual bool onQuery(SkEvent* evt) { virtual bool onQuery(SkEvent* evt) {
@ -42,11 +42,11 @@ protected:
} }
return this->INHERITED::onQuery(evt); return this->INHERITED::onQuery(evt);
} }
void drawBG(SkCanvas* canvas) { void drawBG(SkCanvas* canvas) {
canvas->drawColor(SkColorSetRGB(0xA0,0xDD,0xA0)); canvas->drawColor(SkColorSetRGB(0xA0,0xDD,0xA0));
} }
virtual void onDraw(SkCanvas* canvas) { virtual void onDraw(SkCanvas* canvas) {
SkPath path; SkPath path;
path.moveTo(SkIntToScalar(0), SkIntToScalar(50)); path.moveTo(SkIntToScalar(0), SkIntToScalar(50));
@ -116,8 +116,8 @@ protected:
canvas->scale(3 * SK_Scalar1 / 4, 3 * SK_Scalar1 / 4); canvas->scale(3 * SK_Scalar1 / 4, 3 * SK_Scalar1 / 4);
canvas->save(); canvas->save();
int invALimit = TEST_INVERSE ? 1 : 2; int invALimit = TEST_INVERSE ? 2 : 1;
for (int invA = 0; invALimit < 2; ++invA) { for (int invA = 0; invA < invALimit; ++invA) {
for (int op = 0; op < SK_ARRAY_COUNT(gOps); ++op) { for (int op = 0; op < SK_ARRAY_COUNT(gOps); ++op) {
int idx = invA * SK_ARRAY_COUNT(gOps) + op; int idx = invA * SK_ARRAY_COUNT(gOps) + op;
if (!(idx % 3)) { if (!(idx % 3)) {

View File

@ -2,16 +2,16 @@
** **
** Copyright 2006, The Android Open Source Project ** Copyright 2006, The Android Open Source Project
** **
** Licensed under the Apache License, Version 2.0 (the "License"); ** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License. ** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at ** You may obtain a copy of the License at
** **
** http://www.apache.org/licenses/LICENSE-2.0 ** http://www.apache.org/licenses/LICENSE-2.0
** **
** Unless required by applicable law or agreed to in writing, software ** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS, ** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and ** See the License for the specific language governing permissions and
** limitations under the License. ** limitations under the License.
*/ */
@ -40,9 +40,9 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect,
SkBlitter* blitter, int start_y, int stop_y, int shiftEdgesUp, SkBlitter* blitter, int start_y, int stop_y, int shiftEdgesUp,
const SkRegion& clipRgn); const SkRegion& clipRgn);
// blit the rects above and below avoid, clipped to clp // blit the rects above and below avoid, clipped to clip
void sk_blit_above_and_below(SkBlitter* blitter, const SkIRect& avoid, void sk_blit_above(SkBlitter*, const SkIRect& avoid, const SkRegion& clip);
const SkRegion& clip); void sk_blit_below(SkBlitter*, const SkIRect& avoid, const SkRegion& clip);
#endif #endif

View File

@ -2,16 +2,16 @@
** **
** Copyright 2006, The Android Open Source Project ** Copyright 2006, The Android Open Source Project
** **
** Licensed under the Apache License, Version 2.0 (the "License"); ** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License. ** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at ** You may obtain a copy of the License at
** **
** http://www.apache.org/licenses/LICENSE-2.0 ** http://www.apache.org/licenses/LICENSE-2.0
** **
** Unless required by applicable law or agreed to in writing, software ** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS, ** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and ** See the License for the specific language governing permissions and
** limitations under the License. ** limitations under the License.
*/ */
@ -56,12 +56,12 @@ protected:
BaseSuperBlitter::BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir, BaseSuperBlitter::BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
const SkRegion& clip) { const SkRegion& clip) {
fRealBlitter = realBlitter; fRealBlitter = realBlitter;
// take the union of the ir bounds and clip, since we may be called with an // take the union of the ir bounds and clip, since we may be called with an
// inverse filltype // inverse filltype
const int left = SkMin32(ir.fLeft, clip.getBounds().fLeft); const int left = SkMin32(ir.fLeft, clip.getBounds().fLeft);
const int right = SkMax32(ir.fRight, clip.getBounds().fRight); const int right = SkMax32(ir.fRight, clip.getBounds().fRight);
fLeft = left; fLeft = left;
fSuperLeft = left << SHIFT; fSuperLeft = left << SHIFT;
fWidth = right - left; fWidth = right - left;
@ -153,7 +153,7 @@ void SuperBlitter::blitH(int x, int y, int width)
// int maxValue = (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT); // int maxValue = (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT);
#if 0 #if 0
SkAntiRun<SHIFT> arun; SkAntiRun<SHIFT> arun;
arun.set(x, x + width); arun.set(x, x + width);
fRuns.add(x >> SHIFT, arun.getStartAlpha(), arun.getMiddleCount(), arun.getStopAlpha(), maxValue); fRuns.add(x >> SHIFT, arun.getStartAlpha(), arun.getMiddleCount(), arun.getStopAlpha(), maxValue);
#else #else
@ -215,11 +215,11 @@ public:
{ {
int width = bounds.width(); int width = bounds.width();
int rb = SkAlign4(width); int rb = SkAlign4(width);
return (width <= MaskSuperBlitter::kMAX_WIDTH) && return (width <= MaskSuperBlitter::kMAX_WIDTH) &&
(rb * bounds.height() <= MaskSuperBlitter::kMAX_STORAGE); (rb * bounds.height() <= MaskSuperBlitter::kMAX_STORAGE);
} }
private: private:
enum { enum {
kMAX_WIDTH = 32, // so we don't try to do very wide things, where the RLE blitter would be faster kMAX_WIDTH = 32, // so we don't try to do very wide things, where the RLE blitter would be faster
@ -242,10 +242,10 @@ MaskSuperBlitter::MaskSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
fMask.fBounds = ir; fMask.fBounds = ir;
fMask.fRowBytes = ir.width(); fMask.fRowBytes = ir.width();
fMask.fFormat = SkMask::kA8_Format; fMask.fFormat = SkMask::kA8_Format;
fClipRect = ir; fClipRect = ir;
fClipRect.intersect(clip.getBounds()); fClipRect.intersect(clip.getBounds());
// For valgrind, write 1 extra byte at the end so we don't read // For valgrind, write 1 extra byte at the end so we don't read
// uninitialized memory. See comment in add_aa_span and fStorage[]. // uninitialized memory. See comment in add_aa_span and fStorage[].
memset(fStorage, 0, fMask.fBounds.height() * fMask.fRowBytes + 1); memset(fStorage, 0, fMask.fBounds.height() * fMask.fRowBytes + 1);
@ -292,7 +292,7 @@ static void add_aa_span(uint8_t* alpha, U8CPU startAlpha, int middleCount, U8CPU
void MaskSuperBlitter::blitH(int x, int y, int width) void MaskSuperBlitter::blitH(int x, int y, int width)
{ {
int iy = (y >> SHIFT); int iy = (y >> SHIFT);
SkASSERT(iy >= fMask.fBounds.fTop && iy < fMask.fBounds.fBottom); SkASSERT(iy >= fMask.fBounds.fTop && iy < fMask.fBounds.fBottom);
iy -= fMask.fBounds.fTop; // make it relative to 0 iy -= fMask.fBounds.fTop; // make it relative to 0
@ -309,7 +309,7 @@ void MaskSuperBlitter::blitH(int x, int y, int width)
SkASSERT(ix >= fMask.fBounds.fLeft && ix < fMask.fBounds.fRight); SkASSERT(ix >= fMask.fBounds.fLeft && ix < fMask.fBounds.fRight);
} }
#endif #endif
x -= (fMask.fBounds.fLeft << SHIFT); x -= (fMask.fBounds.fLeft << SHIFT);
// hack, until I figure out why my cubics (I think) go beyond the bounds // hack, until I figure out why my cubics (I think) go beyond the bounds
@ -397,12 +397,12 @@ void SkScan::AntiFillPath(const SkPath& path, const SkRegion& clip,
} }
return; return;
} }
// now use the (possibly wrapped) blitter // now use the (possibly wrapped) blitter
blitter = clipper.getBlitter(); blitter = clipper.getBlitter();
if (path.isInverseFillType()) { if (path.isInverseFillType()) {
sk_blit_above_and_below(blitter, ir, clip); sk_blit_above(blitter, ir, clip);
} }
SkIRect superRect, *superClipRect = NULL; SkIRect superRect, *superClipRect = NULL;
@ -429,4 +429,8 @@ void SkScan::AntiFillPath(const SkPath& path, const SkRegion& clip,
SuperBlitter superBlit(blitter, ir, clip); SuperBlitter superBlit(blitter, ir, clip);
sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, clip); sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, clip);
} }
if (path.isInverseFillType()) {
sk_blit_below(blitter, ir, clip);
}
} }

View File

@ -2,16 +2,16 @@
** **
** Copyright 2006, The Android Open Source Project ** Copyright 2006, The Android Open Source Project
** **
** Licensed under the Apache License, Version 2.0 (the "License"); ** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License. ** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at ** You may obtain a copy of the License at
** **
** http://www.apache.org/licenses/LICENSE-2.0 ** http://www.apache.org/licenses/LICENSE-2.0
** **
** Unless required by applicable law or agreed to in writing, software ** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS, ** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and ** See the License for the specific language governing permissions and
** limitations under the License. ** limitations under the License.
*/ */
@ -75,7 +75,7 @@ static void backward_insert_edge_based_on_x(SkEdge* edge SkDECLAREPARAM(int, cur
for (;;) for (;;)
{ {
SkEdge* prev = edge->fPrev; SkEdge* prev = edge->fPrev;
// add 1 to curr_y since we may have added new edges (built from curves) // add 1 to curr_y since we may have added new edges (built from curves)
// that start on the next scanline // that start on the next scanline
SkASSERT(prev && prev->fFirstY <= curr_y + 1); SkASSERT(prev && prev->fFirstY <= curr_y + 1);
@ -145,11 +145,11 @@ static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
SkFixed prevX = prevHead->fX; SkFixed prevX = prevHead->fX;
validate_edges_for_y(currE, curr_y); validate_edges_for_y(currE, curr_y);
if (proc) { if (proc) {
proc(blitter, curr_y, PREPOST_START); // pre-proc proc(blitter, curr_y, PREPOST_START); // pre-proc
} }
while (currE->fFirstY <= curr_y) while (currE->fFirstY <= curr_y)
{ {
SkASSERT(currE->fLastY >= curr_y); SkASSERT(currE->fLastY >= curr_y);
@ -181,7 +181,7 @@ static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
if (((SkCubicEdge*)currE)->updateCubic()) if (((SkCubicEdge*)currE)->updateCubic())
{ {
SkASSERT(currE->fFirstY == curr_y + 1); SkASSERT(currE->fFirstY == curr_y + 1);
newX = currE->fX; newX = currE->fX;
goto NEXT_X; goto NEXT_X;
} }
@ -210,7 +210,7 @@ static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
currE = next; currE = next;
SkASSERT(currE); SkASSERT(currE);
} }
if (proc) { if (proc) {
proc(blitter, curr_y, PREPOST_END); // post-proc proc(blitter, curr_y, PREPOST_END); // post-proc
} }
@ -257,7 +257,7 @@ public:
} }
fPrevX = x + width; fPrevX = x + width;
} }
// we do not expect to get called with these entrypoints // we do not expect to get called with these entrypoints
virtual void blitAntiH(int, int, const SkAlpha[], const int16_t runs[]) { virtual void blitAntiH(int, int, const SkAlpha[], const int16_t runs[]) {
SkASSERT(!"blitAntiH unexpected"); SkASSERT(!"blitAntiH unexpected");
@ -275,7 +275,7 @@ public:
SkASSERT(!"justAnOpaqueColor unexpected"); SkASSERT(!"justAnOpaqueColor unexpected");
return NULL; return NULL;
} }
private: private:
SkBlitter* fBlitter; SkBlitter* fBlitter;
int fFirstX, fLastX, fPrevX; int fFirstX, fLastX, fPrevX;
@ -313,7 +313,7 @@ static int build_edges(SkEdge edge[], const SkPath& path,
SkPath::Iter iter(path, true); SkPath::Iter iter(path, true);
SkPoint pts[4]; SkPoint pts[4];
SkPath::Verb verb; SkPath::Verb verb;
SkQuadClipper qclipper; SkQuadClipper qclipper;
if (clipRect) { if (clipRect) {
SkIRect r; SkIRect r;
@ -355,7 +355,7 @@ static int build_edges(SkEdge edge[], const SkPath& path,
case SkPath::kCubic_Verb: { case SkPath::kCubic_Verb: {
SkPoint tmp[10]; SkPoint tmp[10];
SkPoint* p = tmp; SkPoint* p = tmp;
int count = SkChopCubicAtYExtrema(pts, tmp); int count = SkChopCubicAtYExtrema(pts, tmp);
SkASSERT(count >= 0 && count <= 2); SkASSERT(count >= 0 && count <= 2);
do { do {
@ -417,7 +417,7 @@ static int worst_case_edge_count(const SkPath& path, size_t* storage)
*/ */
static int cheap_worst_case_edge_count(const SkPath& path, size_t* storage) { static int cheap_worst_case_edge_count(const SkPath& path, size_t* storage) {
int ptCount = path.getPoints(NULL, 0); int ptCount = path.getPoints(NULL, 0);
// worst case is curve, close, curve, close, as that is // worst case is curve, close, curve, close, as that is
// 2 lines per pt, or : pts * 2 // 2 lines per pt, or : pts * 2
// 2 quads + 1 line per 2 pts, or : pts * 3 / 2 // 2 quads + 1 line per 2 pts, or : pts * 3 / 2
// 3 cubics + 1 line per 3 pts : pts * 4 / 3 // 3 cubics + 1 line per 3 pts : pts * 4 / 3
@ -442,15 +442,15 @@ extern "C" {
static int edge_compare(const void* a, const void* b) { static int edge_compare(const void* a, const void* b) {
const SkEdge* edgea = *(const SkEdge**)a; const SkEdge* edgea = *(const SkEdge**)a;
const SkEdge* edgeb = *(const SkEdge**)b; const SkEdge* edgeb = *(const SkEdge**)b;
int valuea = edgea->fFirstY; int valuea = edgea->fFirstY;
int valueb = edgeb->fFirstY; int valueb = edgeb->fFirstY;
if (valuea == valueb) { if (valuea == valueb) {
valuea = edgea->fX; valuea = edgea->fX;
valueb = edgeb->fX; valueb = edgeb->fX;
} }
// this overflows if valuea >>> valueb or vice-versa // this overflows if valuea >>> valueb or vice-versa
// return valuea - valueb; // return valuea - valueb;
// do perform the slower but safe compares // do perform the slower but safe compares
@ -460,13 +460,13 @@ extern "C" {
static SkEdge* sort_edges(SkEdge* list[], int count, SkEdge** last) { static SkEdge* sort_edges(SkEdge* list[], int count, SkEdge** last) {
qsort(list, count, sizeof(SkEdge*), edge_compare); qsort(list, count, sizeof(SkEdge*), edge_compare);
// now make the edges linked in sorted order // now make the edges linked in sorted order
for (int i = 1; i < count; i++) { for (int i = 1; i < count; i++) {
list[i - 1]->fNext = list[i]; list[i - 1]->fNext = list[i];
list[i]->fPrev = list[i - 1]; list[i]->fPrev = list[i - 1];
} }
*last = list[count - 1]; *last = list[count - 1];
return list[0]; return list[0];
} }
@ -483,7 +483,7 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte
#ifdef USE_NEW_BUILDER #ifdef USE_NEW_BUILDER
SkEdgeBuilder builder; SkEdgeBuilder builder;
int count = builder.build(path, clipRect, shiftEdgesUp); int count = builder.build(path, clipRect, shiftEdgesUp);
SkEdge** list = builder.edgeList(); SkEdge** list = builder.edgeList();
#else #else
@ -494,7 +494,7 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte
{ {
size_t size2; size_t size2;
int maxCount2 = worst_case_edge_count(path, &size2); int maxCount2 = worst_case_edge_count(path, &size2);
SkASSERT(maxCount >= maxCount2 && size >= size2); SkASSERT(maxCount >= maxCount2 && size >= size2);
} }
#endif #endif
@ -557,20 +557,25 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte
walk_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, proc); walk_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, proc);
} }
void sk_blit_above_and_below(SkBlitter* blitter, const SkIRect& ir, void sk_blit_above(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip) {
const SkRegion& clip) {
const SkIRect& cr = clip.getBounds(); const SkIRect& cr = clip.getBounds();
SkIRect tmp; SkIRect tmp;
tmp.fLeft = cr.fLeft; tmp.fLeft = cr.fLeft;
tmp.fRight = cr.fRight; tmp.fRight = cr.fRight;
tmp.fTop = cr.fTop; tmp.fTop = cr.fTop;
tmp.fBottom = ir.fTop; tmp.fBottom = ir.fTop;
if (!tmp.isEmpty()) { if (!tmp.isEmpty()) {
blitter->blitRectRegion(tmp, clip); blitter->blitRectRegion(tmp, clip);
} }
}
void sk_blit_below(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip) {
const SkIRect& cr = clip.getBounds();
SkIRect tmp;
tmp.fLeft = cr.fLeft;
tmp.fRight = cr.fRight;
tmp.fTop = ir.fBottom; tmp.fTop = ir.fBottom;
tmp.fBottom = cr.fBottom; tmp.fBottom = cr.fBottom;
if (!tmp.isEmpty()) { if (!tmp.isEmpty()) {
@ -635,10 +640,15 @@ void SkScan::FillPath(const SkPath& path, const SkRegion& clip,
blitter = clipper.getBlitter(); blitter = clipper.getBlitter();
if (blitter) { if (blitter) {
// we have to keep our calls to blitter in sorted order, so we
// must blit the above section first, then the middle, then the bottom.
if (path.isInverseFillType()) { if (path.isInverseFillType()) {
sk_blit_above_and_below(blitter, ir, clip); sk_blit_above(blitter, ir, clip);
} }
sk_fill_path(path, clipper.getClipRect(), blitter, ir.fTop, ir.fBottom, 0, clip); sk_fill_path(path, clipper.getClipRect(), blitter, ir.fTop, ir.fBottom, 0, clip);
if (path.isInverseFillType()) {
sk_blit_below(blitter, ir, clip);
}
} else { } else {
// what does it mean to not have a blitter if path.isInverseFillType??? // what does it mean to not have a blitter if path.isInverseFillType???
} }
@ -649,7 +659,7 @@ void SkScan::FillPath(const SkPath& path, const SkRegion& clip,
static int build_tri_edges(SkEdge edge[], const SkPoint pts[], static int build_tri_edges(SkEdge edge[], const SkPoint pts[],
const SkIRect* clipRect, SkEdge* list[]) { const SkIRect* clipRect, SkEdge* list[]) {
SkEdge** start = list; SkEdge** start = list;
if (edge->setLine(pts[0], pts[1], clipRect, 0)) { if (edge->setLine(pts[0], pts[1], clipRect, 0)) {
*list++ = edge; *list++ = edge;
edge = (SkEdge*)((char*)edge + sizeof(SkEdge)); edge = (SkEdge*)((char*)edge + sizeof(SkEdge));
@ -668,7 +678,7 @@ static int build_tri_edges(SkEdge edge[], const SkPoint pts[],
static void sk_fill_triangle(const SkPoint pts[], const SkIRect* clipRect, static void sk_fill_triangle(const SkPoint pts[], const SkIRect* clipRect,
SkBlitter* blitter, const SkIRect& ir) { SkBlitter* blitter, const SkIRect& ir) {
SkASSERT(pts && blitter); SkASSERT(pts && blitter);
SkEdge edgeStorage[3]; SkEdge edgeStorage[3];
SkEdge* list[3]; SkEdge* list[3];
@ -681,18 +691,18 @@ static void sk_fill_triangle(const SkPoint pts[], const SkIRect* clipRect,
// this returns the first and last edge after they're sorted into a dlink list // this returns the first and last edge after they're sorted into a dlink list
SkEdge* edge = sort_edges(list, count, &last); SkEdge* edge = sort_edges(list, count, &last);
headEdge.fPrev = NULL; headEdge.fPrev = NULL;
headEdge.fNext = edge; headEdge.fNext = edge;
headEdge.fFirstY = kEDGE_HEAD_Y; headEdge.fFirstY = kEDGE_HEAD_Y;
headEdge.fX = SK_MinS32; headEdge.fX = SK_MinS32;
edge->fPrev = &headEdge; edge->fPrev = &headEdge;
tailEdge.fPrev = last; tailEdge.fPrev = last;
tailEdge.fNext = NULL; tailEdge.fNext = NULL;
tailEdge.fFirstY = kEDGE_TAIL_Y; tailEdge.fFirstY = kEDGE_TAIL_Y;
last->fNext = &tailEdge; last->fNext = &tailEdge;
// now edge is the head of the sorted linklist // now edge is the head of the sorted linklist
int stop_y = ir.fBottom; int stop_y = ir.fBottom;
if (clipRect && stop_y > clipRect->fBottom) { if (clipRect && stop_y > clipRect->fBottom) {
@ -710,7 +720,7 @@ void SkScan::FillTriangle(const SkPoint pts[], const SkRegion* clip,
if (clip && clip->isEmpty()) { if (clip && clip->isEmpty()) {
return; return;
} }
SkRect r; SkRect r;
SkIRect ir; SkIRect ir;
r.set(pts, 3); r.set(pts, 3);
@ -718,9 +728,9 @@ void SkScan::FillTriangle(const SkPoint pts[], const SkRegion* clip,
if (ir.isEmpty()) { if (ir.isEmpty()) {
return; return;
} }
SkScanClipper clipper(blitter, clip, ir); SkScanClipper clipper(blitter, clip, ir);
blitter = clipper.getBlitter(); blitter = clipper.getBlitter();
if (NULL != blitter) { if (NULL != blitter) {
sk_fill_triangle(pts, clipper.getClipRect(), blitter, ir); sk_fill_triangle(pts, clipper.getClipRect(), blitter, ir);