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