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