1685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com
2685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com/*
3685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Copyright 2011 The Android Open Source Project
4685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com *
5685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * found in the LICENSE file.
7685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com */
8685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com
9bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
10bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkScan.h"
11bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkBlitter.h"
12bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkColorPriv.h"
139005874dcc2a962acd88141f7e0ade7ada472babreed@android.com#include "SkLineClipper.h"
1426f5a398c38318eb7eab44f72e024ef784d247fareed@google.com#include "SkRasterClip.h"
15bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkFDot6.h"
16bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
17accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com/*  Our attempt to compute the worst case "bounds" for the horizontal and
18accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com    vertical cases has some numerical bug in it, and we sometimes undervalue
19accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com    our extends. The bug is that when this happens, we will set the clip to
20accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com    NULL (for speed), and thus draw outside of the clip by a pixel, which might
21accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com    only look bad, but it might also access memory outside of the valid range
22accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com    allcoated for the device bitmap.
2317f6e4bba20b6542cdf0a4fb0442a7f330003ee4reed@android.com
24accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com    This define enables our fix to outset our "bounds" by 1, thus avoiding the
25accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com    chance of the bug, but at the cost of sometimes taking the rectblitter
26accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com    case (i.e. not setting the clip to NULL) when we might not actually need
27accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com    to. If we can improve/fix the actual calculations, then we can remove this
28accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com    step.
29accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com */
30accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com#define OUTSET_BEFORE_CLIP_TEST     true
31accfc74bb5e66bc8e75ee66d83de9f64d14154e5reed@android.com
32bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define HLINE_STACK_BUFFER      100
33bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
34bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic inline int SmallDot6Scale(int value, int dot6) {
35bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT((int16_t)value == value);
36bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT((unsigned)dot6 <= 64);
37bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return SkMulS16(value, dot6) >> 6;
38bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
39bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
40bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com//#define TEST_GAMMA
41bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
42bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef TEST_GAMMA
43bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    static uint8_t gGammaTable[256];
44bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    #define ApplyGamma(table, alpha)    (table)[alpha]
45bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
463d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org    static void build_gamma_table() {
47bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        static bool gInit = false;
48bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
493d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org        if (gInit == false) {
503d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org            for (int i = 0; i < 256; i++) {
51bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                SkFixed n = i * 257;
52bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                n += n >> 15;
53bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                SkASSERT(n >= 0 && n <= SK_Fixed1);
54bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                n = SkFixedSqrt(n);
55bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                n = n * 255 >> 16;
56bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            //  SkDebugf("morph %d -> %d\n", i, n);
57bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                gGammaTable[i] = SkToU8(n);
58bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
59bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            gInit = true;
60bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
61bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
62bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#else
63bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    #define ApplyGamma(table, alpha)    SkToU8(alpha)
64bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif
65bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
66bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com///////////////////////////////////////////////////////////////////////////////
67bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
683d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.orgstatic void call_hline_blitter(SkBlitter* blitter, int x, int y, int count,
693d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org                               U8CPU alpha) {
70bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(count > 0);
716d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
72bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int16_t runs[HLINE_STACK_BUFFER + 1];
73bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    uint8_t  aa[HLINE_STACK_BUFFER];
746d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
75bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    aa[0] = ApplyGamma(gGammaTable, alpha);
76bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    do {
77bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        int n = count;
783d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org        if (n > HLINE_STACK_BUFFER) {
79bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            n = HLINE_STACK_BUFFER;
803d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org        }
81bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        runs[0] = SkToS16(n);
82bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        runs[n] = 0;
83bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        blitter->blitAntiH(x, y, aa, runs);
84bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        x += n;
85bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        count -= n;
86bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    } while (count > 0);
87bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
88bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
8937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.comclass SkAntiHairBlitter {
9037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.compublic:
9137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    SkAntiHairBlitter() : fBlitter(NULL) {}
92c58edf5df3ce86e5ccecab3907ab7db925972c29djsollen@google.com    virtual ~SkAntiHairBlitter() {}
93bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
9437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    SkBlitter* getBlitter() const { return fBlitter; }
95bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
9637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    void setup(SkBlitter* blitter) {
9737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        fBlitter = blitter;
98bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
99bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
10037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    virtual SkFixed drawCap(int x, SkFixed fy, SkFixed slope, int mod64) = 0;
10137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    virtual SkFixed drawLine(int x, int stopx, SkFixed fy, SkFixed slope) = 0;
102935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
10337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.comprivate:
10437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    SkBlitter*  fBlitter;
10537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com};
106bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
10737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.comclass HLine_SkAntiHairBlitter : public SkAntiHairBlitter {
10837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.compublic:
10937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    virtual SkFixed drawCap(int x, SkFixed fy, SkFixed slope, int mod64) SK_OVERRIDE {
11037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        fy += SK_Fixed1/2;
1116d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
11237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        int y = fy >> 16;
11337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        uint8_t  a = (uint8_t)(fy >> 8);
1146d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
11537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        // lower line
11637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        unsigned ma = SmallDot6Scale(a, mod64);
11737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        if (ma) {
11837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            call_hline_blitter(this->getBlitter(), x, y, 1, ma);
11937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        }
1206d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
12137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        // upper line
12237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        ma = SmallDot6Scale(255 - a, mod64);
12337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        if (ma) {
12437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            call_hline_blitter(this->getBlitter(), x, y - 1, 1, ma);
12537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        }
1266d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
12737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        return fy - SK_Fixed1/2;
12837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    }
129bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
13037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    virtual SkFixed drawLine(int x, int stopx, SkFixed fy,
13137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com                             SkFixed slope) SK_OVERRIDE {
13237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        SkASSERT(x < stopx);
13337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        int count = stopx - x;
13437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        fy += SK_Fixed1/2;
1356d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
13637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        int y = fy >> 16;
13737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        uint8_t  a = (uint8_t)(fy >> 8);
1386d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
13937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        // lower line
14037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        if (a) {
14137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            call_hline_blitter(this->getBlitter(), x, y, count, a);
14237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        }
1436d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
14437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        // upper line
14537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        a = 255 - a;
14637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        if (a) {
14737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            call_hline_blitter(this->getBlitter(), x, y - 1, count, a);
14837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        }
1496d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
15037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        return fy - SK_Fixed1/2;
15137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    }
15237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com};
15337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com
15437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.comclass Horish_SkAntiHairBlitter : public SkAntiHairBlitter {
15537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.compublic:
15637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    virtual SkFixed drawCap(int x, SkFixed fy, SkFixed dy, int mod64) SK_OVERRIDE {
15737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        int16_t runs[2];
15837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        uint8_t  aa[1];
1596d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
16037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        runs[0] = 1;
16137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        runs[1] = 0;
1626d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
16337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        fy += SK_Fixed1/2;
16437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        SkBlitter* blitter = this->getBlitter();
165bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
166bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        int lower_y = fy >> 16;
167bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        uint8_t  a = (uint8_t)(fy >> 8);
168bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        unsigned ma = SmallDot6Scale(a, mod64);
1693d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org        if (ma) {
170bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            aa[0] = ApplyGamma(gamma, ma);
171bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            blitter->blitAntiH(x, lower_y, aa, runs);
172bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            // the clipping blitters might edit runs, but should not affect us
173bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkASSERT(runs[0] == 1);
174bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkASSERT(runs[1] == 0);
175bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
176bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        ma = SmallDot6Scale(255 - a, mod64);
1773d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org        if (ma) {
178bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            aa[0] = ApplyGamma(gamma, ma);
179bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            blitter->blitAntiH(x, lower_y - 1, aa, runs);
180bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            // the clipping blitters might edit runs, but should not affect us
181bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkASSERT(runs[0] == 1);
182bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkASSERT(runs[1] == 0);
183bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
184bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fy += dy;
1856d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
18637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        return fy - SK_Fixed1/2;
1873d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org    }
1886d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
18937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    virtual SkFixed drawLine(int x, int stopx, SkFixed fy, SkFixed dy) SK_OVERRIDE {
19037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        SkASSERT(x < stopx);
1916d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
19237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        int16_t runs[2];
19337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        uint8_t  aa[1];
1946d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
19537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        runs[0] = 1;
19637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        runs[1] = 0;
1976d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
19837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        fy += SK_Fixed1/2;
19937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        SkBlitter* blitter = this->getBlitter();
20037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        do {
20137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            int lower_y = fy >> 16;
20237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            uint8_t  a = (uint8_t)(fy >> 8);
20337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            if (a) {
20437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com                aa[0] = a;
20537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com                blitter->blitAntiH(x, lower_y, aa, runs);
20637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com                // the clipping blitters might edit runs, but should not affect us
20737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com                SkASSERT(runs[0] == 1);
20837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com                SkASSERT(runs[1] == 0);
20937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            }
21037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            a = 255 - a;
21137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            if (a) {
21237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com                aa[0] = a;
21337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com                blitter->blitAntiH(x, lower_y - 1, aa, runs);
21437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com                // the clipping blitters might edit runs, but should not affect us
21537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com                SkASSERT(runs[0] == 1);
21637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com                SkASSERT(runs[1] == 0);
21737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            }
21837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            fy += dy;
21937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        } while (++x < stopx);
2206d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
22137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        return fy - SK_Fixed1/2;
22237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    }
22337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com};
22437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com
22537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.comclass VLine_SkAntiHairBlitter : public SkAntiHairBlitter {
22637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.compublic:
22737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    virtual SkFixed drawCap(int y, SkFixed fx, SkFixed dx, int mod64) SK_OVERRIDE {
22837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        SkASSERT(0 == dx);
22937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        fx += SK_Fixed1/2;
2306d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
23137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        int x = fx >> 16;
23237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        int a = (uint8_t)(fx >> 8);
2336d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
23437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        unsigned ma = SmallDot6Scale(a, mod64);
23537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        if (ma) {
23637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            this->getBlitter()->blitV(x, y, 1, ma);
23737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        }
23837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        ma = SmallDot6Scale(255 - a, mod64);
23937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        if (ma) {
24037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            this->getBlitter()->blitV(x - 1, y, 1, ma);
24137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        }
2426d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
24337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        return fx - SK_Fixed1/2;
2443d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org    }
245935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
24637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    virtual SkFixed drawLine(int y, int stopy, SkFixed fx, SkFixed dx) SK_OVERRIDE {
24737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        SkASSERT(y < stopy);
24837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        SkASSERT(0 == dx);
24937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        fx += SK_Fixed1/2;
2506d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
25137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        int x = fx >> 16;
25237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        int a = (uint8_t)(fx >> 8);
2536d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
25437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        if (a) {
25537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            this->getBlitter()->blitV(x, y, stopy - y, a);
25637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        }
25737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        a = 255 - a;
25837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        if (a) {
25937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            this->getBlitter()->blitV(x - 1, y, stopy - y, a);
26037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        }
2616d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
26237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        return fx - SK_Fixed1/2;
26337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    }
26437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com};
26537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com
26637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.comclass Vertish_SkAntiHairBlitter : public SkAntiHairBlitter {
26737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.compublic:
26837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    virtual SkFixed drawCap(int y, SkFixed fx, SkFixed dx, int mod64) SK_OVERRIDE {
26937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        int16_t runs[3];
27037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        uint8_t  aa[2];
2716d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
27237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        runs[0] = 1;
27337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        runs[2] = 0;
2746d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
27537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        fx += SK_Fixed1/2;
276bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        int x = fx >> 16;
277bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        uint8_t  a = (uint8_t)(fx >> 8);
2786d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
27937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        aa[0] = SmallDot6Scale(255 - a, mod64);
28037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        aa[1] = SmallDot6Scale(a, mod64);
281bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // the clippng blitters might overwrite this guy, so we have to reset it each time
282bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        runs[1] = 1;
28337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        this->getBlitter()->blitAntiH(x - 1, y, aa, runs);
284bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // the clipping blitters might edit runs, but should not affect us
285bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkASSERT(runs[0] == 1);
286bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkASSERT(runs[2] == 0);
287bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fx += dx;
2886d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
28937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        return fx - SK_Fixed1/2;
29037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    }
2916d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
29237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    virtual SkFixed drawLine(int y, int stopy, SkFixed fx, SkFixed dx) SK_OVERRIDE {
29337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        SkASSERT(y < stopy);
29437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        int16_t runs[3];
29537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        uint8_t  aa[2];
2966d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
29737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        runs[0] = 1;
29837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        runs[2] = 0;
2996d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
30037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        fx += SK_Fixed1/2;
30137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        do {
30237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            int x = fx >> 16;
30337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            uint8_t  a = (uint8_t)(fx >> 8);
3046d15c6d8f421912418e084851fc0189f6a9961b6skia.committer@gmail.com
30537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            aa[0] = 255 - a;
30637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            aa[1] = a;
30737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            // the clippng blitters might overwrite this guy, so we have to reset it each time
30837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            runs[1] = 1;
30937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            this->getBlitter()->blitAntiH(x - 1, y, aa, runs);
31037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            // the clipping blitters might edit runs, but should not affect us
31137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            SkASSERT(runs[0] == 1);
31237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            SkASSERT(runs[2] == 0);
31337abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            fx += dx;
31437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        } while (++y < stopy);
315bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
31637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        return fx - SK_Fixed1/2;
31737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    }
31837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com};
319bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
3203d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.orgstatic inline SkFixed fastfixdiv(SkFDot6 a, SkFDot6 b) {
321bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT((a << 16 >> 16) == a);
322bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(b != 0);
323bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return (a << 16) / b;
324bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
325bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
32690d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com#define SkBITCOUNT(x)   (sizeof(x) << 3)
32790d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com
32890d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com#if 1
32990d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com// returns high-bit set iff x==0x8000...
33090d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.comstatic inline int bad_int(int x) {
33190d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com    return x & -x;
33290d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com}
33390d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com
33490d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.comstatic int any_bad_ints(int a, int b, int c, int d) {
33590d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com    return (bad_int(a) | bad_int(b) | bad_int(c) | bad_int(d)) >> (SkBITCOUNT(int) - 1);
33690d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com}
33790d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com#else
33890d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.comstatic inline int good_int(int x) {
33990d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com    return x ^ (1 << (SkBITCOUNT(x) - 1));
34090d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com}
34190d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com
34290d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.comstatic int any_bad_ints(int a, int b, int c, int d) {
34390d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com    return !(good_int(a) & good_int(b) & good_int(c) & good_int(d));
34490d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com}
34590d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com#endif
34690d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com
347afcc161571327871da95761248abefeaafed40a4humper@google.com#ifdef SK_DEBUG
3481562b550f54f1adaf44f2c833a18f63555332e4dreed@google.comstatic bool canConvertFDot6ToFixed(SkFDot6 x) {
3491562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com    const int maxDot6 = SK_MaxS32 >> (16 - 6);
3501562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com    return SkAbs32(x) <= maxDot6;
3511562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com}
352afcc161571327871da95761248abefeaafed40a4humper@google.com#endif
3531562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com
354821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com/*
355821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com *  We want the fractional part of ordinate, but we want multiples of 64 to
356821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com *  return 64, not 0, so we can't just say (ordinate & 63).
357821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com *  We basically want to compute those bits, and if they're 0, return 64.
358821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com *  We can do that w/o a branch with an extra sub and add.
359821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com */
360821f3ed12741706f95f0b2fc9046139c7644e575reed@google.comstatic int contribution_64(SkFDot6 ordinate) {
361821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com#if 0
362821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com    int result = ordinate & 63;
363821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com    if (0 == result) {
364821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com        result = 64;
365821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com    }
366821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com#else
367821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com    int result = ((ordinate - 1) & 63) + 1;
368821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com#endif
369821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com    SkASSERT(result > 0 && result <= 64);
370821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com    return result;
371821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com}
372821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com
373bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1,
3743d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org                             const SkIRect* clip, SkBlitter* blitter) {
37590d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com    // check for integer NaN (0x80000000) which we can't handle (can't negate it)
37690d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com    // It appears typically from a huge float (inf or nan) being converted to int.
37790d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com    // If we see it, just don't draw.
37890d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com    if (any_bad_ints(x0, y0, x1, y1)) {
37990d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com        return;
38090d46bae16e0772fbe878dd7c943b3cc6bc68f68reed@google.com    }
381bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
3821562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com    // The caller must clip the line to [-32767.0 ... 32767.0] ahead of time
3831562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com    // (in dot6 format)
3841562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com    SkASSERT(canConvertFDot6ToFixed(x0));
3851562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com    SkASSERT(canConvertFDot6ToFixed(y0));
3861562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com    SkASSERT(canConvertFDot6ToFixed(x1));
3871562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com    SkASSERT(canConvertFDot6ToFixed(y1));
3881562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com
3893d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org    if (SkAbs32(x1 - x0) > SkIntToFDot6(511) || SkAbs32(y1 - y0) > SkIntToFDot6(511)) {
390c57897f74f960be3972e615e3a0a297c75e9126breed@android.com        /*  instead of (x0 + x1) >> 1, we shift each separately. This is less
391c57897f74f960be3972e615e3a0a297c75e9126breed@android.com            precise, but avoids overflowing the intermediate result if the
392c57897f74f960be3972e615e3a0a297c75e9126breed@android.com            values are huge. A better fix might be to clip the original pts
393c57897f74f960be3972e615e3a0a297c75e9126breed@android.com            directly (i.e. do the divide), so we don't spend time subdividing
394c57897f74f960be3972e615e3a0a297c75e9126breed@android.com            huge lines at all.
395c57897f74f960be3972e615e3a0a297c75e9126breed@android.com         */
396c57897f74f960be3972e615e3a0a297c75e9126breed@android.com        int hx = (x0 >> 1) + (x1 >> 1);
397c57897f74f960be3972e615e3a0a297c75e9126breed@android.com        int hy = (y0 >> 1) + (y1 >> 1);
398bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        do_anti_hairline(x0, y0, hx, hy, clip, blitter);
399bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        do_anti_hairline(hx, hy, x1, y1, clip, blitter);
400bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return;
401bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
402bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
403bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int         scaleStart, scaleStop;
404bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int         istart, istop;
405935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com    SkFixed     fstart, slope;
40637abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com
40737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    HLine_SkAntiHairBlitter     hline_blitter;
40837abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    Horish_SkAntiHairBlitter    horish_blitter;
40937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    VLine_SkAntiHairBlitter     vline_blitter;
41037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    Vertish_SkAntiHairBlitter   vertish_blitter;
41137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    SkAntiHairBlitter*          hairBlitter = NULL;
412bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
4133d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org    if (SkAbs32(x1 - x0) > SkAbs32(y1 - y0)) {   // mostly horizontal
414bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (x0 > x1) {    // we want to go left-to-right
415bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkTSwap<SkFDot6>(x0, x1);
416bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkTSwap<SkFDot6>(y0, y1);
417bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
418bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
419bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        istart = SkFDot6Floor(x0);
420bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        istop = SkFDot6Ceil(x1);
421bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fstart = SkFDot6ToFixed(y0);
422bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (y0 == y1) {   // completely horizontal, take fast case
423bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            slope = 0;
42437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            hairBlitter = &hline_blitter;
425bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        } else {
426bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            slope = fastfixdiv(y1 - y0, x1 - x0);
427bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkASSERT(slope >= -SK_Fixed1 && slope <= SK_Fixed1);
428bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            fstart += (slope * (32 - (x0 & 63)) + 32) >> 6;
42937abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            hairBlitter = &horish_blitter;
430bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
431935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
432bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkASSERT(istop > istart);
433bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (istop - istart == 1) {
434821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com            // we are within a single pixel
435bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            scaleStart = x1 - x0;
436bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkASSERT(scaleStart >= 0 && scaleStart <= 64);
437bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            scaleStop = 0;
438bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        } else {
439bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            scaleStart = 64 - (x0 & 63);
440bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            scaleStop = x1 & 63;
441bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
442bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
4433d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org        if (clip){
4443d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org            if (istart >= clip->fRight || istop <= clip->fLeft) {
445bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                return;
4463d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org            }
4473d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org            if (istart < clip->fLeft) {
448bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                fstart += slope * (clip->fLeft - istart);
449bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                istart = clip->fLeft;
450bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                scaleStart = 64;
451821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com                if (istop - istart == 1) {
452821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com                    // we are within a single pixel
453821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com                    scaleStart = contribution_64(x1);
454821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com                    scaleStop = 0;
455821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com                }
456bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
457731578526ef7f61b1d2acf950c21831a3a2774e6reed@google.com            if (istop > clip->fRight) {
458bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                istop = clip->fRight;
45967b43262006b7553f44959623813af46e1252edfreed@google.com                scaleStop = 0;  // so we don't draw this last column
460bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
46173b5d754f5546de3e51e7ed93f9014ed68fa4b3dreed@google.com
462bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkASSERT(istart <= istop);
4633d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org            if (istart == istop) {
464bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                return;
4653d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org            }
466bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            // now test if our Y values are completely inside the clip
467bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            int top, bottom;
4683d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org            if (slope >= 0) { // T2B
469bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                top = SkFixedFloor(fstart - SK_FixedHalf);
470bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                bottom = SkFixedCeil(fstart + (istop - istart - 1) * slope + SK_FixedHalf);
4713d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org            } else {           // B2T
472bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                bottom = SkFixedCeil(fstart + SK_FixedHalf);
473bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                top = SkFixedFloor(fstart + (istop - istart - 1) * slope - SK_FixedHalf);
474bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
47517f6e4bba20b6542cdf0a4fb0442a7f330003ee4reed@android.com#ifdef OUTSET_BEFORE_CLIP_TEST
47617f6e4bba20b6542cdf0a4fb0442a7f330003ee4reed@android.com            top -= 1;
47717f6e4bba20b6542cdf0a4fb0442a7f330003ee4reed@android.com            bottom += 1;
47817f6e4bba20b6542cdf0a4fb0442a7f330003ee4reed@android.com#endif
4793d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org            if (top >= clip->fBottom || bottom <= clip->fTop) {
480bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                return;
4813d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org            }
4823d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org            if (clip->fTop <= top && clip->fBottom >= bottom) {
483bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                clip = NULL;
4843d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org            }
485bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
4863d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org    } else {   // mostly vertical
4873d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org        if (y0 > y1) {  // we want to go top-to-bottom
488bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkTSwap<SkFDot6>(x0, x1);
489bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkTSwap<SkFDot6>(y0, y1);
490bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
491bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
492bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        istart = SkFDot6Floor(y0);
493bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        istop = SkFDot6Ceil(y1);
494bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fstart = SkFDot6ToFixed(x0);
4953d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org        if (x0 == x1) {
496bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            if (y0 == y1) { // are we zero length?
497bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                return;     // nothing to do
498bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
499bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            slope = 0;
50037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            hairBlitter = &vline_blitter;
5013d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org        } else {
502bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            slope = fastfixdiv(x1 - x0, y1 - y0);
503bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkASSERT(slope <= SK_Fixed1 && slope >= -SK_Fixed1);
504bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            fstart += (slope * (32 - (y0 & 63)) + 32) >> 6;
50537abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com            hairBlitter = &vertish_blitter;
506bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
507bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
508bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkASSERT(istop > istart);
509bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (istop - istart == 1) {
510821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com            // we are within a single pixel
511bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            scaleStart = y1 - y0;
512bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkASSERT(scaleStart >= 0 && scaleStart <= 64);
513bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            scaleStop = 0;
514bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        } else {
515bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            scaleStart = 64 - (y0 & 63);
516bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            scaleStop = y1 & 63;
517bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
518935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
5193d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org        if (clip) {
5203d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org            if (istart >= clip->fBottom || istop <= clip->fTop) {
521bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                return;
5223d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org            }
5233d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org            if (istart < clip->fTop) {
524bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                fstart += slope * (clip->fTop - istart);
525bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                istart = clip->fTop;
526bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                scaleStart = 64;
527821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com                if (istop - istart == 1) {
528821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com                    // we are within a single pixel
529821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com                    scaleStart = contribution_64(y1);
530821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com                    scaleStop = 0;
531821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com                }
532bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
533731578526ef7f61b1d2acf950c21831a3a2774e6reed@google.com            if (istop > clip->fBottom) {
534bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                istop = clip->fBottom;
53567b43262006b7553f44959623813af46e1252edfreed@google.com                scaleStop = 0;  // so we don't draw this last row
536bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
53773b5d754f5546de3e51e7ed93f9014ed68fa4b3dreed@google.com
538bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkASSERT(istart <= istop);
539bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            if (istart == istop)
540bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                return;
541bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
542bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            // now test if our X values are completely inside the clip
543bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            int left, right;
5443d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org            if (slope >= 0) { // L2R
545bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                left = SkFixedFloor(fstart - SK_FixedHalf);
546bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                right = SkFixedCeil(fstart + (istop - istart - 1) * slope + SK_FixedHalf);
5473d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org            } else {           // R2L
548bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                right = SkFixedCeil(fstart + SK_FixedHalf);
549bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                left = SkFixedFloor(fstart + (istop - istart - 1) * slope - SK_FixedHalf);
550bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
55117f6e4bba20b6542cdf0a4fb0442a7f330003ee4reed@android.com#ifdef OUTSET_BEFORE_CLIP_TEST
55217f6e4bba20b6542cdf0a4fb0442a7f330003ee4reed@android.com            left -= 1;
55317f6e4bba20b6542cdf0a4fb0442a7f330003ee4reed@android.com            right += 1;
55417f6e4bba20b6542cdf0a4fb0442a7f330003ee4reed@android.com#endif
5553d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org            if (left >= clip->fRight || right <= clip->fLeft) {
556bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                return;
5573d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org            }
5583d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org            if (clip->fLeft <= left && clip->fRight >= right) {
559bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                clip = NULL;
5603d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org            }
561bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
562bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
563bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
564bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkRectClipBlitter   rectClipper;
5653d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org    if (clip) {
566bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        rectClipper.init(blitter, *clip);
567bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        blitter = &rectClipper;
568bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
569935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
57037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    SkASSERT(hairBlitter);
57137abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    hairBlitter->setup(blitter);
57237abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com
573821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com#ifdef SK_DEBUG
574821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com    if (scaleStart > 0 && scaleStop > 0) {
575821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com        // be sure we don't draw twice in the same pixel
576821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com        SkASSERT(istart < istop - 1);
577821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com    }
578821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com#endif
579821f3ed12741706f95f0b2fc9046139c7644e575reed@google.com
58037abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com    fstart = hairBlitter->drawCap(istart, fstart, slope, scaleStart);
581bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    istart += 1;
58274c46a2c5c4988c88bf0594977c1f8a0c322682dreed@android.com    int fullSpans = istop - istart - (scaleStop > 0);
583bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (fullSpans > 0) {
58437abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        fstart = hairBlitter->drawLine(istart, istart + fullSpans, fstart, slope);
585bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
586bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (scaleStop > 0) {
58737abc308ca69424a5cdbe869d45fa25cb4e9f366reed@google.com        hairBlitter->drawCap(istop - 1, fstart, slope, scaleStop);
588bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
589bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
590bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
59126f5a398c38318eb7eab44f72e024ef784d247fareed@google.comvoid SkScan::AntiHairLineRgn(const SkPoint& pt0, const SkPoint& pt1,
59226f5a398c38318eb7eab44f72e024ef784d247fareed@google.com                             const SkRegion* clip, SkBlitter* blitter) {
5933d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org    if (clip && clip->isEmpty()) {
594bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return;
5953d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org    }
596bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
597bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(clip == NULL || !clip->getBounds().isEmpty());
598bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
599bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef TEST_GAMMA
600bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    build_gamma_table();
601bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif
602bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
6039005874dcc2a962acd88141f7e0ade7ada472babreed@android.com    SkPoint pts[2] = { pt0, pt1 };
604bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
6051562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com#ifdef SK_SCALAR_IS_FLOAT
6061562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com    // We have to pre-clip the line to fit in a SkFixed, so we just chop
6071562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com    // the line. TODO find a way to actually draw beyond that range.
6081562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com    {
6091562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com        SkRect fixedBounds;
6101562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com        const SkScalar max = SkIntToScalar(32767);
6111562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com        fixedBounds.set(-max, -max, max, max);
6121562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com        if (!SkLineClipper::IntersectLine(pts, fixedBounds, pts)) {
6131562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com            return;
6141562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com        }
6151562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com    }
6161562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com#endif
6171562b550f54f1adaf44f2c833a18f63555332e4dreed@google.com
6189005874dcc2a962acd88141f7e0ade7ada472babreed@android.com    if (clip) {
6199005874dcc2a962acd88141f7e0ade7ada472babreed@android.com        SkRect clipBounds;
6209005874dcc2a962acd88141f7e0ade7ada472babreed@android.com        clipBounds.set(clip->getBounds());
62163faf56c5c79a2c6acd10ab759dddee18a504fa9reed@android.com        /*  We perform integral clipping later on, but we do a scalar clip first
62263faf56c5c79a2c6acd10ab759dddee18a504fa9reed@android.com            to ensure that our coordinates are expressible in fixed/integers.
62363faf56c5c79a2c6acd10ab759dddee18a504fa9reed@android.com
62463faf56c5c79a2c6acd10ab759dddee18a504fa9reed@android.com            antialiased hairlines can draw up to 1/2 of a pixel outside of
62563faf56c5c79a2c6acd10ab759dddee18a504fa9reed@android.com            their bounds, so we need to outset the clip before calling the
62663faf56c5c79a2c6acd10ab759dddee18a504fa9reed@android.com            clipper. To make the numerics safer, we outset by a whole pixel,
62763faf56c5c79a2c6acd10ab759dddee18a504fa9reed@android.com            since the 1/2 pixel boundary is important to the antihair blitter,
62863faf56c5c79a2c6acd10ab759dddee18a504fa9reed@android.com            we don't want to risk numerical fate by chopping on that edge.
62963faf56c5c79a2c6acd10ab759dddee18a504fa9reed@android.com         */
63063faf56c5c79a2c6acd10ab759dddee18a504fa9reed@android.com        clipBounds.inset(-SK_Scalar1, -SK_Scalar1);
63163faf56c5c79a2c6acd10ab759dddee18a504fa9reed@android.com
6329005874dcc2a962acd88141f7e0ade7ada472babreed@android.com        if (!SkLineClipper::IntersectLine(pts, clipBounds, pts)) {
6339005874dcc2a962acd88141f7e0ade7ada472babreed@android.com            return;
6349005874dcc2a962acd88141f7e0ade7ada472babreed@android.com        }
6359005874dcc2a962acd88141f7e0ade7ada472babreed@android.com    }
636935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
6379005874dcc2a962acd88141f7e0ade7ada472babreed@android.com    SkFDot6 x0 = SkScalarToFDot6(pts[0].fX);
6389005874dcc2a962acd88141f7e0ade7ada472babreed@android.com    SkFDot6 y0 = SkScalarToFDot6(pts[0].fY);
6399005874dcc2a962acd88141f7e0ade7ada472babreed@android.com    SkFDot6 x1 = SkScalarToFDot6(pts[1].fX);
6409005874dcc2a962acd88141f7e0ade7ada472babreed@android.com    SkFDot6 y1 = SkScalarToFDot6(pts[1].fY);
6419005874dcc2a962acd88141f7e0ade7ada472babreed@android.com
6429005874dcc2a962acd88141f7e0ade7ada472babreed@android.com    if (clip) {
6439005874dcc2a962acd88141f7e0ade7ada472babreed@android.com        SkFDot6 left = SkMin32(x0, x1);
6449005874dcc2a962acd88141f7e0ade7ada472babreed@android.com        SkFDot6 top = SkMin32(y0, y1);
6459005874dcc2a962acd88141f7e0ade7ada472babreed@android.com        SkFDot6 right = SkMax32(x0, x1);
6469005874dcc2a962acd88141f7e0ade7ada472babreed@android.com        SkFDot6 bottom = SkMax32(y0, y1);
6479005874dcc2a962acd88141f7e0ade7ada472babreed@android.com        SkIRect ir;
648bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
649bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        ir.set( SkFDot6Floor(left) - 1,
650bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                SkFDot6Floor(top) - 1,
651bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                SkFDot6Ceil(right) + 1,
652bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                SkFDot6Ceil(bottom) + 1);
653bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
6549005874dcc2a962acd88141f7e0ade7ada472babreed@android.com        if (clip->quickReject(ir)) {
655bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            return;
6569005874dcc2a962acd88141f7e0ade7ada472babreed@android.com        }
6579005874dcc2a962acd88141f7e0ade7ada472babreed@android.com        if (!clip->quickContains(ir)) {
658bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkRegion::Cliperator iter(*clip, ir);
659bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            const SkIRect*       r = &iter.rect();
660bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
6619005874dcc2a962acd88141f7e0ade7ada472babreed@android.com            while (!iter.done()) {
662bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                do_anti_hairline(x0, y0, x1, y1, r, blitter);
663bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                iter.next();
664bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
665bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            return;
666bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
667bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // fall through to no-clip case
668bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
669bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    do_anti_hairline(x0, y0, x1, y1, NULL, blitter);
670bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
671bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
67226f5a398c38318eb7eab44f72e024ef784d247fareed@google.comvoid SkScan::AntiHairRect(const SkRect& rect, const SkRasterClip& clip,
6733d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org                          SkBlitter* blitter) {
674bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkPoint p0, p1;
675bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
676bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    p0.set(rect.fLeft, rect.fTop);
677bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    p1.set(rect.fRight, rect.fTop);
678bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkScan::AntiHairLine(p0, p1, clip, blitter);
679bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    p0.set(rect.fRight, rect.fBottom);
680bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkScan::AntiHairLine(p0, p1, clip, blitter);
681bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    p1.set(rect.fLeft, rect.fBottom);
682bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkScan::AntiHairLine(p0, p1, clip, blitter);
683bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    p0.set(rect.fLeft, rect.fTop);
684bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkScan::AntiHairLine(p0, p1, clip, blitter);
685bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
686bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
6873d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org///////////////////////////////////////////////////////////////////////////////
688bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
689bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comtypedef int FDot8;  // 24.8 integer fixed point
690bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
691bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic inline FDot8 SkFixedToFDot8(SkFixed x) {
692bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return (x + 0x80) >> 8;
693bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
694bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
6953d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.orgstatic void do_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha,
6963d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org                        SkBlitter* blitter) {
697bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(L < R);
698935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
6993d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org    if ((L >> 8) == ((R - 1) >> 8)) {  // 1x1 pixel
700bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        blitter->blitV(L >> 8, top, 1, SkAlphaMul(alpha, R - L));
701bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return;
702bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
703935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
704bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int left = L >> 8;
705935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
7063d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org    if (L & 0xFF) {
707bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        blitter->blitV(left, top, 1, SkAlphaMul(alpha, 256 - (L & 0xFF)));
708bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        left += 1;
709bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
710bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
711bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int rite = R >> 8;
712bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int width = rite - left;
7133d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org    if (width > 0) {
714bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        call_hline_blitter(blitter, left, top, width, alpha);
7153d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org    }
7163d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org    if (R & 0xFF) {
717bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        blitter->blitV(rite, top, 1, SkAlphaMul(alpha, R & 0xFF));
7183d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org    }
719bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
720bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
721a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.orgstatic void antifilldot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B, SkBlitter* blitter,
722a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org                         bool fillInner) {
723bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // check for empty now that we're in our reduced precision space
7243d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org    if (L >= R || T >= B) {
725bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return;
7263d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org    }
727bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int top = T >> 8;
7283d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org    if (top == ((B - 1) >> 8)) {   // just one scanline high
729bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        do_scanline(L, top, R, B - T - 1, blitter);
730bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return;
731bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
732935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
7333d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org    if (T & 0xFF) {
734bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        do_scanline(L, top, R, 256 - (T & 0xFF), blitter);
735bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        top += 1;
736bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
737935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
738bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int bot = B >> 8;
739bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int height = bot - top;
7403d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org    if (height > 0) {
741bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        int left = L >> 8;
74211a407a3f00f3887d6a933a0cf327a437f054942reed@google.com        if (left == ((R - 1) >> 8)) {   // just 1-pixel wide
74311a407a3f00f3887d6a933a0cf327a437f054942reed@google.com            blitter->blitV(left, top, height, R - L - 1);
74411a407a3f00f3887d6a933a0cf327a437f054942reed@google.com        } else {
74511a407a3f00f3887d6a933a0cf327a437f054942reed@google.com            if (L & 0xFF) {
74611a407a3f00f3887d6a933a0cf327a437f054942reed@google.com                blitter->blitV(left, top, height, 256 - (L & 0xFF));
74711a407a3f00f3887d6a933a0cf327a437f054942reed@google.com                left += 1;
74811a407a3f00f3887d6a933a0cf327a437f054942reed@google.com            }
74911a407a3f00f3887d6a933a0cf327a437f054942reed@google.com            int rite = R >> 8;
75011a407a3f00f3887d6a933a0cf327a437f054942reed@google.com            int width = rite - left;
75111a407a3f00f3887d6a933a0cf327a437f054942reed@google.com            if (width > 0 && fillInner) {
75211a407a3f00f3887d6a933a0cf327a437f054942reed@google.com                blitter->blitRect(left, top, width, height);
75311a407a3f00f3887d6a933a0cf327a437f054942reed@google.com            }
75411a407a3f00f3887d6a933a0cf327a437f054942reed@google.com            if (R & 0xFF) {
75511a407a3f00f3887d6a933a0cf327a437f054942reed@google.com                blitter->blitV(rite, top, height, R & 0xFF);
75611a407a3f00f3887d6a933a0cf327a437f054942reed@google.com            }
7573d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org        }
758bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
759935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
7603d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org    if (B & 0xFF) {
761bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        do_scanline(L, bot, R, B & 0xFF, blitter);
7623d746ab2c23d504b2f9ed699a038903b3ba3ef98mike@reedtribe.org    }
763bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
764bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
765a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.orgstatic void antifillrect(const SkXRect& xr, SkBlitter* blitter) {
766a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    antifilldot8(SkFixedToFDot8(xr.fLeft), SkFixedToFDot8(xr.fTop),
767a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org                 SkFixedToFDot8(xr.fRight), SkFixedToFDot8(xr.fBottom),
768a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org                 blitter, true);
769a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org}
770a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org
771bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com///////////////////////////////////////////////////////////////////////////////
772bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
773d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.comvoid SkScan::AntiFillXRect(const SkXRect& xr, const SkRegion* clip,
774bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                          SkBlitter* blitter) {
775d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com    if (NULL == clip) {
776d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com        antifillrect(xr, blitter);
777d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com    } else {
778d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com        SkIRect outerBounds;
779d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com        XRect_roundOut(xr, &outerBounds);
780d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com
781d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com        if (clip->isRect()) {
782d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com            const SkIRect& clipBounds = clip->getBounds();
783d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com
784d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com            if (clipBounds.contains(outerBounds)) {
785d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com                antifillrect(xr, blitter);
786d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com            } else {
787d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com                SkXRect tmpR;
788d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com                // this keeps our original edges fractional
789d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com                XRect_set(&tmpR, clipBounds);
790d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com                if (tmpR.intersect(xr)) {
791d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com                    antifillrect(tmpR, blitter);
792d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com                }
793d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com            }
794bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        } else {
795d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com            SkRegion::Cliperator clipper(*clip, outerBounds);
796d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com            const SkIRect&       rr = clipper.rect();
797935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
798d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com            while (!clipper.done()) {
799d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com                SkXRect  tmpR;
800935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
801d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com                // this keeps our original edges fractional
802d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com                XRect_set(&tmpR, rr);
803d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com                if (tmpR.intersect(xr)) {
804d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com                    antifillrect(tmpR, blitter);
805d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com                }
806d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com                clipper.next();
807bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
808bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
809d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com    }
810d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com}
811d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com
812d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.comvoid SkScan::AntiFillXRect(const SkXRect& xr, const SkRasterClip& clip,
813d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com                           SkBlitter* blitter) {
814d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com    if (clip.isBW()) {
815d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com        AntiFillXRect(xr, &clip.bwRgn(), blitter);
816bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    } else {
817d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com        SkIRect outerBounds;
818d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com        XRect_roundOut(xr, &outerBounds);
819d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com
820d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com        if (clip.quickContains(outerBounds)) {
821d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com            AntiFillXRect(xr, NULL, blitter);
822d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com        } else {
823d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com            SkAAClipBlitterWrapper wrapper(clip, blitter);
824d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com            blitter = wrapper.getBlitter();
825d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com
826d60acc1b5061411e0abc94de402d999c5087f8d1reed@google.com            AntiFillXRect(xr, &wrapper.getRgn(), wrapper.getBlitter());
82726f5a398c38318eb7eab44f72e024ef784d247fareed@google.com        }
828bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
829bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
830bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
831bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef SK_SCALAR_IS_FLOAT
832bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
833bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com/*  This guy takes a float-rect, but with the key improvement that it has
834bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    already been clipped, so we know that it is safe to convert it into a
835bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    XRect (fixedpoint), as it won't overflow.
836bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com*/
837bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic void antifillrect(const SkRect& r, SkBlitter* blitter) {
838bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkXRect xr;
839935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
840bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    XRect_set(&xr, r);
841bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    antifillrect(xr, blitter);
842bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
843bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
844bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com/*  We repeat the clipping logic of AntiFillXRect because the float rect might
845bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    overflow if we blindly converted it to an XRect. This sucks that we have to
846bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    repeat the clipping logic, but I don't see how to share the code/logic.
847935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
848bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    We clip r (as needed) into one or more (smaller) float rects, and then pass
849bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    those to our version of antifillrect, which converts it into an XRect and
850bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    then calls the blit.
851bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com*/
8529005874dcc2a962acd88141f7e0ade7ada472babreed@android.comvoid SkScan::AntiFillRect(const SkRect& origR, const SkRegion* clip,
853bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                          SkBlitter* blitter) {
854bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (clip) {
8559005874dcc2a962acd88141f7e0ade7ada472babreed@android.com        SkRect newR;
8569005874dcc2a962acd88141f7e0ade7ada472babreed@android.com        newR.set(clip->getBounds());
8579005874dcc2a962acd88141f7e0ade7ada472babreed@android.com        if (!newR.intersect(origR)) {
8589005874dcc2a962acd88141f7e0ade7ada472babreed@android.com            return;
8599005874dcc2a962acd88141f7e0ade7ada472babreed@android.com        }
8609005874dcc2a962acd88141f7e0ade7ada472babreed@android.com
861bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkIRect outerBounds;
8629005874dcc2a962acd88141f7e0ade7ada472babreed@android.com        newR.roundOut(&outerBounds);
863935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
864bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (clip->isRect()) {
8659005874dcc2a962acd88141f7e0ade7ada472babreed@android.com            antifillrect(newR, blitter);
866bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        } else {
867bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkRegion::Cliperator clipper(*clip, outerBounds);
868bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            while (!clipper.done()) {
8699005874dcc2a962acd88141f7e0ade7ada472babreed@android.com                newR.set(clipper.rect());
8709005874dcc2a962acd88141f7e0ade7ada472babreed@android.com                if (newR.intersect(origR)) {
8719005874dcc2a962acd88141f7e0ade7ada472babreed@android.com                    antifillrect(newR, blitter);
872bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                }
873bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                clipper.next();
874bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
875bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
876bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    } else {
8779005874dcc2a962acd88141f7e0ade7ada472babreed@android.com        antifillrect(origR, blitter);
878bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
879bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
880bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
88126f5a398c38318eb7eab44f72e024ef784d247fareed@google.comvoid SkScan::AntiFillRect(const SkRect& r, const SkRasterClip& clip,
88226f5a398c38318eb7eab44f72e024ef784d247fareed@google.com                          SkBlitter* blitter) {
88326f5a398c38318eb7eab44f72e024ef784d247fareed@google.com    if (clip.isBW()) {
88426f5a398c38318eb7eab44f72e024ef784d247fareed@google.com        AntiFillRect(r, &clip.bwRgn(), blitter);
88526f5a398c38318eb7eab44f72e024ef784d247fareed@google.com    } else {
88626f5a398c38318eb7eab44f72e024ef784d247fareed@google.com        SkAAClipBlitterWrapper wrap(clip, blitter);
88726f5a398c38318eb7eab44f72e024ef784d247fareed@google.com        AntiFillRect(r, &wrap.getRgn(), wrap.getBlitter());
88826f5a398c38318eb7eab44f72e024ef784d247fareed@google.com    }
88926f5a398c38318eb7eab44f72e024ef784d247fareed@google.com}
89026f5a398c38318eb7eab44f72e024ef784d247fareed@google.com
891c4c4538f03a77d218c7c324c24d4472820c7f808epoger@google.com#endif // SK_SCALAR_IS_FLOAT
892c4c4538f03a77d218c7c324c24d4472820c7f808epoger@google.com
893a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org///////////////////////////////////////////////////////////////////////////////
894a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org
895353f04e3e5b5df81b8bf48845daaadb204818dfdreed@google.com#define SkAlphaMulRound(a, b)   SkMulDiv255Round(a, b)
896353f04e3e5b5df81b8bf48845daaadb204818dfdreed@google.com
897a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org// calls blitRect() if the rectangle is non-empty
898a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.orgstatic void fillcheckrect(int L, int T, int R, int B, SkBlitter* blitter) {
899a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    if (L < R && T < B) {
900a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        blitter->blitRect(L, T, R - L, B - T);
901a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    }
902a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org}
903a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org
904a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.orgstatic inline FDot8 SkScalarToFDot8(SkScalar x) {
905a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org#ifdef SK_SCALAR_IS_FLOAT
906a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    return (int)(x * 256);
907a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org#else
908a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    return x >> 8;
909a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org#endif
910a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org}
911a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org
912a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.orgstatic inline int FDot8Floor(FDot8 x) {
913a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    return x >> 8;
914a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org}
915a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org
916a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.orgstatic inline int FDot8Ceil(FDot8 x) {
917a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    return (x + 0xFF) >> 8;
918a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org}
919a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org
920a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org// 1 - (1 - a)*(1 - b)
921a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.orgstatic inline U8CPU InvAlphaMul(U8CPU a, U8CPU b) {
922353f04e3e5b5df81b8bf48845daaadb204818dfdreed@google.com    // need precise rounding (not just SkAlphaMul) so that values like
923353f04e3e5b5df81b8bf48845daaadb204818dfdreed@google.com    // a=228, b=252 don't overflow the result
924353f04e3e5b5df81b8bf48845daaadb204818dfdreed@google.com    return SkToU8(a + b - SkAlphaMulRound(a, b));
925a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org}
926a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org
927a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.orgstatic void inner_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha,
928a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org                           SkBlitter* blitter) {
929a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    SkASSERT(L < R);
930935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
931a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    if ((L >> 8) == ((R - 1) >> 8)) {  // 1x1 pixel
932a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        blitter->blitV(L >> 8, top, 1, InvAlphaMul(alpha, R - L));
933a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        return;
934a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    }
935935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
936a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    int left = L >> 8;
937a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    if (L & 0xFF) {
938a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        blitter->blitV(left, top, 1, InvAlphaMul(alpha, L & 0xFF));
939a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        left += 1;
940a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    }
941935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
942a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    int rite = R >> 8;
943a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    int width = rite - left;
944a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    if (width > 0) {
945a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        call_hline_blitter(blitter, left, top, width, alpha);
946a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    }
947935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
948a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    if (R & 0xFF) {
949a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        blitter->blitV(rite, top, 1, InvAlphaMul(alpha, ~R & 0xFF));
950a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    }
951a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org}
952a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org
953a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.orgstatic void innerstrokedot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B,
954a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org                            SkBlitter* blitter) {
955a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    SkASSERT(L < R && T < B);
956a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org
957a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    int top = T >> 8;
958a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    if (top == ((B - 1) >> 8)) {   // just one scanline high
9598e70211e0b1a5d50010c246c1ec72a38be0baddareed@google.com        // We want the inverse of B-T, since we're the inner-stroke
9608e70211e0b1a5d50010c246c1ec72a38be0baddareed@google.com        int alpha = 256 - (B - T);
9618e70211e0b1a5d50010c246c1ec72a38be0baddareed@google.com        if (alpha) {
9628e70211e0b1a5d50010c246c1ec72a38be0baddareed@google.com            inner_scanline(L, top, R, alpha, blitter);
9638e70211e0b1a5d50010c246c1ec72a38be0baddareed@google.com        }
964a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        return;
965a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    }
966935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
967a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    if (T & 0xFF) {
968a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        inner_scanline(L, top, R, T & 0xFF, blitter);
969a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        top += 1;
970a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    }
971935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
972a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    int bot = B >> 8;
973a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    int height = bot - top;
974a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    if (height > 0) {
975a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        if (L & 0xFF) {
976a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org            blitter->blitV(L >> 8, top, height, L & 0xFF);
977a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        }
978a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        if (R & 0xFF) {
979a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org            blitter->blitV(R >> 8, top, height, ~R & 0xFF);
980a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        }
981a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    }
982935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
983a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    if (B & 0xFF) {
984a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        inner_scanline(L, bot, R, ~B & 0xFF, blitter);
985a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    }
986a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org}
987a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org
988f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.comvoid SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize,
989a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org                           const SkRegion* clip, SkBlitter* blitter) {
990f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com    SkASSERT(strokeSize.fX >= 0 && strokeSize.fY >= 0);
991a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org
992f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com    SkScalar rx = SkScalarHalf(strokeSize.fX);
993f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com    SkScalar ry = SkScalarHalf(strokeSize.fY);
994a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org
995a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    // outset by the radius
996f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com    FDot8 L = SkScalarToFDot8(r.fLeft - rx);
997f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com    FDot8 T = SkScalarToFDot8(r.fTop - ry);
998f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com    FDot8 R = SkScalarToFDot8(r.fRight + rx);
999f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com    FDot8 B = SkScalarToFDot8(r.fBottom + ry);
1000a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org
1001a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    SkIRect outer;
1002a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    // set outer to the outer rect of the outer section
1003a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    outer.set(FDot8Floor(L), FDot8Floor(T), FDot8Ceil(R), FDot8Ceil(B));
1004a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org
1005a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    SkBlitterClipper clipper;
1006a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    if (clip) {
1007a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        if (clip->quickReject(outer)) {
1008a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org            return;
1009a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        }
1010a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        if (!clip->contains(outer)) {
1011a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org            blitter = clipper.apply(blitter, clip, &outer);
1012a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        }
1013a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        // now we can ignore clip for the rest of the function
1014a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    }
1015935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
1016a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    // stroke the outer hull
1017a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    antifilldot8(L, T, R, B, blitter, false);
1018a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org
1019a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    // set outer to the outer rect of the middle section
1020a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    outer.set(FDot8Ceil(L), FDot8Ceil(T), FDot8Floor(R), FDot8Floor(B));
1021a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org
1022a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    // in case we lost a bit with diameter/2
1023f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com    rx = strokeSize.fX - rx;
1024f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com    ry = strokeSize.fY - ry;
1025a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    // inset by the radius
1026f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com    L = SkScalarToFDot8(r.fLeft + rx);
1027f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com    T = SkScalarToFDot8(r.fTop + ry);
1028f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com    R = SkScalarToFDot8(r.fRight - rx);
1029f356ebc4dffdc026504a338852447ceae7a9ac11reed@google.com    B = SkScalarToFDot8(r.fBottom - ry);
1030a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org
1031a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    if (L >= R || T >= B) {
1032a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, outer.fBottom,
1033a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org                      blitter);
1034a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    } else {
1035a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        SkIRect inner;
1036a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        // set inner to the inner rect of the middle section
1037a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        inner.set(FDot8Floor(L), FDot8Floor(T), FDot8Ceil(R), FDot8Ceil(B));
1038a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org
1039a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        // draw the frame in 4 pieces
1040a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, inner.fTop,
1041a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org                      blitter);
1042a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        fillcheckrect(outer.fLeft, inner.fTop, inner.fLeft, inner.fBottom,
1043a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org                      blitter);
1044a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        fillcheckrect(inner.fRight, inner.fTop, outer.fRight, inner.fBottom,
1045a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org                      blitter);
1046a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        fillcheckrect(outer.fLeft, inner.fBottom, outer.fRight, outer.fBottom,
1047a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org                      blitter);
1048a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org
1049a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        // now stroke the inner rect, which is similar to antifilldot8() except that
1050a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        // it treats the fractional coordinates with the inverse bias (since its
1051a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        // inner).
1052a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org        innerstrokedot8(L, T, R, B, blitter);
1053a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org    }
1054a1f05123b4cf56ce47552d8613d0a3b1a4114f9amike@reedtribe.org}
105526f5a398c38318eb7eab44f72e024ef784d247fareed@google.com
105626f5a398c38318eb7eab44f72e024ef784d247fareed@google.comvoid SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize,
105726f5a398c38318eb7eab44f72e024ef784d247fareed@google.com                           const SkRasterClip& clip, SkBlitter* blitter) {
105826f5a398c38318eb7eab44f72e024ef784d247fareed@google.com    if (clip.isBW()) {
105926f5a398c38318eb7eab44f72e024ef784d247fareed@google.com        AntiFrameRect(r, strokeSize, &clip.bwRgn(), blitter);
106026f5a398c38318eb7eab44f72e024ef784d247fareed@google.com    } else {
106126f5a398c38318eb7eab44f72e024ef784d247fareed@google.com        SkAAClipBlitterWrapper wrap(clip, blitter);
106226f5a398c38318eb7eab44f72e024ef784d247fareed@google.com        AntiFrameRect(r, strokeSize, &wrap.getRgn(), wrap.getBlitter());
106326f5a398c38318eb7eab44f72e024ef784d247fareed@google.com    }
106426f5a398c38318eb7eab44f72e024ef784d247fareed@google.com}
1065