michael@0: michael@0: /* michael@0: * Copyright 2006 The Android Open Source Project michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: #ifndef SkAntiRun_DEFINED michael@0: #define SkAntiRun_DEFINED michael@0: michael@0: #include "SkBlitter.h" michael@0: michael@0: /** Sparse array of run-length-encoded alpha (supersampling coverage) values. michael@0: Sparseness allows us to independently compose several paths into the michael@0: same SkAlphaRuns buffer. michael@0: */ michael@0: michael@0: class SkAlphaRuns { michael@0: public: michael@0: int16_t* fRuns; michael@0: uint8_t* fAlpha; michael@0: michael@0: /// Returns true if the scanline contains only a single run, michael@0: /// of alpha value 0. michael@0: bool empty() const { michael@0: SkASSERT(fRuns[0] > 0); michael@0: return fAlpha[0] == 0 && fRuns[fRuns[0]] == 0; michael@0: } michael@0: michael@0: /// Reinitialize for a new scanline. michael@0: void reset(int width); michael@0: michael@0: /** michael@0: * Insert into the buffer a run starting at (x-offsetX): michael@0: * if startAlpha > 0 michael@0: * one pixel with value += startAlpha, michael@0: * max 255 michael@0: * if middleCount > 0 michael@0: * middleCount pixels with value += maxValue michael@0: * if stopAlpha > 0 michael@0: * one pixel with value += stopAlpha michael@0: * Returns the offsetX value that should be passed on the next call, michael@0: * assuming we're on the same scanline. If the caller is switching michael@0: * scanlines, then offsetX should be 0 when this is called. michael@0: */ michael@0: SK_ALWAYS_INLINE int add(int x, U8CPU startAlpha, int middleCount, U8CPU stopAlpha, michael@0: U8CPU maxValue, int offsetX) { michael@0: SkASSERT(middleCount >= 0); michael@0: SkASSERT(x >= 0 && x + (startAlpha != 0) + middleCount + (stopAlpha != 0) <= fWidth); michael@0: michael@0: SkASSERT(fRuns[offsetX] >= 0); michael@0: michael@0: int16_t* runs = fRuns + offsetX; michael@0: uint8_t* alpha = fAlpha + offsetX; michael@0: uint8_t* lastAlpha = alpha; michael@0: x -= offsetX; michael@0: michael@0: if (startAlpha) { michael@0: SkAlphaRuns::Break(runs, alpha, x, 1); michael@0: /* I should be able to just add alpha[x] + startAlpha. michael@0: However, if the trailing edge of the previous span and the leading michael@0: edge of the current span round to the same super-sampled x value, michael@0: I might overflow to 256 with this add, hence the funny subtract (crud). michael@0: */ michael@0: unsigned tmp = alpha[x] + startAlpha; michael@0: SkASSERT(tmp <= 256); michael@0: alpha[x] = SkToU8(tmp - (tmp >> 8)); // was (tmp >> 7), but that seems wrong if we're trying to catch 256 michael@0: michael@0: runs += x + 1; michael@0: alpha += x + 1; michael@0: x = 0; michael@0: lastAlpha += x; // we don't want the +1 michael@0: SkDEBUGCODE(this->validate();) michael@0: } michael@0: michael@0: if (middleCount) { michael@0: SkAlphaRuns::Break(runs, alpha, x, middleCount); michael@0: alpha += x; michael@0: runs += x; michael@0: x = 0; michael@0: do { michael@0: alpha[0] = SkToU8(alpha[0] + maxValue); michael@0: int n = runs[0]; michael@0: SkASSERT(n <= middleCount); michael@0: alpha += n; michael@0: runs += n; michael@0: middleCount -= n; michael@0: } while (middleCount > 0); michael@0: SkDEBUGCODE(this->validate();) michael@0: lastAlpha = alpha; michael@0: } michael@0: michael@0: if (stopAlpha) { michael@0: SkAlphaRuns::Break(runs, alpha, x, 1); michael@0: alpha += x; michael@0: alpha[0] = SkToU8(alpha[0] + stopAlpha); michael@0: SkDEBUGCODE(this->validate();) michael@0: lastAlpha = alpha; michael@0: } michael@0: michael@0: return SkToS32(lastAlpha - fAlpha); // new offsetX michael@0: } michael@0: michael@0: SkDEBUGCODE(void assertValid(int y, int maxStep) const;) michael@0: SkDEBUGCODE(void dump() const;) michael@0: michael@0: /** michael@0: * Break the runs in the buffer at offsets x and x+count, properly michael@0: * updating the runs to the right and left. michael@0: * i.e. from the state AAAABBBB, run-length encoded as A4B4, michael@0: * Break(..., 2, 5) would produce AAAABBBB rle as A2A2B3B1. michael@0: * Allows add() to sum another run to some of the new sub-runs. michael@0: * i.e. adding ..CCCCC. would produce AADDEEEB, rle as A2D2E3B1. michael@0: */ michael@0: static void Break(int16_t runs[], uint8_t alpha[], int x, int count) { michael@0: SkASSERT(count > 0 && x >= 0); michael@0: michael@0: // SkAlphaRuns::BreakAt(runs, alpha, x); michael@0: // SkAlphaRuns::BreakAt(&runs[x], &alpha[x], count); michael@0: michael@0: int16_t* next_runs = runs + x; michael@0: uint8_t* next_alpha = alpha + x; michael@0: michael@0: while (x > 0) { michael@0: int n = runs[0]; michael@0: SkASSERT(n > 0); michael@0: michael@0: if (x < n) { michael@0: alpha[x] = alpha[0]; michael@0: runs[0] = SkToS16(x); michael@0: runs[x] = SkToS16(n - x); michael@0: break; michael@0: } michael@0: runs += n; michael@0: alpha += n; michael@0: x -= n; michael@0: } michael@0: michael@0: runs = next_runs; michael@0: alpha = next_alpha; michael@0: x = count; michael@0: michael@0: for (;;) { michael@0: int n = runs[0]; michael@0: SkASSERT(n > 0); michael@0: michael@0: if (x < n) { michael@0: alpha[x] = alpha[0]; michael@0: runs[0] = SkToS16(x); michael@0: runs[x] = SkToS16(n - x); michael@0: break; michael@0: } michael@0: x -= n; michael@0: if (x <= 0) { michael@0: break; michael@0: } michael@0: runs += n; michael@0: alpha += n; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Cut (at offset x in the buffer) a run into two shorter runs with michael@0: * matching alpha values. michael@0: * Used by the RectClipBlitter to trim a RLE encoding to match the michael@0: * clipping rectangle. michael@0: */ michael@0: static void BreakAt(int16_t runs[], uint8_t alpha[], int x) { michael@0: while (x > 0) { michael@0: int n = runs[0]; michael@0: SkASSERT(n > 0); michael@0: michael@0: if (x < n) { michael@0: alpha[x] = alpha[0]; michael@0: runs[0] = SkToS16(x); michael@0: runs[x] = SkToS16(n - x); michael@0: break; michael@0: } michael@0: runs += n; michael@0: alpha += n; michael@0: x -= n; michael@0: } michael@0: } michael@0: michael@0: private: michael@0: SkDEBUGCODE(int fWidth;) michael@0: SkDEBUGCODE(void validate() const;) michael@0: }; michael@0: michael@0: #endif