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