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