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 
20 class SkAlphaRuns {
21 public:
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.
empty()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      */
add(int x,U8CPU startAlpha,int middleCount,U8CPU stopAlpha,U8CPU maxValue,int offsetX)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;)
SkDEBUGCODE(void dump ()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      */
BreakAt(int16_t runs[],uint8_t alpha[],int x)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 
186 private:
187     SkDEBUGCODE(int fWidth;)
188     SkDEBUGCODE(void validate() const;)
189 };
190 
191 #endif
192