1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 The Android Open Source Project
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
8ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkScan.h"
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBlitter.h"
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkColorPriv.h"
13e28ff55d980d2992618b6b721c848aba96cf759areed@android.com#include "SkLineClipper.h"
14045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com#include "SkRasterClip.h"
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkFDot6.h"
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
178898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com/*  Our attempt to compute the worst case "bounds" for the horizontal and
188898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com    vertical cases has some numerical bug in it, and we sometimes undervalue
198898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com    our extends. The bug is that when this happens, we will set the clip to
208898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com    NULL (for speed), and thus draw outside of the clip by a pixel, which might
218898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com    only look bad, but it might also access memory outside of the valid range
228898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com    allcoated for the device bitmap.
236c14b43a840c791699747ba4cc0ed5abf2bda218reed@android.com
248898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com    This define enables our fix to outset our "bounds" by 1, thus avoiding the
258898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com    chance of the bug, but at the cost of sometimes taking the rectblitter
268898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com    case (i.e. not setting the clip to NULL) when we might not actually need
278898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com    to. If we can improve/fix the actual calculations, then we can remove this
288898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com    step.
298898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com */
308898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com#define OUTSET_BEFORE_CLIP_TEST     true
318898363b2ee02e36dfa4bb166b59c09c4e835b0freed@android.com
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define HLINE_STACK_BUFFER      100
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline int SmallDot6Scale(int value, int dot6) {
358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT((int16_t)value == value);
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT((unsigned)dot6 <= 64);
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return SkMulS16(value, dot6) >> 6;
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//#define TEST_GAMMA
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef TEST_GAMMA
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static uint8_t gGammaTable[256];
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    #define ApplyGamma(table, alpha)    (table)[alpha]
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
46bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org    static void build_gamma_table() {
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        static bool gInit = false;
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
49bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org        if (gInit == false) {
50bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org            for (int i = 0; i < 256; i++) {
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkFixed n = i * 257;
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                n += n >> 15;
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(n >= 0 && n <= SK_Fixed1);
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                n = SkFixedSqrt(n);
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                n = n * 255 >> 16;
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            //  SkDebugf("morph %d -> %d\n", i, n);
578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                gGammaTable[i] = SkToU8(n);
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            gInit = true;
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#else
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    #define ApplyGamma(table, alpha)    SkToU8(alpha)
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
68bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.orgstatic void call_hline_blitter(SkBlitter* blitter, int x, int y, int count,
69bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org                               U8CPU alpha) {
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(count > 0);
7127b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int16_t runs[HLINE_STACK_BUFFER + 1];
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint8_t  aa[HLINE_STACK_BUFFER];
7427b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    aa[0] = ApplyGamma(gGammaTable, alpha);
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    do {
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int n = count;
78bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org        if (n > HLINE_STACK_BUFFER) {
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            n = HLINE_STACK_BUFFER;
80bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org        }
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        runs[0] = SkToS16(n);
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        runs[n] = 0;
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        blitter->blitAntiH(x, y, aa, runs);
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        x += n;
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        count -= n;
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } while (count > 0);
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
89b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.comclass SkAntiHairBlitter {
90b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.compublic:
91b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    SkAntiHairBlitter() : fBlitter(NULL) {}
92ade109f57c64f4fbc048cd77abaf4c539e010557djsollen@google.com    virtual ~SkAntiHairBlitter() {}
938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
94b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    SkBlitter* getBlitter() const { return fBlitter; }
958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
96b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    void setup(SkBlitter* blitter) {
97b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        fBlitter = blitter;
988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
100b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    virtual SkFixed drawCap(int x, SkFixed fy, SkFixed slope, int mod64) = 0;
101b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    virtual SkFixed drawLine(int x, int stopx, SkFixed fy, SkFixed slope) = 0;
102fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
103b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.comprivate:
104b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    SkBlitter*  fBlitter;
105b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com};
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
107b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.comclass HLine_SkAntiHairBlitter : public SkAntiHairBlitter {
108b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.compublic:
109b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    virtual SkFixed drawCap(int x, SkFixed fy, SkFixed slope, int mod64) SK_OVERRIDE {
110b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        fy += SK_Fixed1/2;
11127b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
112b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        int y = fy >> 16;
113b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        uint8_t  a = (uint8_t)(fy >> 8);
11427b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
115b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        // lower line
116b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        unsigned ma = SmallDot6Scale(a, mod64);
117b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        if (ma) {
118b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            call_hline_blitter(this->getBlitter(), x, y, 1, ma);
119b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        }
12027b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
121b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        // upper line
122b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        ma = SmallDot6Scale(255 - a, mod64);
123b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        if (ma) {
124b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            call_hline_blitter(this->getBlitter(), x, y - 1, 1, ma);
125b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        }
12627b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
127b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        return fy - SK_Fixed1/2;
128b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    }
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
130b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    virtual SkFixed drawLine(int x, int stopx, SkFixed fy,
131b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com                             SkFixed slope) SK_OVERRIDE {
132b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        SkASSERT(x < stopx);
133b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        int count = stopx - x;
134b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        fy += SK_Fixed1/2;
13527b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
136b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        int y = fy >> 16;
137b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        uint8_t  a = (uint8_t)(fy >> 8);
13827b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
139b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        // lower line
140b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        if (a) {
141b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            call_hline_blitter(this->getBlitter(), x, y, count, a);
142b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        }
14327b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
144b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        // upper line
145b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        a = 255 - a;
146b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        if (a) {
147b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            call_hline_blitter(this->getBlitter(), x, y - 1, count, a);
148b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        }
14927b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
150b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        return fy - SK_Fixed1/2;
151b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    }
152b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com};
153b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com
154b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.comclass Horish_SkAntiHairBlitter : public SkAntiHairBlitter {
155b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.compublic:
156b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    virtual SkFixed drawCap(int x, SkFixed fy, SkFixed dy, int mod64) SK_OVERRIDE {
157b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        int16_t runs[2];
158b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        uint8_t  aa[1];
15927b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
160b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        runs[0] = 1;
161b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        runs[1] = 0;
16227b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
163b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        fy += SK_Fixed1/2;
164b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        SkBlitter* blitter = this->getBlitter();
1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int lower_y = fy >> 16;
1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        uint8_t  a = (uint8_t)(fy >> 8);
1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        unsigned ma = SmallDot6Scale(a, mod64);
169bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org        if (ma) {
1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            aa[0] = ApplyGamma(gamma, ma);
1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            blitter->blitAntiH(x, lower_y, aa, runs);
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // the clipping blitters might edit runs, but should not affect us
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(runs[0] == 1);
1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(runs[1] == 0);
1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        ma = SmallDot6Scale(255 - a, mod64);
177bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org        if (ma) {
1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            aa[0] = ApplyGamma(gamma, ma);
1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            blitter->blitAntiH(x, lower_y - 1, aa, runs);
1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // the clipping blitters might edit runs, but should not affect us
1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(runs[0] == 1);
1828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(runs[1] == 0);
1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fy += dy;
18527b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
186b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        return fy - SK_Fixed1/2;
187bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org    }
18827b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
189b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    virtual SkFixed drawLine(int x, int stopx, SkFixed fy, SkFixed dy) SK_OVERRIDE {
190b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        SkASSERT(x < stopx);
19127b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
192b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        int16_t runs[2];
193b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        uint8_t  aa[1];
19427b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
195b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        runs[0] = 1;
196b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        runs[1] = 0;
19727b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
198b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        fy += SK_Fixed1/2;
199b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        SkBlitter* blitter = this->getBlitter();
200b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        do {
201b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            int lower_y = fy >> 16;
202b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            uint8_t  a = (uint8_t)(fy >> 8);
203b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            if (a) {
204b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com                aa[0] = a;
205b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com                blitter->blitAntiH(x, lower_y, aa, runs);
206b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com                // the clipping blitters might edit runs, but should not affect us
207b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com                SkASSERT(runs[0] == 1);
208b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com                SkASSERT(runs[1] == 0);
209b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            }
210b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            a = 255 - a;
211b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            if (a) {
212b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com                aa[0] = a;
213b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com                blitter->blitAntiH(x, lower_y - 1, aa, runs);
214b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com                // the clipping blitters might edit runs, but should not affect us
215b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com                SkASSERT(runs[0] == 1);
216b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com                SkASSERT(runs[1] == 0);
217b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            }
218b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            fy += dy;
219b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        } while (++x < stopx);
22027b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
221b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        return fy - SK_Fixed1/2;
222b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    }
223b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com};
224b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com
225b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.comclass VLine_SkAntiHairBlitter : public SkAntiHairBlitter {
226b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.compublic:
227b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    virtual SkFixed drawCap(int y, SkFixed fx, SkFixed dx, int mod64) SK_OVERRIDE {
228b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        SkASSERT(0 == dx);
229b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        fx += SK_Fixed1/2;
23027b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
231b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        int x = fx >> 16;
232b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        int a = (uint8_t)(fx >> 8);
23327b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
234b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        unsigned ma = SmallDot6Scale(a, mod64);
235b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        if (ma) {
236b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            this->getBlitter()->blitV(x, y, 1, ma);
237b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        }
238b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        ma = SmallDot6Scale(255 - a, mod64);
239b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        if (ma) {
240b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            this->getBlitter()->blitV(x - 1, y, 1, ma);
241b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        }
24227b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
243b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        return fx - SK_Fixed1/2;
244bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org    }
245fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
246b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    virtual SkFixed drawLine(int y, int stopy, SkFixed fx, SkFixed dx) SK_OVERRIDE {
247b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        SkASSERT(y < stopy);
248b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        SkASSERT(0 == dx);
249b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        fx += SK_Fixed1/2;
25027b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
251b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        int x = fx >> 16;
252b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        int a = (uint8_t)(fx >> 8);
25327b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
254b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        if (a) {
255b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            this->getBlitter()->blitV(x, y, stopy - y, a);
256b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        }
257b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        a = 255 - a;
258b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        if (a) {
259b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            this->getBlitter()->blitV(x - 1, y, stopy - y, a);
260b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        }
26127b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
262b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        return fx - SK_Fixed1/2;
263b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    }
264b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com};
265b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com
266b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.comclass Vertish_SkAntiHairBlitter : public SkAntiHairBlitter {
267b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.compublic:
268b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    virtual SkFixed drawCap(int y, SkFixed fx, SkFixed dx, int mod64) SK_OVERRIDE {
269b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        int16_t runs[3];
270b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        uint8_t  aa[2];
27127b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
272b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        runs[0] = 1;
273b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        runs[2] = 0;
27427b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
275b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        fx += SK_Fixed1/2;
2768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int x = fx >> 16;
2778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        uint8_t  a = (uint8_t)(fx >> 8);
27827b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
279b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        aa[0] = SmallDot6Scale(255 - a, mod64);
280b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        aa[1] = SmallDot6Scale(a, mod64);
2818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // the clippng blitters might overwrite this guy, so we have to reset it each time
2828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        runs[1] = 1;
283b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        this->getBlitter()->blitAntiH(x - 1, y, aa, runs);
2848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // the clipping blitters might edit runs, but should not affect us
2858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(runs[0] == 1);
2868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(runs[2] == 0);
2878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fx += dx;
28827b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
289b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        return fx - SK_Fixed1/2;
290b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    }
29127b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
292b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    virtual SkFixed drawLine(int y, int stopy, SkFixed fx, SkFixed dx) SK_OVERRIDE {
293b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        SkASSERT(y < stopy);
294b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        int16_t runs[3];
295b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        uint8_t  aa[2];
29627b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
297b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        runs[0] = 1;
298b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        runs[2] = 0;
29927b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
300b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        fx += SK_Fixed1/2;
301b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        do {
302b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            int x = fx >> 16;
303b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            uint8_t  a = (uint8_t)(fx >> 8);
30427b40e9f36f567a57ae92860052b36cedacdd4fdskia.committer@gmail.com
305b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            aa[0] = 255 - a;
306b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            aa[1] = a;
307b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            // the clippng blitters might overwrite this guy, so we have to reset it each time
308b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            runs[1] = 1;
309b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            this->getBlitter()->blitAntiH(x - 1, y, aa, runs);
310b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            // the clipping blitters might edit runs, but should not affect us
311b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            SkASSERT(runs[0] == 1);
312b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            SkASSERT(runs[2] == 0);
313b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            fx += dx;
314b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        } while (++y < stopy);
3158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
316b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        return fx - SK_Fixed1/2;
317b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    }
318b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com};
3198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
320bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.orgstatic inline SkFixed fastfixdiv(SkFDot6 a, SkFDot6 b) {
3218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT((a << 16 >> 16) == a);
3228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(b != 0);
3238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return (a << 16) / b;
3248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3268a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com#define SkBITCOUNT(x)   (sizeof(x) << 3)
3278a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com
3288a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com#if 1
3298a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com// returns high-bit set iff x==0x8000...
3308a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.comstatic inline int bad_int(int x) {
3318a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com    return x & -x;
3328a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com}
3338a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com
3348a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.comstatic int any_bad_ints(int a, int b, int c, int d) {
3358a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com    return (bad_int(a) | bad_int(b) | bad_int(c) | bad_int(d)) >> (SkBITCOUNT(int) - 1);
3368a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com}
3378a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com#else
3388a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.comstatic inline int good_int(int x) {
3398a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com    return x ^ (1 << (SkBITCOUNT(x) - 1));
3408a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com}
3418a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com
3428a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.comstatic int any_bad_ints(int a, int b, int c, int d) {
3438a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com    return !(good_int(a) & good_int(b) & good_int(c) & good_int(d));
3448a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com}
3458a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com#endif
3468a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com
3470e51577a14f903ffeafa117a75954baeb173ffb9humper@google.com#ifdef SK_DEBUG
34899b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.comstatic bool canConvertFDot6ToFixed(SkFDot6 x) {
34999b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com    const int maxDot6 = SK_MaxS32 >> (16 - 6);
35099b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com    return SkAbs32(x) <= maxDot6;
35199b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com}
3520e51577a14f903ffeafa117a75954baeb173ffb9humper@google.com#endif
35399b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com
354c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com/*
355c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com *  We want the fractional part of ordinate, but we want multiples of 64 to
356c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com *  return 64, not 0, so we can't just say (ordinate & 63).
357c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com *  We basically want to compute those bits, and if they're 0, return 64.
358c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com *  We can do that w/o a branch with an extra sub and add.
359c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com */
360c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.comstatic int contribution_64(SkFDot6 ordinate) {
361c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com#if 0
362c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com    int result = ordinate & 63;
363c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com    if (0 == result) {
364c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com        result = 64;
365c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com    }
366c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com#else
367c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com    int result = ((ordinate - 1) & 63) + 1;
368c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com#endif
369c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com    SkASSERT(result > 0 && result <= 64);
370c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com    return result;
371c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com}
372c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com
3738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1,
374bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org                             const SkIRect* clip, SkBlitter* blitter) {
3758a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com    // check for integer NaN (0x80000000) which we can't handle (can't negate it)
3768a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com    // It appears typically from a huge float (inf or nan) being converted to int.
3778a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com    // If we see it, just don't draw.
3788a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com    if (any_bad_ints(x0, y0, x1, y1)) {
3798a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com        return;
3808a812c252d9206f0d2b1bb691d6b1d45c70e2e8breed@google.com    }
3818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
38299b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com    // The caller must clip the line to [-32767.0 ... 32767.0] ahead of time
38399b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com    // (in dot6 format)
38499b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com    SkASSERT(canConvertFDot6ToFixed(x0));
38599b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com    SkASSERT(canConvertFDot6ToFixed(y0));
38699b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com    SkASSERT(canConvertFDot6ToFixed(x1));
38799b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com    SkASSERT(canConvertFDot6ToFixed(y1));
38899b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com
389bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org    if (SkAbs32(x1 - x0) > SkIntToFDot6(511) || SkAbs32(y1 - y0) > SkIntToFDot6(511)) {
3903555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com        /*  instead of (x0 + x1) >> 1, we shift each separately. This is less
3913555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com            precise, but avoids overflowing the intermediate result if the
3923555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com            values are huge. A better fix might be to clip the original pts
3933555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com            directly (i.e. do the divide), so we don't spend time subdividing
3943555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com            huge lines at all.
3953555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com         */
3963555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com        int hx = (x0 >> 1) + (x1 >> 1);
3973555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com        int hy = (y0 >> 1) + (y1 >> 1);
3988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        do_anti_hairline(x0, y0, hx, hy, clip, blitter);
3998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        do_anti_hairline(hx, hy, x1, y1, clip, blitter);
4008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
4018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int         scaleStart, scaleStop;
4048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int         istart, istop;
405fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    SkFixed     fstart, slope;
406b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com
407b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    HLine_SkAntiHairBlitter     hline_blitter;
408b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    Horish_SkAntiHairBlitter    horish_blitter;
409b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    VLine_SkAntiHairBlitter     vline_blitter;
410b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    Vertish_SkAntiHairBlitter   vertish_blitter;
411b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    SkAntiHairBlitter*          hairBlitter = NULL;
4128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
413bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org    if (SkAbs32(x1 - x0) > SkAbs32(y1 - y0)) {   // mostly horizontal
4148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (x0 > x1) {    // we want to go left-to-right
4158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkTSwap<SkFDot6>(x0, x1);
4168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkTSwap<SkFDot6>(y0, y1);
4178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
4188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        istart = SkFDot6Floor(x0);
4208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        istop = SkFDot6Ceil(x1);
4218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fstart = SkFDot6ToFixed(y0);
4228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (y0 == y1) {   // completely horizontal, take fast case
4238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            slope = 0;
424b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            hairBlitter = &hline_blitter;
4258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } else {
4268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            slope = fastfixdiv(y1 - y0, x1 - x0);
4278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(slope >= -SK_Fixed1 && slope <= SK_Fixed1);
4288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fstart += (slope * (32 - (x0 & 63)) + 32) >> 6;
429b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            hairBlitter = &horish_blitter;
4308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
431fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
4328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(istop > istart);
4338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (istop - istart == 1) {
434c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com            // we are within a single pixel
4358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            scaleStart = x1 - x0;
4368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(scaleStart >= 0 && scaleStart <= 64);
4378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            scaleStop = 0;
4388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } else {
4398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            scaleStart = 64 - (x0 & 63);
4408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            scaleStop = x1 & 63;
4418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
4428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
443bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org        if (clip){
444bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org            if (istart >= clip->fRight || istop <= clip->fLeft) {
4458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                return;
446bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org            }
447bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org            if (istart < clip->fLeft) {
4488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fstart += slope * (clip->fLeft - istart);
4498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                istart = clip->fLeft;
4508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                scaleStart = 64;
451c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com                if (istop - istart == 1) {
452c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com                    // we are within a single pixel
453c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com                    scaleStart = contribution_64(x1);
454c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com                    scaleStop = 0;
455c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com                }
4568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
4570724f4320d4f8c67d26c77594cca7fd030f4be1dreed@google.com            if (istop > clip->fRight) {
4588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                istop = clip->fRight;
459adb2e240188ecd3deef2b31f3836f44968d71d65reed@google.com                scaleStop = 0;  // so we don't draw this last column
4608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
461bbbe9ed59ee1d3077fa4e6368a4a7294240a5ec6reed@google.com
4628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(istart <= istop);
463bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org            if (istart == istop) {
4648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                return;
465bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org            }
4668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // now test if our Y values are completely inside the clip
4678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int top, bottom;
468bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org            if (slope >= 0) { // T2B
4699fb00413ec55deb3a4953d4dff2dba3ec5cdb645mike@reedtribe.org                top = SkFixedFloorToInt(fstart - SK_FixedHalf);
4709fb00413ec55deb3a4953d4dff2dba3ec5cdb645mike@reedtribe.org                bottom = SkFixedCeilToInt(fstart + (istop - istart - 1) * slope + SK_FixedHalf);
471bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org            } else {           // B2T
4729fb00413ec55deb3a4953d4dff2dba3ec5cdb645mike@reedtribe.org                bottom = SkFixedCeilToInt(fstart + SK_FixedHalf);
4739fb00413ec55deb3a4953d4dff2dba3ec5cdb645mike@reedtribe.org                top = SkFixedFloorToInt(fstart + (istop - istart - 1) * slope - SK_FixedHalf);
4748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
4756c14b43a840c791699747ba4cc0ed5abf2bda218reed@android.com#ifdef OUTSET_BEFORE_CLIP_TEST
4766c14b43a840c791699747ba4cc0ed5abf2bda218reed@android.com            top -= 1;
4776c14b43a840c791699747ba4cc0ed5abf2bda218reed@android.com            bottom += 1;
4786c14b43a840c791699747ba4cc0ed5abf2bda218reed@android.com#endif
479bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org            if (top >= clip->fBottom || bottom <= clip->fTop) {
4808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                return;
481bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org            }
482bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org            if (clip->fTop <= top && clip->fBottom >= bottom) {
4838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                clip = NULL;
484bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org            }
4858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
486bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org    } else {   // mostly vertical
487bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org        if (y0 > y1) {  // we want to go top-to-bottom
4888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkTSwap<SkFDot6>(x0, x1);
4898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkTSwap<SkFDot6>(y0, y1);
4908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
4918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        istart = SkFDot6Floor(y0);
4938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        istop = SkFDot6Ceil(y1);
4948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fstart = SkFDot6ToFixed(x0);
495bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org        if (x0 == x1) {
4968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (y0 == y1) { // are we zero length?
4978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                return;     // nothing to do
4988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
4998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            slope = 0;
500b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            hairBlitter = &vline_blitter;
501bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org        } else {
5028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            slope = fastfixdiv(x1 - x0, y1 - y0);
5038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(slope <= SK_Fixed1 && slope >= -SK_Fixed1);
5048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fstart += (slope * (32 - (y0 & 63)) + 32) >> 6;
505b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com            hairBlitter = &vertish_blitter;
5068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
5078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(istop > istart);
5098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (istop - istart == 1) {
510c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com            // we are within a single pixel
5118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            scaleStart = y1 - y0;
5128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(scaleStart >= 0 && scaleStart <= 64);
5138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            scaleStop = 0;
5148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } else {
5158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            scaleStart = 64 - (y0 & 63);
5168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            scaleStop = y1 & 63;
5178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
518fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
519bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org        if (clip) {
520bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org            if (istart >= clip->fBottom || istop <= clip->fTop) {
5218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                return;
522bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org            }
523bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org            if (istart < clip->fTop) {
5248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fstart += slope * (clip->fTop - istart);
5258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                istart = clip->fTop;
5268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                scaleStart = 64;
527c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com                if (istop - istart == 1) {
528c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com                    // we are within a single pixel
529c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com                    scaleStart = contribution_64(y1);
530c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com                    scaleStop = 0;
531c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com                }
5328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
5330724f4320d4f8c67d26c77594cca7fd030f4be1dreed@google.com            if (istop > clip->fBottom) {
5348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                istop = clip->fBottom;
535adb2e240188ecd3deef2b31f3836f44968d71d65reed@google.com                scaleStop = 0;  // so we don't draw this last row
5368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
537bbbe9ed59ee1d3077fa4e6368a4a7294240a5ec6reed@google.com
5388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(istart <= istop);
5398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (istart == istop)
5408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                return;
5418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // now test if our X values are completely inside the clip
5438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int left, right;
544bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org            if (slope >= 0) { // L2R
5459fb00413ec55deb3a4953d4dff2dba3ec5cdb645mike@reedtribe.org                left = SkFixedFloorToInt(fstart - SK_FixedHalf);
5469fb00413ec55deb3a4953d4dff2dba3ec5cdb645mike@reedtribe.org                right = SkFixedCeilToInt(fstart + (istop - istart - 1) * slope + SK_FixedHalf);
547bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org            } else {           // R2L
5489fb00413ec55deb3a4953d4dff2dba3ec5cdb645mike@reedtribe.org                right = SkFixedCeilToInt(fstart + SK_FixedHalf);
5499fb00413ec55deb3a4953d4dff2dba3ec5cdb645mike@reedtribe.org                left = SkFixedFloorToInt(fstart + (istop - istart - 1) * slope - SK_FixedHalf);
5508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
5516c14b43a840c791699747ba4cc0ed5abf2bda218reed@android.com#ifdef OUTSET_BEFORE_CLIP_TEST
5526c14b43a840c791699747ba4cc0ed5abf2bda218reed@android.com            left -= 1;
5536c14b43a840c791699747ba4cc0ed5abf2bda218reed@android.com            right += 1;
5546c14b43a840c791699747ba4cc0ed5abf2bda218reed@android.com#endif
555bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org            if (left >= clip->fRight || right <= clip->fLeft) {
5568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                return;
557bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org            }
558bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org            if (clip->fLeft <= left && clip->fRight >= right) {
5598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                clip = NULL;
560bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org            }
5618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
5628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRectClipBlitter   rectClipper;
565bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org    if (clip) {
5668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        rectClipper.init(blitter, *clip);
5678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        blitter = &rectClipper;
5688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
569fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
570b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    SkASSERT(hairBlitter);
571b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    hairBlitter->setup(blitter);
572b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com
573c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com#ifdef SK_DEBUG
574c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com    if (scaleStart > 0 && scaleStop > 0) {
575c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com        // be sure we don't draw twice in the same pixel
576c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com        SkASSERT(istart < istop - 1);
577c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com    }
578c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com#endif
579c1f6db86dcf478d3c067bfc3fd99174b23d81732reed@google.com
580b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com    fstart = hairBlitter->drawCap(istart, fstart, slope, scaleStart);
5818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    istart += 1;
58228937283e16928a562b3f9e19908db51bbb89ff9reed@android.com    int fullSpans = istop - istart - (scaleStop > 0);
5838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fullSpans > 0) {
584b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        fstart = hairBlitter->drawLine(istart, istart + fullSpans, fstart, slope);
5858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (scaleStop > 0) {
587b03fe429e83d7a32b05a5ee8423e4f62ba6380fareed@google.com        hairBlitter->drawCap(istop - 1, fstart, slope, scaleStop);
5888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
591045e62d715f5ee9b03deb5af3c750f8318096179reed@google.comvoid SkScan::AntiHairLineRgn(const SkPoint& pt0, const SkPoint& pt1,
592045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com                             const SkRegion* clip, SkBlitter* blitter) {
593bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org    if (clip && clip->isEmpty()) {
5948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
595bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org    }
5968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(clip == NULL || !clip->getBounds().isEmpty());
5988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef TEST_GAMMA
6008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    build_gamma_table();
6018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
6028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
603e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    SkPoint pts[2] = { pt0, pt1 };
6048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
60599b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com    // We have to pre-clip the line to fit in a SkFixed, so we just chop
60699b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com    // the line. TODO find a way to actually draw beyond that range.
60799b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com    {
60899b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com        SkRect fixedBounds;
60999b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com        const SkScalar max = SkIntToScalar(32767);
61099b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com        fixedBounds.set(-max, -max, max, max);
61199b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com        if (!SkLineClipper::IntersectLine(pts, fixedBounds, pts)) {
61299b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com            return;
61399b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com        }
61499b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com    }
61599b300ed9dcd09db544dd985cdd95a2ea284cb7creed@google.com
616e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    if (clip) {
617e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        SkRect clipBounds;
618e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        clipBounds.set(clip->getBounds());
619a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com        /*  We perform integral clipping later on, but we do a scalar clip first
620a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com            to ensure that our coordinates are expressible in fixed/integers.
621a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com
622a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com            antialiased hairlines can draw up to 1/2 of a pixel outside of
623a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com            their bounds, so we need to outset the clip before calling the
624a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com            clipper. To make the numerics safer, we outset by a whole pixel,
625a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com            since the 1/2 pixel boundary is important to the antihair blitter,
626a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com            we don't want to risk numerical fate by chopping on that edge.
627a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com         */
628a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com        clipBounds.inset(-SK_Scalar1, -SK_Scalar1);
629a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com
630e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        if (!SkLineClipper::IntersectLine(pts, clipBounds, pts)) {
631e28ff55d980d2992618b6b721c848aba96cf759areed@android.com            return;
632e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        }
633e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    }
634fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
635e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    SkFDot6 x0 = SkScalarToFDot6(pts[0].fX);
636e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    SkFDot6 y0 = SkScalarToFDot6(pts[0].fY);
637e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    SkFDot6 x1 = SkScalarToFDot6(pts[1].fX);
638e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    SkFDot6 y1 = SkScalarToFDot6(pts[1].fY);
639e28ff55d980d2992618b6b721c848aba96cf759areed@android.com
640e28ff55d980d2992618b6b721c848aba96cf759areed@android.com    if (clip) {
641e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        SkFDot6 left = SkMin32(x0, x1);
642e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        SkFDot6 top = SkMin32(y0, y1);
643e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        SkFDot6 right = SkMax32(x0, x1);
644e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        SkFDot6 bottom = SkMax32(y0, y1);
645e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        SkIRect ir;
6468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        ir.set( SkFDot6Floor(left) - 1,
6488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkFDot6Floor(top) - 1,
6498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkFDot6Ceil(right) + 1,
6508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkFDot6Ceil(bottom) + 1);
6518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
652e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        if (clip->quickReject(ir)) {
6538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return;
654e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        }
655e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        if (!clip->quickContains(ir)) {
6568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkRegion::Cliperator iter(*clip, ir);
6578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            const SkIRect*       r = &iter.rect();
6588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
659e28ff55d980d2992618b6b721c848aba96cf759areed@android.com            while (!iter.done()) {
6608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                do_anti_hairline(x0, y0, x1, y1, r, blitter);
6618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                iter.next();
6628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
6638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return;
6648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
6658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // fall through to no-clip case
6668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    do_anti_hairline(x0, y0, x1, y1, NULL, blitter);
6688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
670045e62d715f5ee9b03deb5af3c750f8318096179reed@google.comvoid SkScan::AntiHairRect(const SkRect& rect, const SkRasterClip& clip,
671bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org                          SkBlitter* blitter) {
6728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint p0, p1;
6738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    p0.set(rect.fLeft, rect.fTop);
6758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    p1.set(rect.fRight, rect.fTop);
6768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScan::AntiHairLine(p0, p1, clip, blitter);
6778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    p0.set(rect.fRight, rect.fBottom);
6788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScan::AntiHairLine(p0, p1, clip, blitter);
6798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    p1.set(rect.fLeft, rect.fBottom);
6808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScan::AntiHairLine(p0, p1, clip, blitter);
6818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    p0.set(rect.fLeft, rect.fTop);
6828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScan::AntiHairLine(p0, p1, clip, blitter);
6838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
685bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org///////////////////////////////////////////////////////////////////////////////
6868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comtypedef int FDot8;  // 24.8 integer fixed point
6888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline FDot8 SkFixedToFDot8(SkFixed x) {
6908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return (x + 0x80) >> 8;
6918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
693bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.orgstatic void do_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha,
694bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org                        SkBlitter* blitter) {
6958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(L < R);
696fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
697bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org    if ((L >> 8) == ((R - 1) >> 8)) {  // 1x1 pixel
6988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        blitter->blitV(L >> 8, top, 1, SkAlphaMul(alpha, R - L));
6998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
7008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
701fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
7028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int left = L >> 8;
703fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
704bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org    if (L & 0xFF) {
7058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        blitter->blitV(left, top, 1, SkAlphaMul(alpha, 256 - (L & 0xFF)));
7068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        left += 1;
7078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int rite = R >> 8;
7108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int width = rite - left;
711bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org    if (width > 0) {
7128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        call_hline_blitter(blitter, left, top, width, alpha);
713bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org    }
714bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org    if (R & 0xFF) {
7158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        blitter->blitV(rite, top, 1, SkAlphaMul(alpha, R & 0xFF));
716bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org    }
7178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
7188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7197ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.orgstatic void antifilldot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B, SkBlitter* blitter,
7207ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org                         bool fillInner) {
7218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // check for empty now that we're in our reduced precision space
722bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org    if (L >= R || T >= B) {
7238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
724bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org    }
7258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int top = T >> 8;
726bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org    if (top == ((B - 1) >> 8)) {   // just one scanline high
7278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        do_scanline(L, top, R, B - T - 1, blitter);
7288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
7298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
730fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
731bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org    if (T & 0xFF) {
7328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        do_scanline(L, top, R, 256 - (T & 0xFF), blitter);
7338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        top += 1;
7348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
735fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
7368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int bot = B >> 8;
7378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int height = bot - top;
738bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org    if (height > 0) {
7398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int left = L >> 8;
740f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com        if (left == ((R - 1) >> 8)) {   // just 1-pixel wide
741f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com            blitter->blitV(left, top, height, R - L - 1);
742f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com        } else {
743f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com            if (L & 0xFF) {
744f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com                blitter->blitV(left, top, height, 256 - (L & 0xFF));
745f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com                left += 1;
746f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com            }
747f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com            int rite = R >> 8;
748f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com            int width = rite - left;
749f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com            if (width > 0 && fillInner) {
750f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com                blitter->blitRect(left, top, width, height);
751f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com            }
752f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com            if (R & 0xFF) {
753f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com                blitter->blitV(rite, top, height, R & 0xFF);
754f7398c3ab61053597541fa0b3cfc710006a3e62breed@google.com            }
755bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org        }
7568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
757fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
758bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org    if (B & 0xFF) {
7598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        do_scanline(L, bot, R, B & 0xFF, blitter);
760bcc1d33e9453d7749a8691e4c8c6379a02b9bf72mike@reedtribe.org    }
7618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
7628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7637ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.orgstatic void antifillrect(const SkXRect& xr, SkBlitter* blitter) {
7647ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    antifilldot8(SkFixedToFDot8(xr.fLeft), SkFixedToFDot8(xr.fTop),
7657ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org                 SkFixedToFDot8(xr.fRight), SkFixedToFDot8(xr.fBottom),
7667ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org                 blitter, true);
7677ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org}
7687ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org
7698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
7708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
77167ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.comvoid SkScan::AntiFillXRect(const SkXRect& xr, const SkRegion* clip,
7728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                          SkBlitter* blitter) {
77367ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com    if (NULL == clip) {
77467ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com        antifillrect(xr, blitter);
77567ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com    } else {
77667ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com        SkIRect outerBounds;
77767ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com        XRect_roundOut(xr, &outerBounds);
77867ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com
77967ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com        if (clip->isRect()) {
78067ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com            const SkIRect& clipBounds = clip->getBounds();
78167ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com
78267ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com            if (clipBounds.contains(outerBounds)) {
78367ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com                antifillrect(xr, blitter);
78467ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com            } else {
78567ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com                SkXRect tmpR;
78667ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com                // this keeps our original edges fractional
78767ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com                XRect_set(&tmpR, clipBounds);
78867ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com                if (tmpR.intersect(xr)) {
78967ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com                    antifillrect(tmpR, blitter);
79067ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com                }
79167ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com            }
7928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } else {
79367ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com            SkRegion::Cliperator clipper(*clip, outerBounds);
79467ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com            const SkIRect&       rr = clipper.rect();
795fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
79667ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com            while (!clipper.done()) {
79767ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com                SkXRect  tmpR;
798fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
79967ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com                // this keeps our original edges fractional
80067ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com                XRect_set(&tmpR, rr);
80167ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com                if (tmpR.intersect(xr)) {
80267ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com                    antifillrect(tmpR, blitter);
80367ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com                }
80467ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com                clipper.next();
8058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
8068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
80767ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com    }
80867ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com}
80967ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com
81067ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.comvoid SkScan::AntiFillXRect(const SkXRect& xr, const SkRasterClip& clip,
81167ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com                           SkBlitter* blitter) {
81267ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com    if (clip.isBW()) {
81367ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com        AntiFillXRect(xr, &clip.bwRgn(), blitter);
8148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
81567ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com        SkIRect outerBounds;
81667ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com        XRect_roundOut(xr, &outerBounds);
81767ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com
81867ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com        if (clip.quickContains(outerBounds)) {
81967ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com            AntiFillXRect(xr, NULL, blitter);
82067ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com        } else {
82167ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com            SkAAClipBlitterWrapper wrapper(clip, blitter);
82267ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com            blitter = wrapper.getBlitter();
82367ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com
82467ba5fa3283185f29c22e9b8daad521de0d00b23reed@google.com            AntiFillXRect(xr, &wrapper.getRgn(), wrapper.getBlitter());
825045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com        }
8268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
8278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*  This guy takes a float-rect, but with the key improvement that it has
8308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    already been clipped, so we know that it is safe to convert it into a
8318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    XRect (fixedpoint), as it won't overflow.
8328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/
8338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void antifillrect(const SkRect& r, SkBlitter* blitter) {
8348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkXRect xr;
835fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
8368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    XRect_set(&xr, r);
8378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    antifillrect(xr, blitter);
8388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*  We repeat the clipping logic of AntiFillXRect because the float rect might
8418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    overflow if we blindly converted it to an XRect. This sucks that we have to
8428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    repeat the clipping logic, but I don't see how to share the code/logic.
843fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
8448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    We clip r (as needed) into one or more (smaller) float rects, and then pass
8458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    those to our version of antifillrect, which converts it into an XRect and
8468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    then calls the blit.
8478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/
848e28ff55d980d2992618b6b721c848aba96cf759areed@android.comvoid SkScan::AntiFillRect(const SkRect& origR, const SkRegion* clip,
8498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                          SkBlitter* blitter) {
8508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (clip) {
851e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        SkRect newR;
852e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        newR.set(clip->getBounds());
853e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        if (!newR.intersect(origR)) {
854e28ff55d980d2992618b6b721c848aba96cf759areed@android.com            return;
855e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        }
856e28ff55d980d2992618b6b721c848aba96cf759areed@android.com
8578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkIRect outerBounds;
858e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        newR.roundOut(&outerBounds);
859fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
8608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (clip->isRect()) {
861e28ff55d980d2992618b6b721c848aba96cf759areed@android.com            antifillrect(newR, blitter);
8628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } else {
8638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkRegion::Cliperator clipper(*clip, outerBounds);
8648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            while (!clipper.done()) {
865e28ff55d980d2992618b6b721c848aba96cf759areed@android.com                newR.set(clipper.rect());
866e28ff55d980d2992618b6b721c848aba96cf759areed@android.com                if (newR.intersect(origR)) {
867e28ff55d980d2992618b6b721c848aba96cf759areed@android.com                    antifillrect(newR, blitter);
8688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
8698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                clipper.next();
8708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
8718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
8728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
873e28ff55d980d2992618b6b721c848aba96cf759areed@android.com        antifillrect(origR, blitter);
8748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
8758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
877045e62d715f5ee9b03deb5af3c750f8318096179reed@google.comvoid SkScan::AntiFillRect(const SkRect& r, const SkRasterClip& clip,
878045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com                          SkBlitter* blitter) {
879045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    if (clip.isBW()) {
880045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com        AntiFillRect(r, &clip.bwRgn(), blitter);
881045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    } else {
882045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com        SkAAClipBlitterWrapper wrap(clip, blitter);
883045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com        AntiFillRect(r, &wrap.getRgn(), wrap.getBlitter());
884045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    }
885045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com}
886045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com
8877ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org///////////////////////////////////////////////////////////////////////////////
8887ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org
8893a968750b29b3bb15452a4d4ed040c382727a297reed@google.com#define SkAlphaMulRound(a, b)   SkMulDiv255Round(a, b)
8903a968750b29b3bb15452a4d4ed040c382727a297reed@google.com
8917ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org// calls blitRect() if the rectangle is non-empty
8927ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.orgstatic void fillcheckrect(int L, int T, int R, int B, SkBlitter* blitter) {
8937ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    if (L < R && T < B) {
8947ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        blitter->blitRect(L, T, R - L, B - T);
8957ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    }
8967ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org}
8977ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org
8987ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.orgstatic inline FDot8 SkScalarToFDot8(SkScalar x) {
8997ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    return (int)(x * 256);
9007ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org}
9017ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org
9027ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.orgstatic inline int FDot8Floor(FDot8 x) {
9037ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    return x >> 8;
9047ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org}
9057ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org
9067ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.orgstatic inline int FDot8Ceil(FDot8 x) {
9077ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    return (x + 0xFF) >> 8;
9087ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org}
9097ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org
9107ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org// 1 - (1 - a)*(1 - b)
9117ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.orgstatic inline U8CPU InvAlphaMul(U8CPU a, U8CPU b) {
9123a968750b29b3bb15452a4d4ed040c382727a297reed@google.com    // need precise rounding (not just SkAlphaMul) so that values like
9133a968750b29b3bb15452a4d4ed040c382727a297reed@google.com    // a=228, b=252 don't overflow the result
9143a968750b29b3bb15452a4d4ed040c382727a297reed@google.com    return SkToU8(a + b - SkAlphaMulRound(a, b));
9157ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org}
9167ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org
9177ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.orgstatic void inner_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha,
9187ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org                           SkBlitter* blitter) {
9197ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    SkASSERT(L < R);
920fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
9217ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    if ((L >> 8) == ((R - 1) >> 8)) {  // 1x1 pixel
9227ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        blitter->blitV(L >> 8, top, 1, InvAlphaMul(alpha, R - L));
9237ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        return;
9247ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    }
925fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
9267ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    int left = L >> 8;
9277ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    if (L & 0xFF) {
9287ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        blitter->blitV(left, top, 1, InvAlphaMul(alpha, L & 0xFF));
9297ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        left += 1;
9307ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    }
931fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
9327ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    int rite = R >> 8;
9337ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    int width = rite - left;
9347ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    if (width > 0) {
9357ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        call_hline_blitter(blitter, left, top, width, alpha);
9367ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    }
937fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
9387ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    if (R & 0xFF) {
9397ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        blitter->blitV(rite, top, 1, InvAlphaMul(alpha, ~R & 0xFF));
9407ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    }
9417ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org}
9427ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org
9437ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.orgstatic void innerstrokedot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B,
9447ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org                            SkBlitter* blitter) {
9457ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    SkASSERT(L < R && T < B);
9467ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org
9477ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    int top = T >> 8;
9487ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    if (top == ((B - 1) >> 8)) {   // just one scanline high
94910d02b6ba9f626af5a26a82c288e1beb0002914dreed@google.com        // We want the inverse of B-T, since we're the inner-stroke
95010d02b6ba9f626af5a26a82c288e1beb0002914dreed@google.com        int alpha = 256 - (B - T);
95110d02b6ba9f626af5a26a82c288e1beb0002914dreed@google.com        if (alpha) {
95210d02b6ba9f626af5a26a82c288e1beb0002914dreed@google.com            inner_scanline(L, top, R, alpha, blitter);
95310d02b6ba9f626af5a26a82c288e1beb0002914dreed@google.com        }
9547ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        return;
9557ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    }
956fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
9577ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    if (T & 0xFF) {
9587ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        inner_scanline(L, top, R, T & 0xFF, blitter);
9597ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        top += 1;
9607ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    }
961fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
9627ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    int bot = B >> 8;
9637ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    int height = bot - top;
9647ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    if (height > 0) {
9657ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        if (L & 0xFF) {
9667ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org            blitter->blitV(L >> 8, top, height, L & 0xFF);
9677ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        }
9687ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        if (R & 0xFF) {
9697ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org            blitter->blitV(R >> 8, top, height, ~R & 0xFF);
9707ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        }
9717ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    }
972fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
9737ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    if (B & 0xFF) {
9747ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        inner_scanline(L, bot, R, ~B & 0xFF, blitter);
9757ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    }
9767ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org}
9777ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org
978761fb62b0eb174783316d2a8b933fba896ca6355reed@google.comvoid SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize,
9797ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org                           const SkRegion* clip, SkBlitter* blitter) {
980761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com    SkASSERT(strokeSize.fX >= 0 && strokeSize.fY >= 0);
9817ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org
982761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com    SkScalar rx = SkScalarHalf(strokeSize.fX);
983761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com    SkScalar ry = SkScalarHalf(strokeSize.fY);
9847ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org
9857ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    // outset by the radius
986761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com    FDot8 L = SkScalarToFDot8(r.fLeft - rx);
987761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com    FDot8 T = SkScalarToFDot8(r.fTop - ry);
988761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com    FDot8 R = SkScalarToFDot8(r.fRight + rx);
989761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com    FDot8 B = SkScalarToFDot8(r.fBottom + ry);
9907ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org
9917ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    SkIRect outer;
9927ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    // set outer to the outer rect of the outer section
9937ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    outer.set(FDot8Floor(L), FDot8Floor(T), FDot8Ceil(R), FDot8Ceil(B));
9947ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org
9957ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    SkBlitterClipper clipper;
9967ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    if (clip) {
9977ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        if (clip->quickReject(outer)) {
9987ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org            return;
9997ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        }
10007ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        if (!clip->contains(outer)) {
10017ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org            blitter = clipper.apply(blitter, clip, &outer);
10027ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        }
10037ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        // now we can ignore clip for the rest of the function
10047ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    }
1005fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
10067ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    // stroke the outer hull
10077ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    antifilldot8(L, T, R, B, blitter, false);
10087ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org
10097ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    // set outer to the outer rect of the middle section
10107ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    outer.set(FDot8Ceil(L), FDot8Ceil(T), FDot8Floor(R), FDot8Floor(B));
10117ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org
10127ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    // in case we lost a bit with diameter/2
1013761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com    rx = strokeSize.fX - rx;
1014761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com    ry = strokeSize.fY - ry;
10157ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    // inset by the radius
1016761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com    L = SkScalarToFDot8(r.fLeft + rx);
1017761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com    T = SkScalarToFDot8(r.fTop + ry);
1018761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com    R = SkScalarToFDot8(r.fRight - rx);
1019761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com    B = SkScalarToFDot8(r.fBottom - ry);
10207ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org
10217ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    if (L >= R || T >= B) {
10227ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, outer.fBottom,
10237ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org                      blitter);
10247ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    } else {
10257ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        SkIRect inner;
10267ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        // set inner to the inner rect of the middle section
10277ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        inner.set(FDot8Floor(L), FDot8Floor(T), FDot8Ceil(R), FDot8Ceil(B));
10287ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org
10297ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        // draw the frame in 4 pieces
10307ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, inner.fTop,
10317ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org                      blitter);
10327ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        fillcheckrect(outer.fLeft, inner.fTop, inner.fLeft, inner.fBottom,
10337ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org                      blitter);
10347ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        fillcheckrect(inner.fRight, inner.fTop, outer.fRight, inner.fBottom,
10357ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org                      blitter);
10367ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        fillcheckrect(outer.fLeft, inner.fBottom, outer.fRight, outer.fBottom,
10377ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org                      blitter);
10387ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org
10397ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        // now stroke the inner rect, which is similar to antifilldot8() except that
10407ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        // it treats the fractional coordinates with the inverse bias (since its
10417ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        // inner).
10427ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org        innerstrokedot8(L, T, R, B, blitter);
10437ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org    }
10447ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org}
1045045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com
1046045e62d715f5ee9b03deb5af3c750f8318096179reed@google.comvoid SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize,
1047045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com                           const SkRasterClip& clip, SkBlitter* blitter) {
1048045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    if (clip.isBW()) {
1049045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com        AntiFrameRect(r, strokeSize, &clip.bwRgn(), blitter);
1050045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    } else {
1051045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com        SkAAClipBlitterWrapper wrap(clip, blitter);
1052045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com        AntiFrameRect(r, strokeSize, &wrap.getRgn(), wrap.getBlitter());
1053045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    }
1054045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com}
1055