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