1
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#ifndef SkAntiRun_DEFINED
11#define SkAntiRun_DEFINED
12
13#include "SkBlitter.h"
14
15/** Sparse array of run-length-encoded alpha (supersampling coverage) values.
16    Sparseness allows us to independently compose several paths into the
17    same SkAlphaRuns buffer.
18*/
19
20class SkAlphaRuns {
21public:
22    int16_t*    fRuns;
23    uint8_t*     fAlpha;
24
25    /// Returns true if the scanline contains only a single run,
26    /// of alpha value 0.
27    bool empty() const {
28        SkASSERT(fRuns[0] > 0);
29        return fAlpha[0] == 0 && fRuns[fRuns[0]] == 0;
30    }
31
32    /// Reinitialize for a new scanline.
33    void    reset(int width);
34
35    /**
36     *  Insert into the buffer a run starting at (x-offsetX):
37     *      if startAlpha > 0
38     *          one pixel with value += startAlpha,
39     *              max 255
40     *      if middleCount > 0
41     *          middleCount pixels with value += maxValue
42     *      if stopAlpha > 0
43     *          one pixel with value += stopAlpha
44     *  Returns the offsetX value that should be passed on the next call,
45     *  assuming we're on the same scanline. If the caller is switching
46     *  scanlines, then offsetX should be 0 when this is called.
47     */
48    SK_ALWAYS_INLINE int add(int x, U8CPU startAlpha, int middleCount, U8CPU stopAlpha,
49                             U8CPU maxValue, int offsetX) {
50        SkASSERT(middleCount >= 0);
51        SkASSERT(x >= 0 && x + (startAlpha != 0) + middleCount + (stopAlpha != 0) <= fWidth);
52
53        SkASSERT(fRuns[offsetX] >= 0);
54
55        int16_t*    runs = fRuns + offsetX;
56        uint8_t*    alpha = fAlpha + offsetX;
57        uint8_t*    lastAlpha = alpha;
58        x -= offsetX;
59
60        if (startAlpha) {
61            SkAlphaRuns::Break(runs, alpha, x, 1);
62            /*  I should be able to just add alpha[x] + startAlpha.
63                However, if the trailing edge of the previous span and the leading
64                edge of the current span round to the same super-sampled x value,
65                I might overflow to 256 with this add, hence the funny subtract (crud).
66            */
67            unsigned tmp = alpha[x] + startAlpha;
68            SkASSERT(tmp <= 256);
69            alpha[x] = SkToU8(tmp - (tmp >> 8));    // was (tmp >> 7), but that seems wrong if we're trying to catch 256
70
71            runs += x + 1;
72            alpha += x + 1;
73            x = 0;
74            SkDEBUGCODE(this->validate();)
75        }
76
77        if (middleCount) {
78            SkAlphaRuns::Break(runs, alpha, x, middleCount);
79            alpha += x;
80            runs += x;
81            x = 0;
82            do {
83                alpha[0] = SkToU8(alpha[0] + maxValue);
84                int n = runs[0];
85                SkASSERT(n <= middleCount);
86                alpha += n;
87                runs += n;
88                middleCount -= n;
89            } while (middleCount > 0);
90            SkDEBUGCODE(this->validate();)
91            lastAlpha = alpha;
92        }
93
94        if (stopAlpha) {
95            SkAlphaRuns::Break(runs, alpha, x, 1);
96            alpha += x;
97            alpha[0] = SkToU8(alpha[0] + stopAlpha);
98            SkDEBUGCODE(this->validate();)
99            lastAlpha = alpha;
100        }
101
102        return SkToS32(lastAlpha - fAlpha);  // new offsetX
103    }
104
105    SkDEBUGCODE(void assertValid(int y, int maxStep) const;)
106    SkDEBUGCODE(void dump() const;)
107
108    /**
109     * Break the runs in the buffer at offsets x and x+count, properly
110     * updating the runs to the right and left.
111     *   i.e. from the state AAAABBBB, run-length encoded as A4B4,
112     *   Break(..., 2, 5) would produce AAAABBBB rle as A2A2B3B1.
113     * Allows add() to sum another run to some of the new sub-runs.
114     *   i.e. adding ..CCCCC. would produce AADDEEEB, rle as A2D2E3B1.
115     */
116    static void Break(int16_t runs[], uint8_t alpha[], int x, int count) {
117        SkASSERT(count > 0 && x >= 0);
118
119        //  SkAlphaRuns::BreakAt(runs, alpha, x);
120        //  SkAlphaRuns::BreakAt(&runs[x], &alpha[x], count);
121
122        int16_t* next_runs = runs + x;
123        uint8_t*  next_alpha = alpha + x;
124
125        while (x > 0) {
126            int n = runs[0];
127            SkASSERT(n > 0);
128
129            if (x < n) {
130                alpha[x] = alpha[0];
131                runs[0] = SkToS16(x);
132                runs[x] = SkToS16(n - x);
133                break;
134            }
135            runs += n;
136            alpha += n;
137            x -= n;
138        }
139
140        runs = next_runs;
141        alpha = next_alpha;
142        x = count;
143
144        for (;;) {
145            int n = runs[0];
146            SkASSERT(n > 0);
147
148            if (x < n) {
149                alpha[x] = alpha[0];
150                runs[0] = SkToS16(x);
151                runs[x] = SkToS16(n - x);
152                break;
153            }
154            x -= n;
155            if (x <= 0) {
156                break;
157            }
158            runs += n;
159            alpha += n;
160        }
161    }
162
163    /**
164     * Cut (at offset x in the buffer) a run into two shorter runs with
165     * matching alpha values.
166     * Used by the RectClipBlitter to trim a RLE encoding to match the
167     * clipping rectangle.
168     */
169    static void BreakAt(int16_t runs[], uint8_t alpha[], int x) {
170        while (x > 0) {
171            int n = runs[0];
172            SkASSERT(n > 0);
173
174            if (x < n) {
175                alpha[x] = alpha[0];
176                runs[0] = SkToS16(x);
177                runs[x] = SkToS16(n - x);
178                break;
179            }
180            runs += n;
181            alpha += n;
182            x -= n;
183        }
184    }
185
186private:
187    SkDEBUGCODE(int fWidth;)
188    SkDEBUGCODE(void validate() const;)
189};
190
191#endif
192