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