Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2006 The Android Open Source Project
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkScanPriv.h"
      9 #include "SkBlitter.h"
     10 #include "SkEdge.h"
     11 #include "SkEdgeBuilder.h"
     12 #include "SkGeometry.h"
     13 #include "SkPath.h"
     14 #include "SkQuadClipper.h"
     15 #include "SkRasterClip.h"
     16 #include "SkRegion.h"
     17 #include "SkTemplates.h"
     18 #include "SkTSort.h"
     19 
     20 #define kEDGE_HEAD_Y    SK_MinS32
     21 #define kEDGE_TAIL_Y    SK_MaxS32
     22 
     23 #ifdef SK_DEBUG
     24     static void validate_sort(const SkEdge* edge) {
     25         int y = kEDGE_HEAD_Y;
     26 
     27         while (edge->fFirstY != SK_MaxS32) {
     28             edge->validate();
     29             SkASSERT(y <= edge->fFirstY);
     30 
     31             y = edge->fFirstY;
     32             edge = edge->fNext;
     33         }
     34     }
     35 #else
     36     #define validate_sort(edge)
     37 #endif
     38 
     39 static inline void remove_edge(SkEdge* edge) {
     40     edge->fPrev->fNext = edge->fNext;
     41     edge->fNext->fPrev = edge->fPrev;
     42 }
     43 
     44 static inline void insert_edge_after(SkEdge* edge, SkEdge* afterMe) {
     45     edge->fPrev = afterMe;
     46     edge->fNext = afterMe->fNext;
     47     afterMe->fNext->fPrev = edge;
     48     afterMe->fNext = edge;
     49 }
     50 
     51 static void backward_insert_edge_based_on_x(SkEdge* edge SkDECLAREPARAM(int, curr_y)) {
     52     SkFixed x = edge->fX;
     53 
     54     SkEdge* prev = edge->fPrev;
     55     while (prev->fX > x) {
     56         prev = prev->fPrev;
     57     }
     58     if (prev->fNext != edge) {
     59         remove_edge(edge);
     60         insert_edge_after(edge, prev);
     61     }
     62 }
     63 
     64 static void insert_new_edges(SkEdge* newEdge, int curr_y) {
     65     SkASSERT(newEdge->fFirstY >= curr_y);
     66 
     67     while (newEdge->fFirstY == curr_y) {
     68         SkEdge* next = newEdge->fNext;
     69         backward_insert_edge_based_on_x(newEdge  SkPARAM(curr_y));
     70         newEdge = next;
     71     }
     72 }
     73 
     74 #ifdef SK_DEBUG
     75 static void validate_edges_for_y(const SkEdge* edge, int curr_y) {
     76     while (edge->fFirstY <= curr_y) {
     77         SkASSERT(edge->fPrev && edge->fNext);
     78         SkASSERT(edge->fPrev->fNext == edge);
     79         SkASSERT(edge->fNext->fPrev == edge);
     80         SkASSERT(edge->fFirstY <= edge->fLastY);
     81 
     82         SkASSERT(edge->fPrev->fX <= edge->fX);
     83         edge = edge->fNext;
     84     }
     85 }
     86 #else
     87     #define validate_edges_for_y(edge, curr_y)
     88 #endif
     89 
     90 #if defined _WIN32 && _MSC_VER >= 1300  // disable warning : local variable used without having been initialized
     91 #pragma warning ( push )
     92 #pragma warning ( disable : 4701 )
     93 #endif
     94 
     95 typedef void (*PrePostProc)(SkBlitter* blitter, int y, bool isStartOfScanline);
     96 #define PREPOST_START   true
     97 #define PREPOST_END     false
     98 
     99 static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
    100                        SkBlitter* blitter, int start_y, int stop_y,
    101                        PrePostProc proc, int rightClip) {
    102     validate_sort(prevHead->fNext);
    103 
    104     int curr_y = start_y;
    105     // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
    106     int windingMask = (fillType & 1) ? 1 : -1;
    107 
    108     for (;;) {
    109         int     w = 0;
    110         int     left SK_INIT_TO_AVOID_WARNING;
    111         bool    in_interval = false;
    112         SkEdge* currE = prevHead->fNext;
    113         SkFixed prevX = prevHead->fX;
    114 
    115         validate_edges_for_y(currE, curr_y);
    116 
    117         if (proc) {
    118             proc(blitter, curr_y, PREPOST_START);    // pre-proc
    119         }
    120 
    121         while (currE->fFirstY <= curr_y) {
    122             SkASSERT(currE->fLastY >= curr_y);
    123 
    124             int x = SkFixedRoundToInt(currE->fX);
    125             w += currE->fWinding;
    126             if ((w & windingMask) == 0) { // we finished an interval
    127                 SkASSERT(in_interval);
    128                 int width = x - left;
    129                 SkASSERT(width >= 0);
    130                 if (width)
    131                     blitter->blitH(left, curr_y, width);
    132                 in_interval = false;
    133             } else if (!in_interval) {
    134                 left = x;
    135                 in_interval = true;
    136             }
    137 
    138             SkEdge* next = currE->fNext;
    139             SkFixed newX;
    140 
    141             if (currE->fLastY == curr_y) {    // are we done with this edge?
    142                 if (currE->fCurveCount < 0) {
    143                     if (((SkCubicEdge*)currE)->updateCubic()) {
    144                         SkASSERT(currE->fFirstY == curr_y + 1);
    145 
    146                         newX = currE->fX;
    147                         goto NEXT_X;
    148                     }
    149                 } else if (currE->fCurveCount > 0) {
    150                     if (((SkQuadraticEdge*)currE)->updateQuadratic()) {
    151                         newX = currE->fX;
    152                         goto NEXT_X;
    153                     }
    154                 }
    155                 remove_edge(currE);
    156             } else {
    157                 SkASSERT(currE->fLastY > curr_y);
    158                 newX = currE->fX + currE->fDX;
    159                 currE->fX = newX;
    160             NEXT_X:
    161                 if (newX < prevX) { // ripple currE backwards until it is x-sorted
    162                     backward_insert_edge_based_on_x(currE  SkPARAM(curr_y));
    163                 } else {
    164                     prevX = newX;
    165                 }
    166             }
    167             currE = next;
    168             SkASSERT(currE);
    169         }
    170 
    171         // was our right-edge culled away?
    172         if (in_interval) {
    173             int width = rightClip - left;
    174             if (width > 0) {
    175                 blitter->blitH(left, curr_y, width);
    176             }
    177         }
    178 
    179         if (proc) {
    180             proc(blitter, curr_y, PREPOST_END);    // post-proc
    181         }
    182 
    183         curr_y += 1;
    184         if (curr_y >= stop_y) {
    185             break;
    186         }
    187         // now currE points to the first edge with a Yint larger than curr_y
    188         insert_new_edges(currE, curr_y);
    189     }
    190 }
    191 
    192 // return true if we're done with this edge
    193 static bool update_edge(SkEdge* edge, int last_y) {
    194     SkASSERT(edge->fLastY >= last_y);
    195     if (last_y == edge->fLastY) {
    196         if (edge->fCurveCount < 0) {
    197             if (((SkCubicEdge*)edge)->updateCubic()) {
    198                 SkASSERT(edge->fFirstY == last_y + 1);
    199                 return false;
    200             }
    201         } else if (edge->fCurveCount > 0) {
    202             if (((SkQuadraticEdge*)edge)->updateQuadratic()) {
    203                 SkASSERT(edge->fFirstY == last_y + 1);
    204                 return false;
    205             }
    206         }
    207         return true;
    208     }
    209     return false;
    210 }
    211 
    212 static void walk_convex_edges(SkEdge* prevHead, SkPath::FillType,
    213                               SkBlitter* blitter, int start_y, int stop_y,
    214                               PrePostProc proc) {
    215     validate_sort(prevHead->fNext);
    216 
    217     SkEdge* leftE = prevHead->fNext;
    218     SkEdge* riteE = leftE->fNext;
    219     SkEdge* currE = riteE->fNext;
    220 
    221 #if 0
    222     int local_top = leftE->fFirstY;
    223     SkASSERT(local_top == riteE->fFirstY);
    224 #else
    225     // our edge choppers for curves can result in the initial edges
    226     // not lining up, so we take the max.
    227     int local_top = SkMax32(leftE->fFirstY, riteE->fFirstY);
    228 #endif
    229     SkASSERT(local_top >= start_y);
    230 
    231     for (;;) {
    232         SkASSERT(leftE->fFirstY <= stop_y);
    233         SkASSERT(riteE->fFirstY <= stop_y);
    234 
    235         if (leftE->fX > riteE->fX || (leftE->fX == riteE->fX &&
    236                                       leftE->fDX > riteE->fDX)) {
    237             SkTSwap(leftE, riteE);
    238         }
    239 
    240         int local_bot = SkMin32(leftE->fLastY, riteE->fLastY);
    241         local_bot = SkMin32(local_bot, stop_y - 1);
    242         SkASSERT(local_top <= local_bot);
    243 
    244         SkFixed left = leftE->fX;
    245         SkFixed dLeft = leftE->fDX;
    246         SkFixed rite = riteE->fX;
    247         SkFixed dRite = riteE->fDX;
    248         int count = local_bot - local_top;
    249         SkASSERT(count >= 0);
    250         if (0 == (dLeft | dRite)) {
    251             int L = SkFixedRoundToInt(left);
    252             int R = SkFixedRoundToInt(rite);
    253             if (L < R) {
    254                 count += 1;
    255                 blitter->blitRect(L, local_top, R - L, count);
    256             }
    257             local_top = local_bot + 1;
    258         } else {
    259             do {
    260                 int L = SkFixedRoundToInt(left);
    261                 int R = SkFixedRoundToInt(rite);
    262                 if (L < R) {
    263                     blitter->blitH(L, local_top, R - L);
    264                 }
    265                 left += dLeft;
    266                 rite += dRite;
    267                 local_top += 1;
    268             } while (--count >= 0);
    269         }
    270 
    271         leftE->fX = left;
    272         riteE->fX = rite;
    273 
    274         if (update_edge(leftE, local_bot)) {
    275             if (currE->fFirstY >= stop_y) {
    276                 break;
    277             }
    278             leftE = currE;
    279             currE = currE->fNext;
    280         }
    281         if (update_edge(riteE, local_bot)) {
    282             if (currE->fFirstY >= stop_y) {
    283                 break;
    284             }
    285             riteE = currE;
    286             currE = currE->fNext;
    287         }
    288 
    289         SkASSERT(leftE);
    290         SkASSERT(riteE);
    291 
    292         // check our bottom clip
    293         SkASSERT(local_top == local_bot + 1);
    294         if (local_top >= stop_y) {
    295             break;
    296         }
    297     }
    298 }
    299 
    300 ///////////////////////////////////////////////////////////////////////////////
    301 
    302 // this guy overrides blitH, and will call its proxy blitter with the inverse
    303 // of the spans it is given (clipped to the left/right of the cliprect)
    304 //
    305 // used to implement inverse filltypes on paths
    306 //
    307 class InverseBlitter : public SkBlitter {
    308 public:
    309     void setBlitter(SkBlitter* blitter, const SkIRect& clip, int shift) {
    310         fBlitter = blitter;
    311         fFirstX = clip.fLeft << shift;
    312         fLastX = clip.fRight << shift;
    313     }
    314     void prepost(int y, bool isStart) {
    315         if (isStart) {
    316             fPrevX = fFirstX;
    317         } else {
    318             int invWidth = fLastX - fPrevX;
    319             if (invWidth > 0) {
    320                 fBlitter->blitH(fPrevX, y, invWidth);
    321             }
    322         }
    323     }
    324 
    325     // overrides
    326     void blitH(int x, int y, int width) override {
    327         int invWidth = x - fPrevX;
    328         if (invWidth > 0) {
    329             fBlitter->blitH(fPrevX, y, invWidth);
    330         }
    331         fPrevX = x + width;
    332     }
    333 
    334     // we do not expect to get called with these entrypoints
    335     void blitAntiH(int, int, const SkAlpha[], const int16_t runs[]) override {
    336         SkDEBUGFAIL("blitAntiH unexpected");
    337     }
    338     void blitV(int x, int y, int height, SkAlpha alpha) override {
    339         SkDEBUGFAIL("blitV unexpected");
    340     }
    341     void blitRect(int x, int y, int width, int height) override {
    342         SkDEBUGFAIL("blitRect unexpected");
    343     }
    344     void blitMask(const SkMask&, const SkIRect& clip) override {
    345         SkDEBUGFAIL("blitMask unexpected");
    346     }
    347     const SkBitmap* justAnOpaqueColor(uint32_t* value) override {
    348         SkDEBUGFAIL("justAnOpaqueColor unexpected");
    349         return NULL;
    350     }
    351 
    352 private:
    353     SkBlitter*  fBlitter;
    354     int         fFirstX, fLastX, fPrevX;
    355 };
    356 
    357 static void PrePostInverseBlitterProc(SkBlitter* blitter, int y, bool isStart) {
    358     ((InverseBlitter*)blitter)->prepost(y, isStart);
    359 }
    360 
    361 ///////////////////////////////////////////////////////////////////////////////
    362 
    363 #if defined _WIN32 && _MSC_VER >= 1300
    364 #pragma warning ( pop )
    365 #endif
    366 
    367 static bool operator<(const SkEdge& a, const SkEdge& b) {
    368     int valuea = a.fFirstY;
    369     int valueb = b.fFirstY;
    370 
    371     if (valuea == valueb) {
    372         valuea = a.fX;
    373         valueb = b.fX;
    374     }
    375 
    376     return valuea < valueb;
    377 }
    378 
    379 static SkEdge* sort_edges(SkEdge* list[], int count, SkEdge** last) {
    380     SkTQSort(list, list + count - 1);
    381 
    382     // now make the edges linked in sorted order
    383     for (int i = 1; i < count; i++) {
    384         list[i - 1]->fNext = list[i];
    385         list[i]->fPrev = list[i - 1];
    386     }
    387 
    388     *last = list[count - 1];
    389     return list[0];
    390 }
    391 
    392 // clipRect may be null, even though we always have a clip. This indicates that
    393 // the path is contained in the clip, and so we can ignore it during the blit
    394 //
    395 // clipRect (if no null) has already been shifted up
    396 //
    397 void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitter,
    398                   int start_y, int stop_y, int shiftEdgesUp, const SkRegion& clipRgn) {
    399     SkASSERT(blitter);
    400 
    401     SkEdgeBuilder   builder;
    402 
    403     // If we're convex, then we need both edges, even the right edge is past the clip
    404     const bool canCullToTheRight = !path.isConvex();
    405 
    406     int count = builder.build(path, clipRect, shiftEdgesUp, canCullToTheRight);
    407     SkASSERT(count >= 0);
    408 
    409     SkEdge**    list = builder.edgeList();
    410 
    411     if (0 == count) {
    412         if (path.isInverseFillType()) {
    413             /*
    414              *  Since we are in inverse-fill, our caller has already drawn above
    415              *  our top (start_y) and will draw below our bottom (stop_y). Thus
    416              *  we need to restrict our drawing to the intersection of the clip
    417              *  and those two limits.
    418              */
    419             SkIRect rect = clipRgn.getBounds();
    420             if (rect.fTop < start_y) {
    421                 rect.fTop = start_y;
    422             }
    423             if (rect.fBottom > stop_y) {
    424                 rect.fBottom = stop_y;
    425             }
    426             if (!rect.isEmpty()) {
    427                 blitter->blitRect(rect.fLeft << shiftEdgesUp,
    428                                   rect.fTop << shiftEdgesUp,
    429                                   rect.width() << shiftEdgesUp,
    430                                   rect.height() << shiftEdgesUp);
    431             }
    432         }
    433         return;
    434     }
    435 
    436     SkEdge headEdge, tailEdge, *last;
    437     // this returns the first and last edge after they're sorted into a dlink list
    438     SkEdge* edge = sort_edges(list, count, &last);
    439 
    440     headEdge.fPrev = NULL;
    441     headEdge.fNext = edge;
    442     headEdge.fFirstY = kEDGE_HEAD_Y;
    443     headEdge.fX = SK_MinS32;
    444     edge->fPrev = &headEdge;
    445 
    446     tailEdge.fPrev = last;
    447     tailEdge.fNext = NULL;
    448     tailEdge.fFirstY = kEDGE_TAIL_Y;
    449     last->fNext = &tailEdge;
    450 
    451     // now edge is the head of the sorted linklist
    452 
    453     start_y <<= shiftEdgesUp;
    454     stop_y <<= shiftEdgesUp;
    455     if (clipRect && start_y < clipRect->fTop) {
    456         start_y = clipRect->fTop;
    457     }
    458     if (clipRect && stop_y > clipRect->fBottom) {
    459         stop_y = clipRect->fBottom;
    460     }
    461 
    462     InverseBlitter  ib;
    463     PrePostProc     proc = NULL;
    464 
    465     if (path.isInverseFillType()) {
    466         ib.setBlitter(blitter, clipRgn.getBounds(), shiftEdgesUp);
    467         blitter = &ib;
    468         proc = PrePostInverseBlitterProc;
    469     }
    470 
    471     if (path.isConvex() && (NULL == proc)) {
    472         SkASSERT(count >= 2);   // convex walker does not handle missing right edges
    473         walk_convex_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, NULL);
    474     } else {
    475         int rightEdge;
    476         if (clipRect) {
    477             rightEdge = clipRect->right();
    478         } else {
    479             rightEdge = SkScalarRoundToInt(path.getBounds().right()) << shiftEdgesUp;
    480         }
    481 
    482         walk_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, proc, rightEdge);
    483     }
    484 }
    485 
    486 void sk_blit_above(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip) {
    487     const SkIRect& cr = clip.getBounds();
    488     SkIRect tmp;
    489 
    490     tmp.fLeft = cr.fLeft;
    491     tmp.fRight = cr.fRight;
    492     tmp.fTop = cr.fTop;
    493     tmp.fBottom = ir.fTop;
    494     if (!tmp.isEmpty()) {
    495         blitter->blitRectRegion(tmp, clip);
    496     }
    497 }
    498 
    499 void sk_blit_below(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip) {
    500     const SkIRect& cr = clip.getBounds();
    501     SkIRect tmp;
    502 
    503     tmp.fLeft = cr.fLeft;
    504     tmp.fRight = cr.fRight;
    505     tmp.fTop = ir.fBottom;
    506     tmp.fBottom = cr.fBottom;
    507     if (!tmp.isEmpty()) {
    508         blitter->blitRectRegion(tmp, clip);
    509     }
    510 }
    511 
    512 ///////////////////////////////////////////////////////////////////////////////
    513 
    514 /**
    515  *  If the caller is drawing an inverse-fill path, then it pass true for
    516  *  skipRejectTest, so we don't abort drawing just because the src bounds (ir)
    517  *  is outside of the clip.
    518  */
    519 SkScanClipper::SkScanClipper(SkBlitter* blitter, const SkRegion* clip,
    520                              const SkIRect& ir, bool skipRejectTest) {
    521     fBlitter = NULL;     // null means blit nothing
    522     fClipRect = NULL;
    523 
    524     if (clip) {
    525         fClipRect = &clip->getBounds();
    526         if (!skipRejectTest && !SkIRect::Intersects(*fClipRect, ir)) { // completely clipped out
    527             return;
    528         }
    529 
    530         if (clip->isRect()) {
    531             if (fClipRect->contains(ir)) {
    532                 fClipRect = NULL;
    533             } else {
    534                 // only need a wrapper blitter if we're horizontally clipped
    535                 if (fClipRect->fLeft > ir.fLeft || fClipRect->fRight < ir.fRight) {
    536                     fRectBlitter.init(blitter, *fClipRect);
    537                     blitter = &fRectBlitter;
    538                 }
    539             }
    540         } else {
    541             fRgnBlitter.init(blitter, clip);
    542             blitter = &fRgnBlitter;
    543         }
    544     }
    545     fBlitter = blitter;
    546 }
    547 
    548 ///////////////////////////////////////////////////////////////////////////////
    549 
    550 static bool clip_to_limit(const SkRegion& orig, SkRegion* reduced) {
    551     const int32_t limit = 32767;
    552 
    553     SkIRect limitR;
    554     limitR.set(-limit, -limit, limit, limit);
    555     if (limitR.contains(orig.getBounds())) {
    556         return false;
    557     }
    558     reduced->op(orig, limitR, SkRegion::kIntersect_Op);
    559     return true;
    560 }
    561 
    562 void SkScan::FillPath(const SkPath& path, const SkRegion& origClip,
    563                       SkBlitter* blitter) {
    564     if (origClip.isEmpty()) {
    565         return;
    566     }
    567 
    568     // Our edges are fixed-point, and don't like the bounds of the clip to
    569     // exceed that. Here we trim the clip just so we don't overflow later on
    570     const SkRegion* clipPtr = &origClip;
    571     SkRegion finiteClip;
    572     if (clip_to_limit(origClip, &finiteClip)) {
    573         if (finiteClip.isEmpty()) {
    574             return;
    575         }
    576         clipPtr = &finiteClip;
    577     }
    578         // don't reference "origClip" any more, just use clipPtr
    579 
    580     SkIRect ir;
    581     // We deliberately call dround() instead of round(), since we can't afford to generate a
    582     // bounds that is tighter than the corresponding SkEdges. The edge code basically converts
    583     // the floats to fixed, and then "rounds". If we called round() instead of dround() here,
    584     // we could generate the wrong ir for values like 0.4999997.
    585     path.getBounds().dround(&ir);
    586     if (ir.isEmpty()) {
    587         if (path.isInverseFillType()) {
    588             blitter->blitRegion(*clipPtr);
    589         }
    590         return;
    591     }
    592 
    593     SkScanClipper clipper(blitter, clipPtr, ir, path.isInverseFillType());
    594 
    595     blitter = clipper.getBlitter();
    596     if (blitter) {
    597         // we have to keep our calls to blitter in sorted order, so we
    598         // must blit the above section first, then the middle, then the bottom.
    599         if (path.isInverseFillType()) {
    600             sk_blit_above(blitter, ir, *clipPtr);
    601         }
    602         sk_fill_path(path, clipper.getClipRect(), blitter, ir.fTop, ir.fBottom,
    603                      0, *clipPtr);
    604         if (path.isInverseFillType()) {
    605             sk_blit_below(blitter, ir, *clipPtr);
    606         }
    607     } else {
    608         // what does it mean to not have a blitter if path.isInverseFillType???
    609     }
    610 }
    611 
    612 void SkScan::FillPath(const SkPath& path, const SkIRect& ir,
    613                       SkBlitter* blitter) {
    614     SkRegion rgn(ir);
    615     FillPath(path, rgn, blitter);
    616 }
    617 
    618 ///////////////////////////////////////////////////////////////////////////////
    619 
    620 static int build_tri_edges(SkEdge edge[], const SkPoint pts[],
    621                            const SkIRect* clipRect, SkEdge* list[]) {
    622     SkEdge** start = list;
    623 
    624     if (edge->setLine(pts[0], pts[1], clipRect, 0)) {
    625         *list++ = edge;
    626         edge = (SkEdge*)((char*)edge + sizeof(SkEdge));
    627     }
    628     if (edge->setLine(pts[1], pts[2], clipRect, 0)) {
    629         *list++ = edge;
    630         edge = (SkEdge*)((char*)edge + sizeof(SkEdge));
    631     }
    632     if (edge->setLine(pts[2], pts[0], clipRect, 0)) {
    633         *list++ = edge;
    634     }
    635     return (int)(list - start);
    636 }
    637 
    638 
    639 static void sk_fill_triangle(const SkPoint pts[], const SkIRect* clipRect,
    640                              SkBlitter* blitter, const SkIRect& ir) {
    641     SkASSERT(pts && blitter);
    642 
    643     SkEdge edgeStorage[3];
    644     SkEdge* list[3];
    645 
    646     int count = build_tri_edges(edgeStorage, pts, clipRect, list);
    647     if (count < 2) {
    648         return;
    649     }
    650 
    651     SkEdge headEdge, tailEdge, *last;
    652 
    653     // this returns the first and last edge after they're sorted into a dlink list
    654     SkEdge* edge = sort_edges(list, count, &last);
    655 
    656     headEdge.fPrev = NULL;
    657     headEdge.fNext = edge;
    658     headEdge.fFirstY = kEDGE_HEAD_Y;
    659     headEdge.fX = SK_MinS32;
    660     edge->fPrev = &headEdge;
    661 
    662     tailEdge.fPrev = last;
    663     tailEdge.fNext = NULL;
    664     tailEdge.fFirstY = kEDGE_TAIL_Y;
    665     last->fNext = &tailEdge;
    666 
    667     // now edge is the head of the sorted linklist
    668     int stop_y = ir.fBottom;
    669     if (clipRect && stop_y > clipRect->fBottom) {
    670         stop_y = clipRect->fBottom;
    671     }
    672     int start_y = ir.fTop;
    673     if (clipRect && start_y < clipRect->fTop) {
    674         start_y = clipRect->fTop;
    675     }
    676     walk_convex_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y, NULL);
    677 //    walk_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y, NULL);
    678 }
    679 
    680 void SkScan::FillTriangle(const SkPoint pts[], const SkRasterClip& clip,
    681                           SkBlitter* blitter) {
    682     if (clip.isEmpty()) {
    683         return;
    684     }
    685 
    686     SkRect  r;
    687     SkIRect ir;
    688     r.set(pts, 3);
    689     r.round(&ir);
    690     if (ir.isEmpty() || !SkIRect::Intersects(ir, clip.getBounds())) {
    691         return;
    692     }
    693 
    694     SkAAClipBlitterWrapper wrap;
    695     const SkRegion* clipRgn;
    696     if (clip.isBW()) {
    697         clipRgn = &clip.bwRgn();
    698     } else {
    699         wrap.init(clip, blitter);
    700         clipRgn = &wrap.getRgn();
    701         blitter = wrap.getBlitter();
    702     }
    703 
    704     SkScanClipper clipper(blitter, clipRgn, ir);
    705     blitter = clipper.getBlitter();
    706     if (blitter) {
    707         sk_fill_triangle(pts, clipper.getClipRect(), blitter, ir);
    708     }
    709 }
    710