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