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