1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/core/SkAntiRun.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,192 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2006 The Android Open Source Project 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 + 1.13 +#ifndef SkAntiRun_DEFINED 1.14 +#define SkAntiRun_DEFINED 1.15 + 1.16 +#include "SkBlitter.h" 1.17 + 1.18 +/** Sparse array of run-length-encoded alpha (supersampling coverage) values. 1.19 + Sparseness allows us to independently compose several paths into the 1.20 + same SkAlphaRuns buffer. 1.21 +*/ 1.22 + 1.23 +class SkAlphaRuns { 1.24 +public: 1.25 + int16_t* fRuns; 1.26 + uint8_t* fAlpha; 1.27 + 1.28 + /// Returns true if the scanline contains only a single run, 1.29 + /// of alpha value 0. 1.30 + bool empty() const { 1.31 + SkASSERT(fRuns[0] > 0); 1.32 + return fAlpha[0] == 0 && fRuns[fRuns[0]] == 0; 1.33 + } 1.34 + 1.35 + /// Reinitialize for a new scanline. 1.36 + void reset(int width); 1.37 + 1.38 + /** 1.39 + * Insert into the buffer a run starting at (x-offsetX): 1.40 + * if startAlpha > 0 1.41 + * one pixel with value += startAlpha, 1.42 + * max 255 1.43 + * if middleCount > 0 1.44 + * middleCount pixels with value += maxValue 1.45 + * if stopAlpha > 0 1.46 + * one pixel with value += stopAlpha 1.47 + * Returns the offsetX value that should be passed on the next call, 1.48 + * assuming we're on the same scanline. If the caller is switching 1.49 + * scanlines, then offsetX should be 0 when this is called. 1.50 + */ 1.51 + SK_ALWAYS_INLINE int add(int x, U8CPU startAlpha, int middleCount, U8CPU stopAlpha, 1.52 + U8CPU maxValue, int offsetX) { 1.53 + SkASSERT(middleCount >= 0); 1.54 + SkASSERT(x >= 0 && x + (startAlpha != 0) + middleCount + (stopAlpha != 0) <= fWidth); 1.55 + 1.56 + SkASSERT(fRuns[offsetX] >= 0); 1.57 + 1.58 + int16_t* runs = fRuns + offsetX; 1.59 + uint8_t* alpha = fAlpha + offsetX; 1.60 + uint8_t* lastAlpha = alpha; 1.61 + x -= offsetX; 1.62 + 1.63 + if (startAlpha) { 1.64 + SkAlphaRuns::Break(runs, alpha, x, 1); 1.65 + /* I should be able to just add alpha[x] + startAlpha. 1.66 + However, if the trailing edge of the previous span and the leading 1.67 + edge of the current span round to the same super-sampled x value, 1.68 + I might overflow to 256 with this add, hence the funny subtract (crud). 1.69 + */ 1.70 + unsigned tmp = alpha[x] + startAlpha; 1.71 + SkASSERT(tmp <= 256); 1.72 + alpha[x] = SkToU8(tmp - (tmp >> 8)); // was (tmp >> 7), but that seems wrong if we're trying to catch 256 1.73 + 1.74 + runs += x + 1; 1.75 + alpha += x + 1; 1.76 + x = 0; 1.77 + lastAlpha += x; // we don't want the +1 1.78 + SkDEBUGCODE(this->validate();) 1.79 + } 1.80 + 1.81 + if (middleCount) { 1.82 + SkAlphaRuns::Break(runs, alpha, x, middleCount); 1.83 + alpha += x; 1.84 + runs += x; 1.85 + x = 0; 1.86 + do { 1.87 + alpha[0] = SkToU8(alpha[0] + maxValue); 1.88 + int n = runs[0]; 1.89 + SkASSERT(n <= middleCount); 1.90 + alpha += n; 1.91 + runs += n; 1.92 + middleCount -= n; 1.93 + } while (middleCount > 0); 1.94 + SkDEBUGCODE(this->validate();) 1.95 + lastAlpha = alpha; 1.96 + } 1.97 + 1.98 + if (stopAlpha) { 1.99 + SkAlphaRuns::Break(runs, alpha, x, 1); 1.100 + alpha += x; 1.101 + alpha[0] = SkToU8(alpha[0] + stopAlpha); 1.102 + SkDEBUGCODE(this->validate();) 1.103 + lastAlpha = alpha; 1.104 + } 1.105 + 1.106 + return SkToS32(lastAlpha - fAlpha); // new offsetX 1.107 + } 1.108 + 1.109 + SkDEBUGCODE(void assertValid(int y, int maxStep) const;) 1.110 + SkDEBUGCODE(void dump() const;) 1.111 + 1.112 + /** 1.113 + * Break the runs in the buffer at offsets x and x+count, properly 1.114 + * updating the runs to the right and left. 1.115 + * i.e. from the state AAAABBBB, run-length encoded as A4B4, 1.116 + * Break(..., 2, 5) would produce AAAABBBB rle as A2A2B3B1. 1.117 + * Allows add() to sum another run to some of the new sub-runs. 1.118 + * i.e. adding ..CCCCC. would produce AADDEEEB, rle as A2D2E3B1. 1.119 + */ 1.120 + static void Break(int16_t runs[], uint8_t alpha[], int x, int count) { 1.121 + SkASSERT(count > 0 && x >= 0); 1.122 + 1.123 + // SkAlphaRuns::BreakAt(runs, alpha, x); 1.124 + // SkAlphaRuns::BreakAt(&runs[x], &alpha[x], count); 1.125 + 1.126 + int16_t* next_runs = runs + x; 1.127 + uint8_t* next_alpha = alpha + x; 1.128 + 1.129 + while (x > 0) { 1.130 + int n = runs[0]; 1.131 + SkASSERT(n > 0); 1.132 + 1.133 + if (x < n) { 1.134 + alpha[x] = alpha[0]; 1.135 + runs[0] = SkToS16(x); 1.136 + runs[x] = SkToS16(n - x); 1.137 + break; 1.138 + } 1.139 + runs += n; 1.140 + alpha += n; 1.141 + x -= n; 1.142 + } 1.143 + 1.144 + runs = next_runs; 1.145 + alpha = next_alpha; 1.146 + x = count; 1.147 + 1.148 + for (;;) { 1.149 + int n = runs[0]; 1.150 + SkASSERT(n > 0); 1.151 + 1.152 + if (x < n) { 1.153 + alpha[x] = alpha[0]; 1.154 + runs[0] = SkToS16(x); 1.155 + runs[x] = SkToS16(n - x); 1.156 + break; 1.157 + } 1.158 + x -= n; 1.159 + if (x <= 0) { 1.160 + break; 1.161 + } 1.162 + runs += n; 1.163 + alpha += n; 1.164 + } 1.165 + } 1.166 + 1.167 + /** 1.168 + * Cut (at offset x in the buffer) a run into two shorter runs with 1.169 + * matching alpha values. 1.170 + * Used by the RectClipBlitter to trim a RLE encoding to match the 1.171 + * clipping rectangle. 1.172 + */ 1.173 + static void BreakAt(int16_t runs[], uint8_t alpha[], int x) { 1.174 + while (x > 0) { 1.175 + int n = runs[0]; 1.176 + SkASSERT(n > 0); 1.177 + 1.178 + if (x < n) { 1.179 + alpha[x] = alpha[0]; 1.180 + runs[0] = SkToS16(x); 1.181 + runs[x] = SkToS16(n - x); 1.182 + break; 1.183 + } 1.184 + runs += n; 1.185 + alpha += n; 1.186 + x -= n; 1.187 + } 1.188 + } 1.189 + 1.190 +private: 1.191 + SkDEBUGCODE(int fWidth;) 1.192 + SkDEBUGCODE(void validate() const;) 1.193 +}; 1.194 + 1.195 +#endif