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