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
validate_sort(const SkEdge * edge)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
remove_edge(SkEdge * edge)39 static inline void remove_edge(SkEdge* edge) {
40 edge->fPrev->fNext = edge->fNext;
41 edge->fNext->fPrev = edge->fPrev;
42 }
43
insert_edge_after(SkEdge * edge,SkEdge * afterMe)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
backward_insert_edge_based_on_x(SkEdge * edge SkDECLAREPARAM (int,curr_y))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
insert_new_edges(SkEdge * newEdge,int curr_y)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
validate_edges_for_y(const SkEdge * edge,int curr_y)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
walk_edges(SkEdge * prevHead,SkPath::FillType fillType,SkBlitter * blitter,int start_y,int stop_y,PrePostProc proc,int rightClip)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
update_edge(SkEdge * edge,int last_y)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
walk_convex_edges(SkEdge * prevHead,SkPath::FillType,SkBlitter * blitter,int start_y,int stop_y,PrePostProc proc)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:
setBlitter(SkBlitter * blitter,const SkIRect & clip,int shift)309 void setBlitter(SkBlitter* blitter, const SkIRect& clip, int shift) {
310 fBlitter = blitter;
311 fFirstX = clip.fLeft << shift;
312 fLastX = clip.fRight << shift;
313 }
prepost(int y,bool isStart)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
blitH(int x,int y,int width)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
blitAntiH(int,int,const SkAlpha[],const int16_t runs[])335 void blitAntiH(int, int, const SkAlpha[], const int16_t runs[]) override {
336 SkDEBUGFAIL("blitAntiH unexpected");
337 }
blitV(int x,int y,int height,SkAlpha alpha)338 void blitV(int x, int y, int height, SkAlpha alpha) override {
339 SkDEBUGFAIL("blitV unexpected");
340 }
blitRect(int x,int y,int width,int height)341 void blitRect(int x, int y, int width, int height) override {
342 SkDEBUGFAIL("blitRect unexpected");
343 }
blitMask(const SkMask &,const SkIRect & clip)344 void blitMask(const SkMask&, const SkIRect& clip) override {
345 SkDEBUGFAIL("blitMask unexpected");
346 }
justAnOpaqueColor(uint32_t * value)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
PrePostInverseBlitterProc(SkBlitter * blitter,int y,bool isStart)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
operator <(const SkEdge & a,const SkEdge & b)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
sort_edges(SkEdge * list[],int count,SkEdge ** last)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 //
sk_fill_path(const SkPath & path,const SkIRect * clipRect,SkBlitter * blitter,int start_y,int stop_y,int shiftEdgesUp,const SkRegion & clipRgn)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
sk_blit_above(SkBlitter * blitter,const SkIRect & ir,const SkRegion & clip)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
sk_blit_below(SkBlitter * blitter,const SkIRect & ir,const SkRegion & clip)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 */
SkScanClipper(SkBlitter * blitter,const SkRegion * clip,const SkIRect & ir,bool skipRejectTest)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
clip_to_limit(const SkRegion & orig,SkRegion * reduced)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
FillPath(const SkPath & path,const SkRegion & origClip,SkBlitter * blitter)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
FillPath(const SkPath & path,const SkIRect & ir,SkBlitter * blitter)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
build_tri_edges(SkEdge edge[],const SkPoint pts[],const SkIRect * clipRect,SkEdge * list[])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
sk_fill_triangle(const SkPoint pts[],const SkIRect * clipRect,SkBlitter * blitter,const SkIRect & ir)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
FillTriangle(const SkPoint pts[],const SkRasterClip & clip,SkBlitter * blitter)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