• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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             lastAlpha += x; // we don't want the +1
75             SkDEBUGCODE(this->validate();)
76         }
77 
78         if (middleCount) {
79             SkAlphaRuns::Break(runs, alpha, x, middleCount);
80             alpha += x;
81             runs += x;
82             x = 0;
83             do {
84                 alpha[0] = SkToU8(alpha[0] + maxValue);
85                 int n = runs[0];
86                 SkASSERT(n <= middleCount);
87                 alpha += n;
88                 runs += n;
89                 middleCount -= n;
90             } while (middleCount > 0);
91             SkDEBUGCODE(this->validate();)
92             lastAlpha = alpha;
93         }
94 
95         if (stopAlpha) {
96             SkAlphaRuns::Break(runs, alpha, x, 1);
97             alpha += x;
98             alpha[0] = SkToU8(alpha[0] + stopAlpha);
99             SkDEBUGCODE(this->validate();)
100             lastAlpha = alpha;
101         }
102 
103         return SkToS32(lastAlpha - fAlpha);  // new offsetX
104     }
105 
106     SkDEBUGCODE(void assertValid(int y, int maxStep) const;)
SkDEBUGCODE(void dump ()const;)107     SkDEBUGCODE(void dump() const;)
108 
109     /**
110      * Break the runs in the buffer at offsets x and x+count, properly
111      * updating the runs to the right and left.
112      *   i.e. from the state AAAABBBB, run-length encoded as A4B4,
113      *   Break(..., 2, 5) would produce AAAABBBB rle as A2A2B3B1.
114      * Allows add() to sum another run to some of the new sub-runs.
115      *   i.e. adding ..CCCCC. would produce AADDEEEB, rle as A2D2E3B1.
116      */
117     static void Break(int16_t runs[], uint8_t alpha[], int x, int count) {
118         SkASSERT(count > 0 && x >= 0);
119 
120         //  SkAlphaRuns::BreakAt(runs, alpha, x);
121         //  SkAlphaRuns::BreakAt(&runs[x], &alpha[x], count);
122 
123         int16_t* next_runs = runs + x;
124         uint8_t*  next_alpha = alpha + x;
125 
126         while (x > 0) {
127             int n = runs[0];
128             SkASSERT(n > 0);
129 
130             if (x < n) {
131                 alpha[x] = alpha[0];
132                 runs[0] = SkToS16(x);
133                 runs[x] = SkToS16(n - x);
134                 break;
135             }
136             runs += n;
137             alpha += n;
138             x -= n;
139         }
140 
141         runs = next_runs;
142         alpha = next_alpha;
143         x = count;
144 
145         for (;;) {
146             int n = runs[0];
147             SkASSERT(n > 0);
148 
149             if (x < n) {
150                 alpha[x] = alpha[0];
151                 runs[0] = SkToS16(x);
152                 runs[x] = SkToS16(n - x);
153                 break;
154             }
155             x -= n;
156             if (x <= 0) {
157                 break;
158             }
159             runs += n;
160             alpha += n;
161         }
162     }
163 
164     /**
165      * Cut (at offset x in the buffer) a run into two shorter runs with
166      * matching alpha values.
167      * Used by the RectClipBlitter to trim a RLE encoding to match the
168      * clipping rectangle.
169      */
BreakAt(int16_t runs[],uint8_t alpha[],int x)170     static void BreakAt(int16_t runs[], uint8_t alpha[], int x) {
171         while (x > 0) {
172             int n = runs[0];
173             SkASSERT(n > 0);
174 
175             if (x < n) {
176                 alpha[x] = alpha[0];
177                 runs[0] = SkToS16(x);
178                 runs[x] = SkToS16(n - x);
179                 break;
180             }
181             runs += n;
182             alpha += n;
183             x -= n;
184         }
185     }
186 
187 private:
188     SkDEBUGCODE(int fWidth;)
189     SkDEBUGCODE(void validate() const;)
190 };
191 
192 #endif
193