• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright 2011 The Android Open Source Project
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 
10 #include "SkScan.h"
11 #include "SkBlitter.h"
12 #include "SkColorPriv.h"
13 #include "SkLineClipper.h"
14 #include "SkRasterClip.h"
15 #include "SkFDot6.h"
16 
17 /*  Our attempt to compute the worst case "bounds" for the horizontal and
18     vertical cases has some numerical bug in it, and we sometimes undervalue
19     our extends. The bug is that when this happens, we will set the clip to
20     NULL (for speed), and thus draw outside of the clip by a pixel, which might
21     only look bad, but it might also access memory outside of the valid range
22     allcoated for the device bitmap.
23 
24     This define enables our fix to outset our "bounds" by 1, thus avoiding the
25     chance of the bug, but at the cost of sometimes taking the rectblitter
26     case (i.e. not setting the clip to NULL) when we might not actually need
27     to. If we can improve/fix the actual calculations, then we can remove this
28     step.
29  */
30 #define OUTSET_BEFORE_CLIP_TEST     true
31 
32 #define HLINE_STACK_BUFFER      100
33 
SmallDot6Scale(int value,int dot6)34 static inline int SmallDot6Scale(int value, int dot6) {
35     SkASSERT((int16_t)value == value);
36     SkASSERT((unsigned)dot6 <= 64);
37     return SkMulS16(value, dot6) >> 6;
38 }
39 
40 //#define TEST_GAMMA
41 
42 #ifdef TEST_GAMMA
43     static uint8_t gGammaTable[256];
44     #define ApplyGamma(table, alpha)    (table)[alpha]
45 
build_gamma_table()46     static void build_gamma_table() {
47         static bool gInit = false;
48 
49         if (gInit == false) {
50             for (int i = 0; i < 256; i++) {
51                 SkFixed n = i * 257;
52                 n += n >> 15;
53                 SkASSERT(n >= 0 && n <= SK_Fixed1);
54                 n = SkFixedSqrt(n);
55                 n = n * 255 >> 16;
56             //  SkDebugf("morph %d -> %d\n", i, n);
57                 gGammaTable[i] = SkToU8(n);
58             }
59             gInit = true;
60         }
61     }
62 #else
63     #define ApplyGamma(table, alpha)    SkToU8(alpha)
64 #endif
65 
66 ///////////////////////////////////////////////////////////////////////////////
67 
call_hline_blitter(SkBlitter * blitter,int x,int y,int count,U8CPU alpha)68 static void call_hline_blitter(SkBlitter* blitter, int x, int y, int count,
69                                U8CPU alpha) {
70     SkASSERT(count > 0);
71 
72     int16_t runs[HLINE_STACK_BUFFER + 1];
73     uint8_t  aa[HLINE_STACK_BUFFER];
74 
75     aa[0] = ApplyGamma(gGammaTable, alpha);
76     do {
77         int n = count;
78         if (n > HLINE_STACK_BUFFER) {
79             n = HLINE_STACK_BUFFER;
80         }
81         runs[0] = SkToS16(n);
82         runs[n] = 0;
83         blitter->blitAntiH(x, y, aa, runs);
84         x += n;
85         count -= n;
86     } while (count > 0);
87 }
88 
hline(int x,int stopx,SkFixed fy,SkFixed,SkBlitter * blitter,int mod64)89 static SkFixed hline(int x, int stopx, SkFixed fy, SkFixed /*slope*/,
90                      SkBlitter* blitter, int mod64) {
91     SkASSERT(x < stopx);
92     int count = stopx - x;
93     fy += SK_Fixed1/2;
94 
95     int y = fy >> 16;
96     uint8_t  a = (uint8_t)(fy >> 8);
97 
98     // lower line
99     unsigned ma = SmallDot6Scale(a, mod64);
100     if (ma) {
101         call_hline_blitter(blitter, x, y, count, ma);
102     }
103 
104     // upper line
105     ma = SmallDot6Scale(255 - a, mod64);
106     if (ma) {
107         call_hline_blitter(blitter, x, y - 1, count, ma);
108     }
109 
110     return fy - SK_Fixed1/2;
111 }
112 
horish(int x,int stopx,SkFixed fy,SkFixed dy,SkBlitter * blitter,int mod64)113 static SkFixed horish(int x, int stopx, SkFixed fy, SkFixed dy,
114                       SkBlitter* blitter, int mod64) {
115     SkASSERT(x < stopx);
116 
117 #ifdef TEST_GAMMA
118     const uint8_t* gamma = gGammaTable;
119 #endif
120     int16_t runs[2];
121     uint8_t  aa[1];
122 
123     runs[0] = 1;
124     runs[1] = 0;
125 
126     fy += SK_Fixed1/2;
127     do {
128         int lower_y = fy >> 16;
129         uint8_t  a = (uint8_t)(fy >> 8);
130         unsigned ma = SmallDot6Scale(a, mod64);
131         if (ma) {
132             aa[0] = ApplyGamma(gamma, ma);
133             blitter->blitAntiH(x, lower_y, aa, runs);
134             // the clipping blitters might edit runs, but should not affect us
135             SkASSERT(runs[0] == 1);
136             SkASSERT(runs[1] == 0);
137         }
138         ma = SmallDot6Scale(255 - a, mod64);
139         if (ma) {
140             aa[0] = ApplyGamma(gamma, ma);
141             blitter->blitAntiH(x, lower_y - 1, aa, runs);
142             // the clipping blitters might edit runs, but should not affect us
143             SkASSERT(runs[0] == 1);
144             SkASSERT(runs[1] == 0);
145         }
146         fy += dy;
147     } while (++x < stopx);
148 
149     return fy - SK_Fixed1/2;
150 }
151 
vline(int y,int stopy,SkFixed fx,SkFixed,SkBlitter * blitter,int mod64)152 static SkFixed vline(int y, int stopy, SkFixed fx, SkFixed /*slope*/,
153                      SkBlitter* blitter, int mod64) {
154     SkASSERT(y < stopy);
155     fx += SK_Fixed1/2;
156 
157     int x = fx >> 16;
158     int a = (uint8_t)(fx >> 8);
159 
160     unsigned ma = SmallDot6Scale(a, mod64);
161     if (ma) {
162         blitter->blitV(x, y, stopy - y, ApplyGamma(gGammaTable, ma));
163     }
164     ma = SmallDot6Scale(255 - a, mod64);
165     if (ma) {
166         blitter->blitV(x - 1, y, stopy - y, ApplyGamma(gGammaTable, ma));
167     }
168 
169     return fx - SK_Fixed1/2;
170 }
171 
vertish(int y,int stopy,SkFixed fx,SkFixed dx,SkBlitter * blitter,int mod64)172 static SkFixed vertish(int y, int stopy, SkFixed fx, SkFixed dx,
173                        SkBlitter* blitter, int mod64) {
174     SkASSERT(y < stopy);
175 #ifdef TEST_GAMMA
176     const uint8_t* gamma = gGammaTable;
177 #endif
178     int16_t runs[3];
179     uint8_t  aa[2];
180 
181     runs[0] = 1;
182     runs[2] = 0;
183 
184     fx += SK_Fixed1/2;
185     do {
186         int x = fx >> 16;
187         uint8_t  a = (uint8_t)(fx >> 8);
188 
189         aa[0] = ApplyGamma(gamma, SmallDot6Scale(255 - a, mod64));
190         aa[1] = ApplyGamma(gamma, SmallDot6Scale(a, mod64));
191         // the clippng blitters might overwrite this guy, so we have to reset it each time
192         runs[1] = 1;
193         blitter->blitAntiH(x - 1, y, aa, runs);
194         // the clipping blitters might edit runs, but should not affect us
195         SkASSERT(runs[0] == 1);
196         SkASSERT(runs[2] == 0);
197         fx += dx;
198     } while (++y < stopy);
199 
200     return fx - SK_Fixed1/2;
201 }
202 
203 typedef SkFixed (*LineProc)(int istart, int istop, SkFixed fstart,
204                             SkFixed slope, SkBlitter*, int);
205 
fastfixdiv(SkFDot6 a,SkFDot6 b)206 static inline SkFixed fastfixdiv(SkFDot6 a, SkFDot6 b) {
207     SkASSERT((a << 16 >> 16) == a);
208     SkASSERT(b != 0);
209     return (a << 16) / b;
210 }
211 
do_anti_hairline(SkFDot6 x0,SkFDot6 y0,SkFDot6 x1,SkFDot6 y1,const SkIRect * clip,SkBlitter * blitter)212 static void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1,
213                              const SkIRect* clip, SkBlitter* blitter) {
214     // check that we're no larger than 511 pixels (so we can do a faster div).
215     // if we are, subdivide and call again
216 
217     if (SkAbs32(x1 - x0) > SkIntToFDot6(511) || SkAbs32(y1 - y0) > SkIntToFDot6(511)) {
218         /*  instead of (x0 + x1) >> 1, we shift each separately. This is less
219             precise, but avoids overflowing the intermediate result if the
220             values are huge. A better fix might be to clip the original pts
221             directly (i.e. do the divide), so we don't spend time subdividing
222             huge lines at all.
223          */
224         int hx = (x0 >> 1) + (x1 >> 1);
225         int hy = (y0 >> 1) + (y1 >> 1);
226         do_anti_hairline(x0, y0, hx, hy, clip, blitter);
227         do_anti_hairline(hx, hy, x1, y1, clip, blitter);
228         return;
229     }
230 
231     int         scaleStart, scaleStop;
232     int         istart, istop;
233     SkFixed     fstart, slope;
234     LineProc    proc;
235 
236     if (SkAbs32(x1 - x0) > SkAbs32(y1 - y0)) {   // mostly horizontal
237         if (x0 > x1) {    // we want to go left-to-right
238             SkTSwap<SkFDot6>(x0, x1);
239             SkTSwap<SkFDot6>(y0, y1);
240         }
241 
242         istart = SkFDot6Floor(x0);
243         istop = SkFDot6Ceil(x1);
244         fstart = SkFDot6ToFixed(y0);
245         if (y0 == y1) {   // completely horizontal, take fast case
246             slope = 0;
247             proc = hline;
248         } else {
249             slope = fastfixdiv(y1 - y0, x1 - x0);
250             SkASSERT(slope >= -SK_Fixed1 && slope <= SK_Fixed1);
251             fstart += (slope * (32 - (x0 & 63)) + 32) >> 6;
252             proc = horish;
253         }
254 
255         SkASSERT(istop > istart);
256         if (istop - istart == 1) {
257             scaleStart = x1 - x0;
258             SkASSERT(scaleStart >= 0 && scaleStart <= 64);
259             scaleStop = 0;
260         } else {
261             scaleStart = 64 - (x0 & 63);
262             scaleStop = x1 & 63;
263         }
264 
265         if (clip){
266             if (istart >= clip->fRight || istop <= clip->fLeft) {
267                 return;
268             }
269             if (istart < clip->fLeft) {
270                 fstart += slope * (clip->fLeft - istart);
271                 istart = clip->fLeft;
272                 scaleStart = 64;
273             }
274             if (istop > clip->fRight) {
275                 istop = clip->fRight;
276                 scaleStop = 64;
277             }
278             SkASSERT(istart <= istop);
279             if (istart == istop) {
280                 return;
281             }
282             // now test if our Y values are completely inside the clip
283             int top, bottom;
284             if (slope >= 0) { // T2B
285                 top = SkFixedFloor(fstart - SK_FixedHalf);
286                 bottom = SkFixedCeil(fstart + (istop - istart - 1) * slope + SK_FixedHalf);
287             } else {           // B2T
288                 bottom = SkFixedCeil(fstart + SK_FixedHalf);
289                 top = SkFixedFloor(fstart + (istop - istart - 1) * slope - SK_FixedHalf);
290             }
291 #ifdef OUTSET_BEFORE_CLIP_TEST
292             top -= 1;
293             bottom += 1;
294 #endif
295             if (top >= clip->fBottom || bottom <= clip->fTop) {
296                 return;
297             }
298             if (clip->fTop <= top && clip->fBottom >= bottom) {
299                 clip = NULL;
300             }
301         }
302     } else {   // mostly vertical
303         if (y0 > y1) {  // we want to go top-to-bottom
304             SkTSwap<SkFDot6>(x0, x1);
305             SkTSwap<SkFDot6>(y0, y1);
306         }
307 
308         istart = SkFDot6Floor(y0);
309         istop = SkFDot6Ceil(y1);
310         fstart = SkFDot6ToFixed(x0);
311         if (x0 == x1) {
312             if (y0 == y1) { // are we zero length?
313                 return;     // nothing to do
314             }
315             slope = 0;
316             proc = vline;
317         } else {
318             slope = fastfixdiv(x1 - x0, y1 - y0);
319             SkASSERT(slope <= SK_Fixed1 && slope >= -SK_Fixed1);
320             fstart += (slope * (32 - (y0 & 63)) + 32) >> 6;
321             proc = vertish;
322         }
323 
324         SkASSERT(istop > istart);
325         if (istop - istart == 1) {
326             scaleStart = y1 - y0;
327             SkASSERT(scaleStart >= 0 && scaleStart <= 64);
328             scaleStop = 0;
329         } else {
330             scaleStart = 64 - (y0 & 63);
331             scaleStop = y1 & 63;
332         }
333 
334         if (clip) {
335             if (istart >= clip->fBottom || istop <= clip->fTop) {
336                 return;
337             }
338             if (istart < clip->fTop) {
339                 fstart += slope * (clip->fTop - istart);
340                 istart = clip->fTop;
341                 scaleStart = 64;
342             }
343             if (istop > clip->fBottom) {
344                 istop = clip->fBottom;
345                 scaleStop = 64;
346             }
347             SkASSERT(istart <= istop);
348             if (istart == istop)
349                 return;
350 
351             // now test if our X values are completely inside the clip
352             int left, right;
353             if (slope >= 0) { // L2R
354                 left = SkFixedFloor(fstart - SK_FixedHalf);
355                 right = SkFixedCeil(fstart + (istop - istart - 1) * slope + SK_FixedHalf);
356             } else {           // R2L
357                 right = SkFixedCeil(fstart + SK_FixedHalf);
358                 left = SkFixedFloor(fstart + (istop - istart - 1) * slope - SK_FixedHalf);
359             }
360 #ifdef OUTSET_BEFORE_CLIP_TEST
361             left -= 1;
362             right += 1;
363 #endif
364             if (left >= clip->fRight || right <= clip->fLeft) {
365                 return;
366             }
367             if (clip->fLeft <= left && clip->fRight >= right) {
368                 clip = NULL;
369             }
370         }
371     }
372 
373     SkRectClipBlitter   rectClipper;
374     if (clip) {
375         rectClipper.init(blitter, *clip);
376         blitter = &rectClipper;
377     }
378 
379     fstart = proc(istart, istart + 1, fstart, slope, blitter, scaleStart);
380     istart += 1;
381     int fullSpans = istop - istart - (scaleStop > 0);
382     if (fullSpans > 0) {
383         fstart = proc(istart, istart + fullSpans, fstart, slope, blitter, 64);
384     }
385     if (scaleStop > 0) {
386         proc(istop - 1, istop, fstart, slope, blitter, scaleStop);
387     }
388 }
389 
AntiHairLineRgn(const SkPoint & pt0,const SkPoint & pt1,const SkRegion * clip,SkBlitter * blitter)390 void SkScan::AntiHairLineRgn(const SkPoint& pt0, const SkPoint& pt1,
391                              const SkRegion* clip, SkBlitter* blitter) {
392     if (clip && clip->isEmpty()) {
393         return;
394     }
395 
396     SkASSERT(clip == NULL || !clip->getBounds().isEmpty());
397 
398 #ifdef TEST_GAMMA
399     build_gamma_table();
400 #endif
401 
402     SkPoint pts[2] = { pt0, pt1 };
403 
404     if (clip) {
405         SkRect clipBounds;
406         clipBounds.set(clip->getBounds());
407         /*  We perform integral clipping later on, but we do a scalar clip first
408             to ensure that our coordinates are expressible in fixed/integers.
409 
410             antialiased hairlines can draw up to 1/2 of a pixel outside of
411             their bounds, so we need to outset the clip before calling the
412             clipper. To make the numerics safer, we outset by a whole pixel,
413             since the 1/2 pixel boundary is important to the antihair blitter,
414             we don't want to risk numerical fate by chopping on that edge.
415          */
416         clipBounds.inset(-SK_Scalar1, -SK_Scalar1);
417 
418         if (!SkLineClipper::IntersectLine(pts, clipBounds, pts)) {
419             return;
420         }
421     }
422 
423     SkFDot6 x0 = SkScalarToFDot6(pts[0].fX);
424     SkFDot6 y0 = SkScalarToFDot6(pts[0].fY);
425     SkFDot6 x1 = SkScalarToFDot6(pts[1].fX);
426     SkFDot6 y1 = SkScalarToFDot6(pts[1].fY);
427 
428     if (clip) {
429         SkFDot6 left = SkMin32(x0, x1);
430         SkFDot6 top = SkMin32(y0, y1);
431         SkFDot6 right = SkMax32(x0, x1);
432         SkFDot6 bottom = SkMax32(y0, y1);
433         SkIRect ir;
434 
435         ir.set( SkFDot6Floor(left) - 1,
436                 SkFDot6Floor(top) - 1,
437                 SkFDot6Ceil(right) + 1,
438                 SkFDot6Ceil(bottom) + 1);
439 
440         if (clip->quickReject(ir)) {
441             return;
442         }
443         if (!clip->quickContains(ir)) {
444             SkRegion::Cliperator iter(*clip, ir);
445             const SkIRect*       r = &iter.rect();
446 
447             while (!iter.done()) {
448                 do_anti_hairline(x0, y0, x1, y1, r, blitter);
449                 iter.next();
450             }
451             return;
452         }
453         // fall through to no-clip case
454     }
455     do_anti_hairline(x0, y0, x1, y1, NULL, blitter);
456 }
457 
AntiHairRect(const SkRect & rect,const SkRasterClip & clip,SkBlitter * blitter)458 void SkScan::AntiHairRect(const SkRect& rect, const SkRasterClip& clip,
459                           SkBlitter* blitter) {
460     SkPoint p0, p1;
461 
462     p0.set(rect.fLeft, rect.fTop);
463     p1.set(rect.fRight, rect.fTop);
464     SkScan::AntiHairLine(p0, p1, clip, blitter);
465     p0.set(rect.fRight, rect.fBottom);
466     SkScan::AntiHairLine(p0, p1, clip, blitter);
467     p1.set(rect.fLeft, rect.fBottom);
468     SkScan::AntiHairLine(p0, p1, clip, blitter);
469     p0.set(rect.fLeft, rect.fTop);
470     SkScan::AntiHairLine(p0, p1, clip, blitter);
471 }
472 
473 ///////////////////////////////////////////////////////////////////////////////
474 
475 typedef int FDot8;  // 24.8 integer fixed point
476 
SkFixedToFDot8(SkFixed x)477 static inline FDot8 SkFixedToFDot8(SkFixed x) {
478     return (x + 0x80) >> 8;
479 }
480 
do_scanline(FDot8 L,int top,FDot8 R,U8CPU alpha,SkBlitter * blitter)481 static void do_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha,
482                         SkBlitter* blitter) {
483     SkASSERT(L < R);
484 
485     if ((L >> 8) == ((R - 1) >> 8)) {  // 1x1 pixel
486         blitter->blitV(L >> 8, top, 1, SkAlphaMul(alpha, R - L));
487         return;
488     }
489 
490     int left = L >> 8;
491 
492     if (L & 0xFF) {
493         blitter->blitV(left, top, 1, SkAlphaMul(alpha, 256 - (L & 0xFF)));
494         left += 1;
495     }
496 
497     int rite = R >> 8;
498     int width = rite - left;
499     if (width > 0) {
500         call_hline_blitter(blitter, left, top, width, alpha);
501     }
502     if (R & 0xFF) {
503         blitter->blitV(rite, top, 1, SkAlphaMul(alpha, R & 0xFF));
504     }
505 }
506 
antifilldot8(FDot8 L,FDot8 T,FDot8 R,FDot8 B,SkBlitter * blitter,bool fillInner)507 static void antifilldot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B, SkBlitter* blitter,
508                          bool fillInner) {
509     // check for empty now that we're in our reduced precision space
510     if (L >= R || T >= B) {
511         return;
512     }
513     int top = T >> 8;
514     if (top == ((B - 1) >> 8)) {   // just one scanline high
515         do_scanline(L, top, R, B - T - 1, blitter);
516         return;
517     }
518 
519     if (T & 0xFF) {
520         do_scanline(L, top, R, 256 - (T & 0xFF), blitter);
521         top += 1;
522     }
523 
524     int bot = B >> 8;
525     int height = bot - top;
526     if (height > 0) {
527         int left = L >> 8;
528         if (left == ((R - 1) >> 8)) {   // just 1-pixel wide
529             blitter->blitV(left, top, height, R - L - 1);
530         } else {
531             if (L & 0xFF) {
532                 blitter->blitV(left, top, height, 256 - (L & 0xFF));
533                 left += 1;
534             }
535             int rite = R >> 8;
536             int width = rite - left;
537             if (width > 0 && fillInner) {
538                 blitter->blitRect(left, top, width, height);
539             }
540             if (R & 0xFF) {
541                 blitter->blitV(rite, top, height, R & 0xFF);
542             }
543         }
544     }
545 
546     if (B & 0xFF) {
547         do_scanline(L, bot, R, B & 0xFF, blitter);
548     }
549 }
550 
antifillrect(const SkXRect & xr,SkBlitter * blitter)551 static void antifillrect(const SkXRect& xr, SkBlitter* blitter) {
552     antifilldot8(SkFixedToFDot8(xr.fLeft), SkFixedToFDot8(xr.fTop),
553                  SkFixedToFDot8(xr.fRight), SkFixedToFDot8(xr.fBottom),
554                  blitter, true);
555 }
556 
557 ///////////////////////////////////////////////////////////////////////////////
558 
AntiFillXRect(const SkXRect & xr,const SkRegion * clip,SkBlitter * blitter)559 void SkScan::AntiFillXRect(const SkXRect& xr, const SkRegion* clip,
560                           SkBlitter* blitter) {
561     if (NULL == clip) {
562         antifillrect(xr, blitter);
563     } else {
564         SkIRect outerBounds;
565         XRect_roundOut(xr, &outerBounds);
566 
567         if (clip->isRect()) {
568             const SkIRect& clipBounds = clip->getBounds();
569 
570             if (clipBounds.contains(outerBounds)) {
571                 antifillrect(xr, blitter);
572             } else {
573                 SkXRect tmpR;
574                 // this keeps our original edges fractional
575                 XRect_set(&tmpR, clipBounds);
576                 if (tmpR.intersect(xr)) {
577                     antifillrect(tmpR, blitter);
578                 }
579             }
580         } else {
581             SkRegion::Cliperator clipper(*clip, outerBounds);
582             const SkIRect&       rr = clipper.rect();
583 
584             while (!clipper.done()) {
585                 SkXRect  tmpR;
586 
587                 // this keeps our original edges fractional
588                 XRect_set(&tmpR, rr);
589                 if (tmpR.intersect(xr)) {
590                     antifillrect(tmpR, blitter);
591                 }
592                 clipper.next();
593             }
594         }
595     }
596 }
597 
AntiFillXRect(const SkXRect & xr,const SkRasterClip & clip,SkBlitter * blitter)598 void SkScan::AntiFillXRect(const SkXRect& xr, const SkRasterClip& clip,
599                            SkBlitter* blitter) {
600     if (clip.isBW()) {
601         AntiFillXRect(xr, &clip.bwRgn(), blitter);
602     } else {
603         SkIRect outerBounds;
604         XRect_roundOut(xr, &outerBounds);
605 
606         if (clip.quickContains(outerBounds)) {
607             AntiFillXRect(xr, NULL, blitter);
608         } else {
609             SkAAClipBlitterWrapper wrapper(clip, blitter);
610             blitter = wrapper.getBlitter();
611 
612             AntiFillXRect(xr, &wrapper.getRgn(), wrapper.getBlitter());
613         }
614     }
615 }
616 
617 #ifdef SK_SCALAR_IS_FLOAT
618 
619 /*  This guy takes a float-rect, but with the key improvement that it has
620     already been clipped, so we know that it is safe to convert it into a
621     XRect (fixedpoint), as it won't overflow.
622 */
antifillrect(const SkRect & r,SkBlitter * blitter)623 static void antifillrect(const SkRect& r, SkBlitter* blitter) {
624     SkXRect xr;
625 
626     XRect_set(&xr, r);
627     antifillrect(xr, blitter);
628 }
629 
630 /*  We repeat the clipping logic of AntiFillXRect because the float rect might
631     overflow if we blindly converted it to an XRect. This sucks that we have to
632     repeat the clipping logic, but I don't see how to share the code/logic.
633 
634     We clip r (as needed) into one or more (smaller) float rects, and then pass
635     those to our version of antifillrect, which converts it into an XRect and
636     then calls the blit.
637 */
AntiFillRect(const SkRect & origR,const SkRegion * clip,SkBlitter * blitter)638 void SkScan::AntiFillRect(const SkRect& origR, const SkRegion* clip,
639                           SkBlitter* blitter) {
640     if (clip) {
641         SkRect newR;
642         newR.set(clip->getBounds());
643         if (!newR.intersect(origR)) {
644             return;
645         }
646 
647         SkIRect outerBounds;
648         newR.roundOut(&outerBounds);
649 
650         if (clip->isRect()) {
651             antifillrect(newR, blitter);
652         } else {
653             SkRegion::Cliperator clipper(*clip, outerBounds);
654             while (!clipper.done()) {
655                 newR.set(clipper.rect());
656                 if (newR.intersect(origR)) {
657                     antifillrect(newR, blitter);
658                 }
659                 clipper.next();
660             }
661         }
662     } else {
663         antifillrect(origR, blitter);
664     }
665 }
666 
AntiFillRect(const SkRect & r,const SkRasterClip & clip,SkBlitter * blitter)667 void SkScan::AntiFillRect(const SkRect& r, const SkRasterClip& clip,
668                           SkBlitter* blitter) {
669     if (clip.isBW()) {
670         AntiFillRect(r, &clip.bwRgn(), blitter);
671     } else {
672         SkAAClipBlitterWrapper wrap(clip, blitter);
673         AntiFillRect(r, &wrap.getRgn(), wrap.getBlitter());
674     }
675 }
676 
677 #endif // SK_SCALAR_IS_FLOAT
678 
679 ///////////////////////////////////////////////////////////////////////////////
680 
681 #define SkAlphaMulRound(a, b)   SkMulDiv255Round(a, b)
682 
683 // calls blitRect() if the rectangle is non-empty
fillcheckrect(int L,int T,int R,int B,SkBlitter * blitter)684 static void fillcheckrect(int L, int T, int R, int B, SkBlitter* blitter) {
685     if (L < R && T < B) {
686         blitter->blitRect(L, T, R - L, B - T);
687     }
688 }
689 
SkScalarToFDot8(SkScalar x)690 static inline FDot8 SkScalarToFDot8(SkScalar x) {
691 #ifdef SK_SCALAR_IS_FLOAT
692     return (int)(x * 256);
693 #else
694     return x >> 8;
695 #endif
696 }
697 
FDot8Floor(FDot8 x)698 static inline int FDot8Floor(FDot8 x) {
699     return x >> 8;
700 }
701 
FDot8Ceil(FDot8 x)702 static inline int FDot8Ceil(FDot8 x) {
703     return (x + 0xFF) >> 8;
704 }
705 
706 // 1 - (1 - a)*(1 - b)
InvAlphaMul(U8CPU a,U8CPU b)707 static inline U8CPU InvAlphaMul(U8CPU a, U8CPU b) {
708     // need precise rounding (not just SkAlphaMul) so that values like
709     // a=228, b=252 don't overflow the result
710     return SkToU8(a + b - SkAlphaMulRound(a, b));
711 }
712 
inner_scanline(FDot8 L,int top,FDot8 R,U8CPU alpha,SkBlitter * blitter)713 static void inner_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha,
714                            SkBlitter* blitter) {
715     SkASSERT(L < R);
716 
717     if ((L >> 8) == ((R - 1) >> 8)) {  // 1x1 pixel
718         blitter->blitV(L >> 8, top, 1, InvAlphaMul(alpha, R - L));
719         return;
720     }
721 
722     int left = L >> 8;
723     if (L & 0xFF) {
724         blitter->blitV(left, top, 1, InvAlphaMul(alpha, L & 0xFF));
725         left += 1;
726     }
727 
728     int rite = R >> 8;
729     int width = rite - left;
730     if (width > 0) {
731         call_hline_blitter(blitter, left, top, width, alpha);
732     }
733 
734     if (R & 0xFF) {
735         blitter->blitV(rite, top, 1, InvAlphaMul(alpha, ~R & 0xFF));
736     }
737 }
738 
innerstrokedot8(FDot8 L,FDot8 T,FDot8 R,FDot8 B,SkBlitter * blitter)739 static void innerstrokedot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B,
740                             SkBlitter* blitter) {
741     SkASSERT(L < R && T < B);
742 
743     int top = T >> 8;
744     if (top == ((B - 1) >> 8)) {   // just one scanline high
745         inner_scanline(L, top, R, B - T, blitter);
746         return;
747     }
748 
749     if (T & 0xFF) {
750         inner_scanline(L, top, R, T & 0xFF, blitter);
751         top += 1;
752     }
753 
754     int bot = B >> 8;
755     int height = bot - top;
756     if (height > 0) {
757         if (L & 0xFF) {
758             blitter->blitV(L >> 8, top, height, L & 0xFF);
759         }
760         if (R & 0xFF) {
761             blitter->blitV(R >> 8, top, height, ~R & 0xFF);
762         }
763     }
764 
765     if (B & 0xFF) {
766         inner_scanline(L, bot, R, ~B & 0xFF, blitter);
767     }
768 }
769 
AntiFrameRect(const SkRect & r,const SkPoint & strokeSize,const SkRegion * clip,SkBlitter * blitter)770 void SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize,
771                            const SkRegion* clip, SkBlitter* blitter) {
772     SkASSERT(strokeSize.fX >= 0 && strokeSize.fY >= 0);
773 
774     SkScalar rx = SkScalarHalf(strokeSize.fX);
775     SkScalar ry = SkScalarHalf(strokeSize.fY);
776 
777     // outset by the radius
778     FDot8 L = SkScalarToFDot8(r.fLeft - rx);
779     FDot8 T = SkScalarToFDot8(r.fTop - ry);
780     FDot8 R = SkScalarToFDot8(r.fRight + rx);
781     FDot8 B = SkScalarToFDot8(r.fBottom + ry);
782 
783     SkIRect outer;
784     // set outer to the outer rect of the outer section
785     outer.set(FDot8Floor(L), FDot8Floor(T), FDot8Ceil(R), FDot8Ceil(B));
786 
787     SkBlitterClipper clipper;
788     if (clip) {
789         if (clip->quickReject(outer)) {
790             return;
791         }
792         if (!clip->contains(outer)) {
793             blitter = clipper.apply(blitter, clip, &outer);
794         }
795         // now we can ignore clip for the rest of the function
796     }
797 
798     // stroke the outer hull
799     antifilldot8(L, T, R, B, blitter, false);
800 
801     // set outer to the outer rect of the middle section
802     outer.set(FDot8Ceil(L), FDot8Ceil(T), FDot8Floor(R), FDot8Floor(B));
803 
804     // in case we lost a bit with diameter/2
805     rx = strokeSize.fX - rx;
806     ry = strokeSize.fY - ry;
807     // inset by the radius
808     L = SkScalarToFDot8(r.fLeft + rx);
809     T = SkScalarToFDot8(r.fTop + ry);
810     R = SkScalarToFDot8(r.fRight - rx);
811     B = SkScalarToFDot8(r.fBottom - ry);
812 
813     if (L >= R || T >= B) {
814         fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, outer.fBottom,
815                       blitter);
816     } else {
817         SkIRect inner;
818         // set inner to the inner rect of the middle section
819         inner.set(FDot8Floor(L), FDot8Floor(T), FDot8Ceil(R), FDot8Ceil(B));
820 
821         // draw the frame in 4 pieces
822         fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, inner.fTop,
823                       blitter);
824         fillcheckrect(outer.fLeft, inner.fTop, inner.fLeft, inner.fBottom,
825                       blitter);
826         fillcheckrect(inner.fRight, inner.fTop, outer.fRight, inner.fBottom,
827                       blitter);
828         fillcheckrect(outer.fLeft, inner.fBottom, outer.fRight, outer.fBottom,
829                       blitter);
830 
831         // now stroke the inner rect, which is similar to antifilldot8() except that
832         // it treats the fractional coordinates with the inverse bias (since its
833         // inner).
834         innerstrokedot8(L, T, R, B, blitter);
835     }
836 }
837 
AntiFrameRect(const SkRect & r,const SkPoint & strokeSize,const SkRasterClip & clip,SkBlitter * blitter)838 void SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize,
839                            const SkRasterClip& clip, SkBlitter* blitter) {
840     if (clip.isBW()) {
841         AntiFrameRect(r, strokeSize, &clip.bwRgn(), blitter);
842     } else {
843         SkAAClipBlitterWrapper wrap(clip, blitter);
844         AntiFrameRect(r, strokeSize, &wrap.getRgn(), wrap.getBlitter());
845     }
846 }
847 
848