blob: eb7dc34d7e9e870e94ba2f7d00175f7bcc219a1e [file] [log] [blame]
caryclark@google.com639df892012-01-10 21:46:10 +00001/*
2 * SkAntiEdge.cpp
3 * core
4 *
5 * Created by Cary Clark on 5/6/11.
6 * Copyright 2011 __MyCompanyName__. All rights reserved.
7 *
8 */
9
10#include "SkAntiEdge.h"
11#include "SkPoint.h"
12
13void SkAntiEdge::pointOnLine(SkFixed x, SkFixed y) {
14 float x0 = SkFixedToFloat(x);
15 float y0 = SkFixedToFloat(y);
16 float x1 = SkFixedToFloat(fFirstX);
17 float y1 = SkFixedToFloat(fFirstY);
18 float x2 = SkFixedToFloat(fLastX);
19 float y2 = SkFixedToFloat(fLastY);
20 float numer = (x2 - x1) * (y1 - y0) - (x1 - x0) * (y2 - y1);
21 float denom = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
22 double dist = fabs(numer) / sqrt(denom);
23 SkAssertResult(dist < 0.01);
24}
25
26void SkAntiEdge::pointInLine(SkFixed x, SkFixed y) {
27 if (y == SK_MaxS32) {
28 return;
29 }
30 pointOnLine(x, y);
31 SkAssertResult(y >= fFirstY && y <= fLastY);
32}
33
34void SkAntiEdge::validate() {
35 pointOnLine(fWalkX, fY);
36 pointOnLine(fX, fWalkY);
37}
38
39bool SkAntiEdge::setLine(const SkPoint& p0, const SkPoint& p1) {
40 fFirstY = SkScalarToFixed(p0.fY);
41 fLastY = SkScalarToFixed(p1.fY);
42 if (fFirstY == fLastY) {
43 return false;
rmistry@google.comd6176b02012-08-23 18:14:13 +000044 }
caryclark@google.com639df892012-01-10 21:46:10 +000045 fFirstX = SkScalarToFixed(p0.fX);
46 fLastX = SkScalarToFixed(p1.fX);
47 if (fFirstY > fLastY) {
48 SkTSwap(fFirstX, fLastX);
49 SkTSwap(fFirstY, fLastY);
50 fWinding = -1;
51 } else {
52 fWinding = 1;
53 }
54 SkFixed dx = fLastX - fFirstX;
55 fDXFlipped = dx < 0;
56 SkFixed dy = fLastY - fFirstY;
57 fDX = SkFixedDiv(dx, dy);
58 fDY = dx == 0 ? SK_MaxS32 : SkFixedDiv(dy, SkFixedAbs(dx));
59 fLink = NULL;
60 fLinkSet = false;
61 return true;
62}
63
64void SkAntiEdge::calcLine() {
65 SkFixed yStartFrac = SkFixedFraction(fFirstY);
66 if (fDXFlipped) {
67 SkFixed vert = SK_Fixed1 - yStartFrac; // distance from y start to x-axis
68 fX0 = fFirstX + SkFixedMul(fDX, vert);
69 SkFixed backupX = fFirstX + SkFixedMul(vert, fDX); // x cell to back up to
70 SkFixed cellX = SkIntToFixed(SkFixedFloor(backupX));
71 SkFixed endX = SkIntToFixed(SkFixedFloor(fLastX));
72 if (cellX < endX) {
73 cellX = endX;
74 }
75 SkFixed distX = fFirstX - cellX; // to y-axis
76 fY0 = fFirstY + SkFixedMul(fDY, distX);
77 SkFixed rowBottom = SkIntToFixed(SkFixedCeil(fFirstY + 1));
78 if (fLastY > rowBottom) {
79 fPartialY = 0;
80 fX = fX0;
81 fY = rowBottom;
82 } else {
83 fPartialY = SkFixedFraction(fLastY);
84 fX = fLastX;
85 fY = fLastY;
86 }
87 } else {
88 fPartialY = yStartFrac;
89 fX0 = fFirstX - SkFixedMul(fDX, yStartFrac);
90 fY0 = fFirstY;
91 if (fDY != SK_MaxS32) {
92 SkFixed xStartFrac = SkFixedFraction(fFirstX);
93 fY0 -= SkFixedMul(fDY, xStartFrac);
94 }
95 fX = fFirstX;
96 fY = fFirstY;
97 }
98 fWalkX = fX;
99 fWalkY = fY;
100 fFinished = false;
101}
102
103static SkFixed SkFixedAddPin(SkFixed a, SkFixed b) {
104 SkFixed result = a + b;
105 if (((a ^ ~b) & (a ^ result)) >= 0) { // one positive, one negative
106 return result; // or all three same sign
107 }
108 return a < 0 ? -SK_FixedMax : SK_FixedMax;
109}
110
111// edge is increasing in x and y
112uint16_t SkAntiEdge::advanceX(SkFixed left) {
113 validate();
114 SkFixed x = SkFixedAddPin(fX0, fDX);
115 SkFixed wy = SkIntToFixed(SkFixedFloor(fWalkY + SK_Fixed1));
116 pointOnLine(x, wy);
117 SkFixed partial = SK_Fixed1 - fPartialY;
118 SkFixed bottomPartial = wy - fLastY;
119 if (bottomPartial > 0) {
120 partial -= bottomPartial;
121 }
122 if (x > fLastX) {
123 x = fLastX;
124 wy = fLastY;
125 }
126 uint16_t coverage;
127 if (left >= x) {
128 fFinished = true;
129 coverage = partial - 1; // walker is to the right of edge
130 } else {
131 SkFixed y = SkFixedAddPin(fY0, fDY);
132 SkFixed wx = SkIntToFixed(SkFixedFloor(fWalkX + SK_Fixed1));
133 if (fDY != SK_MaxS32) {
134 pointOnLine(wx, y);
135 }
136 if (y > fLastY) {
137 y = fLastY;
138 wx = fLastX;
139 }
140 bool topCorner = fWalkX <= fX;
141 bool bottomCorner = x <= wx;
142 bool halfPlane = !(topCorner ^ bottomCorner);
143 if (halfPlane) {
144 if (x - SkIntToFixed(SkFixedFloor(fX)) <= SK_Fixed1) {
145 coverage = ~((fX + x) >> 1); // avg of fx, fx+dx
146 fFinished = true;
147 if (x >= left + SK_Fixed1) {
148 fWalkX = wx;
149 fY = fY0 = y;
150 }
151 } else {
152 SkAssertResult(y - SkIntToFixed(SkFixedFloor(fY)) <= SK_Fixed1);
153 coverage = ((fY + y) >> 1);
154 fFinished = y == fLastY;
155 fWalkX = wx;
156 fY = fY0 = y;
157 }
158 coverage = coverage * partial >> 16;
159 } else if (topCorner) {
160 SkFixed xDiff = wx - fX;
161 SkAssertResult(xDiff >= 0);
162 SkAssertResult(xDiff <= SK_Fixed1);
163 SkFixed yDiff = y - fWalkY;
164 // This may be a very small negative number if error accumulates
165 // FIXME: for now, try setting it to zero in that case.
166 if (yDiff < 0) {
167 fX = fX0 = SkIntToFixed(SkFixedCeil(fX));
168 yDiff = 0;
169 }
170 SkAssertResult(yDiff >= 0);
171 SkAssertResult(yDiff <= SK_Fixed1);
172 int xCoverage = xDiff >> 1; // throw away 1 bit so multiply
173 int yCoverage = yDiff >> 1; // stays in range
174 int triangle = xCoverage * yCoverage; // 30 bits
175 SkFixed bottomPartial = y - fLastY;
176 fFinished = bottomPartial >= 0;
177 if (fFinished) {
178 yCoverage = bottomPartial >> 1;
179 xCoverage = (wx - fLastX) >> 1;
180 triangle -= xCoverage * yCoverage;
181 }
182 coverage = triangle >> 15;
183 fWalkX = wx;
184 fY = fY0 = y;
185 } else {
186 SkAssertResult(bottomCorner);
187 SkFixed xDiff = x - fWalkX;
188 SkAssertResult(xDiff >= 0);
189 SkAssertResult(xDiff <= SK_Fixed1);
190 SkFixed yDiff = wy - fY;
191 SkAssertResult(yDiff >= 0);
192 SkAssertResult(yDiff <= SK_Fixed1);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000193 int xCoverage = xDiff >> 1; // throw away 1 bit so multiply
caryclark@google.com639df892012-01-10 21:46:10 +0000194 int yCoverage = yDiff >> 1; // stays in range
195 int triangle = xCoverage * yCoverage >> 15;
196 coverage = partial - 1 - triangle;
197 fFinished = true;
198 }
199 }
200 validate();
201 return coverage;
202}
203
204// edge is increasing in x, but decreasing in y
205uint16_t SkAntiEdge::advanceFlippedX(SkFixed left) {
206 validate();
207 SkFixed x = SkFixedAddPin(fX0, -fDX);
208 SkFixed wy = SkIntToFixed(SkFixedFloor(fWalkY - 1));
209 pointOnLine(x, wy);
210 SkFixed partial = fPartialY ? fPartialY : SK_Fixed1;
211 SkFixed topPartial = fFirstY - wy;
212 if (topPartial > 0) {
213 partial -= topPartial;
214 }
215 if (x > fFirstX) {
216 x = fFirstX;
217 wy = fFirstY;
218 }
219 uint16_t coverage;
220 if (left >= x) {
221 fFinished = true;
222 coverage = partial - 1; // walker is to the right of edge
223 } else {
224 SkFixed y = SkFixedAddPin(fY0, -fDY);
225 SkFixed wx = SkIntToFixed(SkFixedFloor(fWalkX + SK_Fixed1));
226 pointOnLine(wx, y);
227 if (y < fFirstY) {
228 y = fFirstY;
229 wx = fFirstX;
230 }
231 bool bottomCorner = fWalkX <= fX;
232 bool topCorner = x <= wx;
233 bool halfPlane = !(topCorner ^ bottomCorner);
234 if (halfPlane) {
235 if (x - SkIntToFixed(SkFixedFloor(fX)) <= SK_Fixed1) {
236 coverage = ~((fX + x) >> 1); // avg of fx, fx+dx
237 fFinished = true;
238 } else {
239 SkAssertResult(y - SkIntToFixed(SkFixedFloor(fY)) <= SK_Fixed1);
240 coverage = ~((fY + y) >> 1);
241 fFinished = y == fY;
242 fWalkX = wx;
243 fY = fY0 = y;
244 }
245 coverage = coverage * partial >> 16;
246 } else if (bottomCorner) {
247 SkFixed xDiff = wx - fX;
248 SkAssertResult(xDiff >= 0);
249 SkAssertResult(xDiff <= SK_Fixed1);
250 SkFixed yDiff = fWalkY - y;
251 SkAssertResult(yDiff >= 0);
252 SkAssertResult(yDiff <= SK_Fixed1);
253 int xCoverage = xDiff >> 1; // throw away 1 bit so multiply
254 int yCoverage = yDiff >> 1; // stays in range
255 int triangle = xCoverage * yCoverage; // 30 bits
256 SkFixed bottomPartial = fFirstY - y;
257 fFinished = bottomPartial >= 0;
258 if (fFinished) {
259 yCoverage = bottomPartial >> 1;
260 xCoverage = (wx - fFirstX) >> 1;
261 triangle -= xCoverage * yCoverage;
262 }
263 coverage = triangle >> 15;
264 fWalkX = wx;
265 fY = fY0 = y;
266 } else {
267 SkAssertResult(topCorner);
268 SkFixed xDiff = x - fWalkX;
269 SkAssertResult(xDiff >= 0);
270 SkAssertResult(xDiff <= SK_Fixed1);
271 SkFixed yDiff = fY - wy;
272 SkAssertResult(yDiff >= 0);
273 SkAssertResult(yDiff <= SK_Fixed1);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000274 int xCoverage = xDiff >> 1; // throw away 1 bit so multiply
caryclark@google.com639df892012-01-10 21:46:10 +0000275 int yCoverage = yDiff >> 1; // stays in range
276 int triangle = xCoverage * yCoverage >> 15;
277 coverage = partial - 1 - triangle;
278 fFinished = true;
279 }
280 }
281 validate();
282 return coverage;
283}
284
285void SkAntiEdge::advanceY(SkFixed top) {
286 validate();
287 fX0 = SkFixedAddPin(fX0, fDX);
288 fPartialY = 0;
289 if (fDXFlipped) {
290 if (fX0 < fLastX) {
291 fWalkX = fX = fLastX;
292 } else {
293 fWalkX = fX = fX0;
294 }
295 SkFixed bottom = top + SK_Fixed1;
296 if (bottom > fLastY) {
297 bottom = fLastY;
298 }
299 SkFixed vert = bottom - fFirstY; // distance from y start to x-axis
300 SkFixed backupX = fFirstX + SkFixedMul(vert, fDX); // x cell to back up to
301 SkFixed distX = fFirstX - SkIntToFixed(SkFixedFloor(backupX)); // to y-axis
302 fY0 = fFirstY + SkFixedMul(fDY, distX);
303
304 fY = top + SK_Fixed1;
305 if (fY > fLastY) {
306 fY = fLastY;
307 }
308 if (fLastY < top + SK_Fixed1) {
309 fPartialY = SkFixedFraction(fLastY);
310 }
311 } else {
312 if (fX0 > fLastX) {
313 fX0 = fLastX;
314 }
315 fX = fX0;
316 }
317 fWalkY = SkIntToFixed(SkFixedFloor(fWalkY + SK_Fixed1));
318 if (fWalkY > fLastY) {
319 fWalkY = fLastY;
320 }
321 validate();
322 fFinished = false;
323}
324
325int SkAntiEdgeBuilder::build(const SkPoint pts[], int count) {
326 SkAntiEdge* edge = fEdges.append();
327 for (int index = 0; index < count; ++index) {
328 if (edge->setLine(pts[index], pts[(index + 1) % count])) {
329 edge = fEdges.append();
330 }
331 }
332 int result = fEdges.count();
333 fEdges.setCount(--result);
334 if (result > 0) {
335 sk_bzero(&fHeadEdge, sizeof(fHeadEdge));
336 sk_bzero(&fTailEdge, sizeof(fTailEdge));
337 for (int index = 0; index < result; ++index) {
338 *fList.append() = &fEdges[index];
339 }
340 }
341 return result;
342}
343
344void SkAntiEdgeBuilder::calc() {
345 for (SkAntiEdge* active = fEdges.begin(); active != fEdges.end(); ++active) {
346 active->calcLine();
347 }
348 // compute winding sum for edges
349 SkAntiEdge* first = fHeadEdge.fNext;
350 SkAntiEdge* active;
351 SkAntiEdge* listTop = first;
352 for (active = first; active != &fTailEdge; active = active->fNext) {
353 active->fWindingSum = active->fWinding;
354 while (listTop->fLastY < active->fFirstY) {
355 listTop = listTop->fNext;
356 }
357 for (SkAntiEdge* check = listTop; check->fFirstY <= active->fFirstY; check = check->fNext) {
358 if (check == active) {
359 continue;
360 }
361 if (check->fLastY <= active->fFirstY) {
362 continue;
363 }
364 if (check->fFirstX > active->fFirstX) {
365 continue;
366 }
367 if (check->fFirstX == active->fFirstX && check->fDX > active->fDX) {
368 continue;
369 }
370 active->fWindingSum += check->fWinding;
371 }
372 }
373}
374
375extern "C" {
376 static int edge_compare(const void* a, const void* b) {
377 const SkAntiEdge* edgea = *(const SkAntiEdge**)a;
378 const SkAntiEdge* edgeb = *(const SkAntiEdge**)b;
379
380 int valuea = edgea->fFirstY;
381 int valueb = edgeb->fFirstY;
382
383 if (valuea == valueb) {
384 valuea = edgea->fFirstX;
385 valueb = edgeb->fFirstX;
386 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000387
caryclark@google.com639df892012-01-10 21:46:10 +0000388 if (valuea == valueb) {
389 valuea = edgea->fDX;
390 valueb = edgeb->fDX;
391 }
392
393 return valuea - valueb;
394 }
395}
396
397void SkAntiEdgeBuilder::sort(SkTDArray<SkAntiEdge*>& listOfEdges) {
398 SkAntiEdge** list = listOfEdges.begin();
399 int count = listOfEdges.count();
400 qsort(list, count, sizeof(SkAntiEdge*), edge_compare);
401
402 // link the edges in sorted order
403 for (int i = 1; i < count; i++) {
404 list[i - 1]->fNext = list[i];
405 list[i]->fPrev = list[i - 1];
406 }
407}
408
409#define kEDGE_HEAD_XY SK_MinS32
410#define kEDGE_TAIL_XY SK_MaxS32
411
412void SkAntiEdgeBuilder::sort() {
413 sort(fList);
414 SkAntiEdge* last = fList.end()[-1];
415 fHeadEdge.fNext = fList[0];
416 fHeadEdge.fFirstX = fHeadEdge.fFirstY = fHeadEdge.fWalkY = fHeadEdge.fLastY = kEDGE_HEAD_XY;
417 fList[0]->fPrev = &fHeadEdge;
418
419 fTailEdge.fPrev = last;
420 fTailEdge.fFirstX = fTailEdge.fFirstY = fTailEdge.fWalkY = fTailEdge.fLastY = kEDGE_TAIL_XY;
421 last->fNext = &fTailEdge;
422}
423
424static inline void remove_edge(SkAntiEdge* edge) {
425 edge->fPrev->fNext = edge->fNext;
426 edge->fNext->fPrev = edge->fPrev;
427}
428
429static inline void swap_edges(SkAntiEdge* prev, SkAntiEdge* next) {
430 SkASSERT(prev->fNext == next && next->fPrev == prev);
431
432 // remove prev from the list
433 prev->fPrev->fNext = next;
434 next->fPrev = prev->fPrev;
435
436 // insert prev after next
437 prev->fNext = next->fNext;
438 next->fNext->fPrev = prev;
439 next->fNext = prev;
440 prev->fPrev = next;
441}
442
443static void backward_insert_edge_based_on_x(SkAntiEdge* edge SkDECLAREPARAM(int, y)) {
444 SkFixed x = edge->fFirstX;
445
446 for (;;) {
447 SkAntiEdge* prev = edge->fPrev;
448
449 // add 1 to curr_y since we may have added new edges (built from curves)
450 // that start on the next scanline
451 SkASSERT(prev && SkFixedFloor(prev->fWalkY - prev->fDXFlipped) <= y + 1);
452
453 if (prev->fFirstX <= x) {
454 break;
455 }
456 swap_edges(prev, edge);
457 }
458}
459
460static void insert_new_edges(SkAntiEdge* newEdge, SkFixed curr_y) {
461 int y = SkFixedFloor(curr_y);
462 if (SkFixedFloor(newEdge->fWalkY - newEdge->fDXFlipped) < y) {
463 return;
464 }
465 while (SkFixedFloor(newEdge->fWalkY - newEdge->fDXFlipped) == y) {
466 SkAntiEdge* next = newEdge->fNext;
467 backward_insert_edge_based_on_x(newEdge SkPARAM(y));
468 newEdge = next;
469 }
470}
471
472static int find_active_edges(int y, SkAntiEdge** activeLeft,
473 SkAntiEdge** activeLast) {
474 SkAntiEdge* first = *activeLeft;
475 SkFixed bottom = first->fLastY;
476 SkAntiEdge* active = first->fNext;
477 first->fLinkSet = false;
478 SkFixed yLimit = SkIntToFixed(y + 1); // limiting pixel edge
479 for ( ; active->fWalkY != kEDGE_TAIL_XY; active = active->fNext) {
480 active->fLinkSet = false;
481 if (yLimit <= active->fWalkY - active->fDXFlipped) {
482 break;
483 }
484 if ((*activeLeft)->fWalkX > active->fWalkX) {
485 *activeLeft = active;
486 }
487 if (bottom > active->fLastY) {
488 bottom = active->fLastY;
489 }
490 }
491 *activeLast = active;
492 return SkFixedCeil(bottom);
493}
494
495// All edges are oriented to increase in y. Link edges with common tops and
496// bottoms so the links can share their winding sum.
497void SkAntiEdgeBuilder::link() {
498 SkAntiEdge* tail = fEdges.end();
499 // look for links forwards and backwards
500 SkAntiEdge* prev = fEdges.begin();
501 SkAntiEdge* active;
502 for (active = prev + 1; active != tail; ++active) {
503 if (prev->fWinding == active->fWinding) {
504 if (prev->fLastX == active->fFirstX && prev->fLastY == active->fFirstY) {
505 prev->fLink = active;
506 active->fLinkSet = true;
507 } else if (active->fLastX == prev->fFirstX && active->fLastY == prev->fFirstY) {
508 active->fLink = prev;
509 prev->fLinkSet = true;
510 }
511 }
512 prev = active;
513 }
514 // look for stragglers
515 prev = fEdges.begin() - 1;
516 do {
517 do {
518 if (++prev == tail) {
519 return;
520 }
521 } while (prev->fLinkSet || NULL != prev->fLink);
522 for (active = prev + 1; active != tail; ++active) {
523 if (active->fLinkSet || NULL != active->fLink) {
524 continue;
525 }
526 if (prev->fWinding != active->fWinding) {
527 continue;
528 }
529 if (prev->fLastX == active->fFirstX && prev->fLastY == active->fFirstY) {
530 prev->fLink = active;
531 active->fLinkSet = true;
532 break;
533 }
534 if (active->fLastX == prev->fFirstX && active->fLastY == prev->fFirstY) {
535 active->fLink = prev;
536 prev->fLinkSet = true;
537 break;
538 }
539 }
540 } while (true);
541}
542
543void SkAntiEdgeBuilder::split(SkAntiEdge* edge, SkFixed y) {
544 SkPoint upperPoint = {edge->fFirstX, edge->fFirstY};
545 SkPoint midPoint = {edge->fFirstX + SkMulDiv(y - edge->fFirstY,
546 edge->fLastX - edge->fFirstX, edge->fLastY - edge->fFirstY), y};
547 SkPoint lowerPoint = {edge->fLastX, edge->fLastY};
548 int8_t winding = edge->fWinding;
549 edge->setLine(upperPoint, midPoint);
550 edge->fWinding = winding;
551 SkAntiEdge* lower = fEdges.append();
552 lower->setLine(midPoint, lowerPoint);
553 lower->fWinding = winding;
554 insert_new_edges(lower, y);
555}
556
557// An edge computes pixel coverage by considering the integral winding value
558// to its left. If an edge is enclosed by fractional winding, split it.
559// FIXME: This is also a good time to find crossing edges and split them, too.
560void SkAntiEdgeBuilder::split() {
561 // create a new set of edges that describe the whole link
562 SkTDArray<SkAntiEdge> links;
563 SkAntiEdge* first = fHeadEdge.fNext;
564 SkAntiEdge* active;
565 for (active = first; active != &fTailEdge; active = active->fNext) {
566 if (active->fLinkSet || NULL == active->fLink) {
567 continue;
568 }
569 SkAntiEdge* link = links.append();
570 link->fFirstX = active->fFirstX;
571 link->fFirstY = active->fFirstY;
572 SkAntiEdge* linkEnd;
573 SkAntiEdge* next = active;
574 do {
575 linkEnd = next;
576 next = next->fLink;
577 } while (NULL != next);
578 link->fLastX = linkEnd->fLastX;
579 link->fLastY = linkEnd->fLastY;
580 }
581 // create a list of all edges, links and singletons
582 SkTDArray<SkAntiEdge*> list;
583 for (active = links.begin(); active != links.end(); ++active) {
584 *list.append() = active;
585 }
586 for (active = first; active != &fTailEdge; active = active->fNext) {
587 if (!active->fLinkSet && NULL == active->fLink) {
588 SkAntiEdge* link = links.append();
589 link->fFirstX = active->fFirstX;
590 link->fFirstY = active->fFirstY;
591 link->fLastX = active->fLastX;
592 link->fLastY = active->fLastY;
593 *list.append() = link;
594 }
595 }
596 SkAntiEdge tail;
597 tail.fFirstY = tail.fLastY = kEDGE_TAIL_XY;
598 *list.append() = &tail;
599 sort(list);
600 // walk the list, splitting edges partially occluded on the left
601 SkAntiEdge* listTop = list[0];
602 for (active = first; active != &fTailEdge; active = active->fNext) {
603 while (listTop->fLastY < active->fFirstY) {
604 listTop = listTop->fNext;
605 }
606 for (SkAntiEdge* check = listTop; check->fFirstY < active->fLastY; check = check->fNext) {
607 if (check->fFirstX > active->fFirstX) {
608 continue;
609 }
610 if (check->fFirstX == active->fFirstX && check->fDX > active->fDX) {
611 continue;
612 }
613 if (check->fFirstY > active->fFirstY) {
614 split(active, check->fFirstY);
615 }
616 if (check->fLastY < active->fLastY) {
617 split(active, check->fLastY);
618 }
619 }
620 }
621}
622
623static inline uint8_t coverage_to_8(int coverage) {
624 uint16_t x = coverage < 0 ? 0 : coverage > 0xFFFF ? 0xFFFF : coverage;
625 // for values 0x7FFF and smaller, add (0x7F - high byte) and trunc
626 // for values 0x8000 and larger, subtract (high byte - 0x80) and trunc
627 return (x + 0x7f + (x >> 15) - (x >> 8)) >> 8;
628}
629
630void SkAntiEdgeBuilder::walk(uint8_t* result, int rowBytes, int height) {
631 SkAntiEdge* first = fHeadEdge.fNext;
632 SkFixed top = first->fWalkY - first->fDXFlipped;
633 int y = SkFixedFloor(top);
634 do {
635 SkAntiEdge* activeLeft = first;
636 SkAntiEdge* activeLast, * active;
637 int yLast = find_active_edges(y, &activeLeft, &activeLast);
638 while (y < yLast) {
639 SkAssertResult(y >= 0);
640 SkAssertResult(y < height);
641 SkFixed left = activeLeft->fWalkX;
642 int x = SkFixedFloor(left);
643 uint8_t* resultPtr = &result[y * rowBytes + x];
644 bool finished;
645 do {
646 left = SkIntToFixed(x);
647 SkAssertResult(x >= 0);
648 // SkAssertResult(x < pixelCol);
649 if (x >= rowBytes) { // FIXME: cumulative error in fX += fDX
650 break; // fails to set fFinished early enough
651 } // see test 6 (dy<dx)
652 finished = true;
653 int coverage = 0;
654 for (active = first; active != activeLast; active = active->fNext) {
655 if (left + SK_Fixed1 <= active->fX) {
656 finished = false;
657 continue; // walker is to the left of edge
658 }
659 int cover = active->fDXFlipped ?
660 active->advanceFlippedX(left) : active->advanceX(left);
661 if (0 == active->fWindingSum) {
662 cover = -cover;
663 }
664 coverage += cover;
665 finished &= active->fFinished;
666 }
667 uint8_t old = *resultPtr;
668 uint8_t pix = coverage_to_8(coverage);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000669 uint8_t blend = old > pix ? old : pix;
caryclark@google.com639df892012-01-10 21:46:10 +0000670 *resultPtr++ = blend;
671 ++x;
672 } while (!finished);
673 ++y;
674 top = SkIntToFixed(y);
675 SkFixed topLimit = top + SK_Fixed1;
676 SkFixed xSort = -SK_FixedMax;
677 for (active = first; active != activeLast; active = active->fNext) {
678 if (xSort > active->fX || topLimit > active->fLastY) {
679 yLast = y; // recompute bottom after all Ys are advanced
680 }
681 xSort = active->fX;
682 if (active->fWalkY < active->fLastY) {
683 active->advanceY(top);
684 }
685 }
686 for (active = first; active != activeLast; ) {
687 SkAntiEdge* next = active->fNext;
688 if (top >= active->fLastY) {
689 remove_edge(active);
690 }
691 active = next;
692 }
693 first = fHeadEdge.fNext;
694 }
695 SkAntiEdge* prev = activeLast->fPrev;
696 if (prev != &fHeadEdge) {
697 insert_new_edges(prev, top);
698 first = fHeadEdge.fNext;
699 }
700 } while (first->fWalkY < kEDGE_TAIL_XY);
701}
702
703void SkAntiEdgeBuilder::process(const SkPoint* points, int ptCount,
704 uint8_t* result, int pixelCol, int pixelRow) {
705 if (ptCount < 3) {
706 return;
707 }
708 int count = build(points, ptCount);
709 if (count == 0) {
710 return;
711 }
712 SkAssertResult(count > 1);
713 link();
714 sort();
715 split();
716 calc();
717 walk(result, pixelCol, pixelRow);
718}
719
720////////////////////////////////////////////////////////////////////////////////
721
722int test3by3_test;
723
724// input is a rectangle
725static void test_3_by_3() {
726 const int pixelRow = 3;
727 const int pixelCol = 3;
728 const int ptCount = 4;
729 const int pixelCount = pixelRow * pixelCol;
730 const SkPoint tests[][ptCount] = {
731 {{2.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, 2.0f}, {2.0f, 2.0f}}, // 0: full rect
732 {{2.5f, 1.0f}, {1.5f, 1.0f}, {1.5f, 2.0f}, {2.5f, 2.0f}}, // 1: y edge
733 {{2.0f, 1.5f}, {1.0f, 1.5f}, {1.0f, 2.5f}, {2.0f, 2.5f}}, // 2: x edge
734 {{2.5f, 1.5f}, {1.5f, 1.5f}, {1.5f, 2.5f}, {2.5f, 2.5f}}, // 3: x/y edge
735 {{2.8f, 0.2f}, {0.2f, 0.2f}, {0.2f, 2.8f}, {2.8f, 2.8f}}, // 4: large
736 {{1.8f, 1.2f}, {1.2f, 1.2f}, {1.2f, 1.8f}, {1.8f, 1.8f}}, // 5: small
737 {{0.0f, 0.0f}, {0.0f, 1.0f}, {3.0f, 2.0f}, {3.0f, 1.0f}}, // 6: dy<dx
738 {{3.0f, 0.0f}, {0.0f, 1.0f}, {0.0f, 2.0f}, {3.0f, 1.0f}}, // 7: dy<-dx
739 {{1.0f, 0.0f}, {0.0f, 0.0f}, {1.0f, 3.0f}, {2.0f, 3.0f}}, // 8: dy>dx
740 {{2.0f, 0.0f}, {1.0f, 0.0f}, {0.0f, 3.0f}, {1.0f, 3.0f}}, // 9: dy>-dx
741 {{0.5f, 0.5f}, {0.5f, 1.5f}, {2.5f, 2.5f}, {2.5f, 1.5f}}, // 10: dy<dx 2
742 {{2.5f, 0.5f}, {0.5f, 1.5f}, {0.5f, 2.5f}, {2.5f, 1.5f}}, // 11: dy<-dx 2
743 {{0.0f, 0.0f}, {2.0f, 0.0f}, {2.0f, 2.0f}, {0.0f, 2.0f}}, // 12: 2x2
744 {{0.0f, 0.0f}, {3.0f, 0.0f}, {3.0f, 3.0f}, {0.0f, 3.0f}}, // 13: 3x3
745 {{1.75f, 0.25f}, {2.75f, 1.25f}, {1.25f, 2.75f}, {0.25f, 1.75f}}, // 14
746 {{2.25f, 0.25f}, {2.75f, 0.75f}, {0.75f, 2.75f}, {0.25f, 2.25f}}, // 15
747 {{0.25f, 0.75f}, {0.75f, 0.25f}, {2.75f, 2.25f}, {2.25f, 2.75f}}, // 16
748 {{1.25f, 0.50f}, {1.75f, 0.25f}, {2.75f, 2.25f}, {2.25f, 2.50f}}, // 17
749 {{1.00f, 0.75f}, {2.00f, 0.50f}, {2.00f, 1.50f}, {1.00f, 1.75f}}, // 18
750 {{1.00f, 0.50f}, {2.00f, 0.75f}, {2.00f, 1.75f}, {1.00f, 1.50f}}, // 19
751 {{1.00f, 0.75f}, {1.00f, 1.75f}, {2.00f, 1.50f}, {2.00f, 0.50f}}, // 20
752 {{1.00f, 0.50f}, {1.00f, 1.50f}, {2.00f, 1.75f}, {2.00f, 0.75f}}, // 21
753 };
754 const uint8_t results[][pixelCount] = {
755 {0x00, 0x00, 0x00, // 0: 1 pixel rect
756 0x00, 0xFF, 0x00,
757 0x00, 0x00, 0x00},
758 {0x00, 0x00, 0x00, // 1: y edge
759 0x00, 0x7F, 0x80,
760 0x00, 0x00, 0x00},
761 {0x00, 0x00, 0x00, // 2: x edge
762 0x00, 0x7F, 0x00,
763 0x00, 0x7F, 0x00},
764 {0x00, 0x00, 0x00, // 3: x/y edge
765 0x00, 0x40, 0x40,
766 0x00, 0x40, 0x40},
767 {0xA3, 0xCC, 0xA3, // 4: large
768 0xCC, 0xFF, 0xCC,
769 0xA3, 0xCC, 0xA3},
770 {0x00, 0x00, 0x00, // 5: small
771 0x00, 0x5C, 0x00,
772 0x00, 0x00, 0x00},
773 {0xD5, 0x80, 0x2B, // 6: dy<dx
774 0x2A, 0x7F, 0xD4,
775 0x00, 0x00, 0x00},
776 {0x2B, 0x80, 0xD5, // 7: dy<-dx
777 0xD4, 0x7F, 0x2A,
778 0x00, 0x00, 0x00},
779 {0xD5, 0x2A, 0x00, // 8: dy>dx
780 0x80, 0x7F, 0x00,
781 0x2B, 0xD4, 0x00},
782 {0x2A, 0xD5, 0x00, // 9: dy>-dx
783 0x7F, 0x80, 0x00,
784 0xD4, 0x2B, 0x00},
785 {0x30, 0x10, 0x00, // 10: dy<dx 2
786 0x50, 0xDF, 0x50,
787 0x00, 0x10, 0x30},
788 {0x00, 0x10, 0x30, // 11: dy<-dx 2
789 0x50, 0xDF, 0x50,
790 0x30, 0x10, 0x00},
791 {0xFF, 0xFF, 0x00, // 12: 2x2
792 0xFF, 0xFF, 0x00,
793 0x00, 0x00, 0x00},
794 {0xFF, 0xFF, 0xFF, // 13: 3x3
795 0xFF, 0xFF, 0xFF,
796 0xFF, 0xFF, 0xFF},
797 {0x00, 0x70, 0x20, // 14
798 0x70, 0xFF, 0x70,
799 0x20, 0x70, 0x00},
800 {0x00, 0x20, 0x60, // 15
801 0x20, 0xBF, 0x20,
802 0x60, 0x20, 0x00},
803 {0x60, 0x20, 0x00, // 16
804 0x20, 0xBF, 0x20,
805 0x00, 0x20, 0x60},
806 {0x00, 0x60, 0x04, // 17
807 0x00, 0x40, 0x60,
808 0x00, 0x00, 0x3C},
809 {0x00, 0x60, 0x00, // 18
810 0x00, 0x9F, 0x00,
811 0x00, 0x00, 0x00},
812 {0x00, 0x60, 0x00, // 19
813 0x00, 0x9F, 0x00,
814 0x00, 0x00, 0x00},
815 {0x00, 0x60, 0x00, // 20
816 0x00, 0x9F, 0x00,
817 0x00, 0x00, 0x00},
818 {0x00, 0x60, 0x00, // 21
819 0x00, 0x9F, 0x00,
820 0x00, 0x00, 0x00},
821 };
822 const int testCount = sizeof(tests) / sizeof(tests[0]);
823 SkAssertResult(testCount == sizeof(results) / sizeof(results[0]));
824 int testFirst = test3by3_test < 0 ? 0 : test3by3_test;
825 int testLast = test3by3_test < 0 ? testCount : test3by3_test + 1;
826 for (int testIndex = testFirst; testIndex < testLast; ++testIndex) {
827 uint8_t result[pixelRow][pixelCol];
828 sk_bzero(result, sizeof(result));
829 const SkPoint* rect = tests[testIndex];
830 SkAntiEdgeBuilder builder;
831 builder.process(rect, ptCount, result[0], pixelCol, pixelRow);
832 SkAssertResult(memcmp(results[testIndex], result[0], pixelCount) == 0);
833 }
834}
835
836// input has arbitrary number of points
837static void test_arbitrary_3_by_3() {
838 const int pixelRow = 3;
839 const int pixelCol = 3;
840 const int pixelCount = pixelRow * pixelCol;
841 const SkPoint t1[] = { {1,1}, {2,1}, {2,1.5f}, {1,1.5f}, {1,2}, {2,2},
842 {2,1.5f}, {1,1.5f}, {1,1} };
843 const SkPoint* tests[] = { t1 };
844 size_t testPts[] = { sizeof(t1) / sizeof(t1[0]) };
845 const uint8_t results[][pixelCount] = {
846 {0x00, 0x00, 0x00, // 0: 1 pixel rect
847 0x00, 0xFF, 0x00,
848 0x00, 0x00, 0x00},
849 };
850 const int testCount = sizeof(tests) / sizeof(tests[0]);
851 SkAssertResult(testCount == sizeof(results) / sizeof(results[0]));
852 int testFirst = test3by3_test < 0 ? 0 : test3by3_test;
853 int testLast = test3by3_test < 0 ? testCount : test3by3_test + 1;
854 for (int testIndex = testFirst; testIndex < testLast; ++testIndex) {
855 uint8_t result[pixelRow][pixelCol];
856 sk_bzero(result, sizeof(result));
857 const SkPoint* pts = tests[testIndex];
858 size_t ptCount = testPts[testIndex];
859 SkAntiEdgeBuilder builder;
860 builder.process(pts, ptCount, result[0], pixelCol, pixelRow);
861 SkAssertResult(memcmp(results[testIndex], result[0], pixelCount) == 0);
862 }
863}
864
865#include "SkRect.h"
866#include "SkPath.h"
867
868int testsweep_test;
869
870static void create_sweep(uint8_t* result, int pixelRow, int pixelCol, SkScalar rectWidth) {
871 const int ptCount = 4;
872 SkRect refRect = {pixelCol / 2 - rectWidth / 2, 5,
873 pixelCol / 2 + rectWidth / 2, pixelRow / 2 - 5};
874 SkPath refPath;
875 refPath.addRect(refRect);
876 SkScalar angleFirst = testsweep_test < 0 ? 0 : testsweep_test;
877 SkScalar angleLast = testsweep_test < 0 ? 360 : testsweep_test + 1;
878 for (SkScalar angle = angleFirst; angle < angleLast; angle += 12) {
879 SkPath rotPath;
880 SkMatrix matrix;
881 matrix.setRotate(angle, SkIntToScalar(pixelCol) / 2,
882 SkIntToScalar(pixelRow) / 2);
883 refPath.transform(matrix, &rotPath);
884 SkPoint rect[ptCount], temp[2];
885 SkPath::Iter iter(rotPath, false);
886 int index = 0;
887 for (;;) {
888 SkPath::Verb verb = iter.next(temp);
889 if (verb == SkPath::kMove_Verb) {
890 continue;
891 }
892 if (verb == SkPath::kClose_Verb) {
893 break;
894 }
895 SkAssertResult(SkPath::kLine_Verb == verb);
896 rect[index++] = temp[0];
897 }
898 SkAntiEdgeBuilder builder;
899 builder.process(rect, ptCount, result, pixelCol, pixelRow);
900 }
901}
902
903static void create_horz(uint8_t* result, int pixelRow, int pixelCol) {
904 const int ptCount = 4;
905 for (SkScalar x = 0; x < 100; x += 5) {
906 SkPoint rect[ptCount];
907 rect[0].fX = 0; rect[0].fY = x;
908 rect[1].fX = 100; rect[1].fY = x;
909 rect[2].fX = 100; rect[2].fY = x + x / 50;
910 rect[3].fX = 0; rect[3].fY = x + x / 50;
911 SkAntiEdgeBuilder builder;
912 builder.process(rect, ptCount, result, pixelCol, pixelRow);
913 }
914}
915
916static void create_vert(uint8_t* result, int pixelRow, int pixelCol) {
917 const int ptCount = 4;
918 for (SkScalar x = 0; x < 100; x += 5) {
919 SkPoint rect[ptCount];
920 rect[0].fY = 0; rect[0].fX = x;
921 rect[1].fY = 100; rect[1].fX = x;
922 rect[2].fY = 100; rect[2].fX = x + x / 50;
923 rect[3].fY = 0; rect[3].fX = x + x / 50;
924 SkAntiEdgeBuilder builder;
925 builder.process(rect, ptCount, result, pixelCol, pixelRow);
926 }
927}
928
929static void create_angle(uint8_t* result, int pixelRow, int pixelCol, SkScalar angle) {
930 const int ptCount = 4;
931 SkRect refRect = {25, 25, 125, 125};
932 SkPath refPath;
933 for (SkScalar x = 30; x < 125; x += 5) {
934 refRect.fTop = x;
935 refRect.fBottom = x + (x - 25) / 50;
936 refPath.addRect(refRect);
937 }
938 SkPath rotPath;
939 SkMatrix matrix;
940 matrix.setRotate(angle, 75, 75);
941 refPath.transform(matrix, &rotPath);
942 SkPath::Iter iter(rotPath, false);
943 for (SkScalar x = 30; x < 125; x += 5) {
944 SkPoint rect[ptCount], temp[2];
945 int index = 0;
946 for (;;) {
947 SkPath::Verb verb = iter.next(temp);
948 if (verb == SkPath::kMove_Verb) {
949 continue;
950 }
951 if (verb == SkPath::kClose_Verb) {
952 break;
953 }
954 SkAssertResult(SkPath::kLine_Verb == verb);
955 rect[index++] = temp[0];
956 }
957 // if ((x == 30 || x == 75) && angle == 12) continue;
958 SkAntiEdgeBuilder builder;
959 builder.process(rect, ptCount, result, pixelCol, pixelRow);
960 }
961}
962
963static void test_sweep() {
964 const int pixelRow = 100;
965 const int pixelCol = 100;
966 uint8_t result[pixelRow][pixelCol];
967 sk_bzero(result, sizeof(result));
968 create_sweep(result[0], pixelRow, pixelCol, 1);
969}
970
971static void test_horz() {
972 const int pixelRow = 100;
973 const int pixelCol = 100;
974 uint8_t result[pixelRow][pixelCol];
975 sk_bzero(result, sizeof(result));
976 create_horz(result[0], pixelRow, pixelCol);
977}
978
979static void test_vert() {
980 const int pixelRow = 100;
981 const int pixelCol = 100;
982 uint8_t result[pixelRow][pixelCol];
983 sk_bzero(result, sizeof(result));
984 create_vert(result[0], pixelRow, pixelCol);
985}
986
987static void test_angle(SkScalar angle) {
988 const int pixelRow = 150;
989 const int pixelCol = 150;
990 uint8_t result[pixelRow][pixelCol];
991 sk_bzero(result, sizeof(result));
992 create_angle(result[0], pixelRow, pixelCol, angle);
993}
994
995#include "SkBitmap.h"
996
997void CreateSweep(SkBitmap* sweep, SkScalar rectWidth) {
998 const int pixelRow = 100;
999 const int pixelCol = 100;
1000 sweep->setConfig(SkBitmap::kA8_Config, pixelCol, pixelRow);
1001 sweep->allocPixels();
1002 sweep->eraseColor(0);
1003 sweep->lockPixels();
1004 void* pixels = sweep->getPixels();
1005 create_sweep((uint8_t*) pixels, pixelRow, pixelCol, rectWidth);
1006 sweep->unlockPixels();
1007}
1008
1009void CreateHorz(SkBitmap* sweep) {
1010 const int pixelRow = 100;
1011 const int pixelCol = 100;
1012 sweep->setConfig(SkBitmap::kA8_Config, pixelCol, pixelRow);
1013 sweep->allocPixels();
1014 sweep->eraseColor(0);
1015 sweep->lockPixels();
1016 void* pixels = sweep->getPixels();
1017 create_horz((uint8_t*) pixels, pixelRow, pixelCol);
1018 sweep->unlockPixels();
1019}
1020
1021void CreateVert(SkBitmap* sweep) {
1022 const int pixelRow = 100;
1023 const int pixelCol = 100;
1024 sweep->setConfig(SkBitmap::kA8_Config, pixelCol, pixelRow);
1025 sweep->allocPixels();
1026 sweep->eraseColor(0);
1027 sweep->lockPixels();
1028 void* pixels = sweep->getPixels();
1029 create_vert((uint8_t*) pixels, pixelRow, pixelCol);
1030 sweep->unlockPixels();
1031}
1032
1033void CreateAngle(SkBitmap* sweep, SkScalar angle) {
1034 const int pixelRow = 150;
1035 const int pixelCol = 150;
1036 sweep->setConfig(SkBitmap::kA8_Config, pixelCol, pixelRow);
1037 sweep->allocPixels();
1038 sweep->eraseColor(0);
1039 sweep->lockPixels();
1040 void* pixels = sweep->getPixels();
1041 create_angle((uint8_t*) pixels, pixelRow, pixelCol, angle);
1042 sweep->unlockPixels();
1043}
1044
1045#include "SkCanvas.h"
1046
1047static void testPng() {
caryclark@google.com639df892012-01-10 21:46:10 +00001048 SkBitmap device;
1049 device.setConfig(SkBitmap::kARGB_8888_Config, 4, 4);
1050 device.allocPixels();
1051 device.eraseColor(0xFFFFFFFF);
reed@google.com82ba6772012-09-28 19:09:23 +00001052
1053 SkCanvas canvas(device);
caryclark@google.com639df892012-01-10 21:46:10 +00001054 canvas.drawARGB(167, 0, 0, 0);
reed@google.com82ba6772012-09-28 19:09:23 +00001055
caryclark@google.com639df892012-01-10 21:46:10 +00001056 device.lockPixels();
1057 unsigned char* pixels = (unsigned char*) device.getPixels();
1058 SkDebugf("%02x%02x%02x%02x", pixels[3], pixels[2], pixels[1], pixels[0]);
1059}
1060
1061void SkAntiEdge_Test() {
1062 testPng();
1063 test_arbitrary_3_by_3();
1064 test_angle(12);
1065#if 0
1066 test3by3_test = 18;
1067#else
1068 test3by3_test = -1;
1069#endif
1070#if 0
1071 testsweep_test = 7 * 12;
1072#else
1073 testsweep_test = -1;
1074#endif
1075 if (testsweep_test == -1) {
1076 test_3_by_3();
1077 }
1078 test_sweep();
1079 test_horz();
1080 test_vert();
1081}
1082